diff --git a/.github/workflows/issues.yml b/.github/workflows/issues.yml index 1e0c34e13c..67097be2fd 100644 --- a/.github/workflows/issues.yml +++ b/.github/workflows/issues.yml @@ -8,7 +8,7 @@ jobs: steps: - uses: actions/checkout@v4.1.1 - name: Apply Issue Labels - uses: github/issue-labeler@v3.3 + uses: github/issue-labeler@v3.4 with: repo-token: "${{ secrets.GITHUB_TOKEN }}" configuration-path: .github/labeler-issue.yml diff --git a/.gitignore b/.gitignore index f4ae5814f9..1ee2755aec 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,10 @@ vendor/ !command/test-fixtures/**/.terraform/ *.sh + +!createaddon.sh +!createcrd.sh +!deleteaddon.sh +!deletecrd.sh +!updatecrd.sh +!updateodf.sh diff --git a/.secrets.baseline b/.secrets.baseline index 403ad68ee7..a70dbb54d0 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -3,11 +3,8 @@ "files": "go.mod|go.sum|.*.map|^.secrets.baseline$", "lines": null }, - "generated_at": "2024-01-22T15:02:07Z", + "generated_at": "2024-02-14T08:29:34Z", "plugins_used": [ - { - "name": "AWSKeyDetector" - }, { "name": "ArtifactoryDetector" }, @@ -21,12 +18,6 @@ { "name": "BasicAuthDetector" }, - { - "name": "BoxDetector" - }, - { - "name": "CloudantDetector" - }, { "ghe_instance": "github.ibm.com", "name": "GheDetector" @@ -51,9 +42,6 @@ "keyword_exclude": null, "name": "KeywordDetector" }, - { - "name": "MailchimpDetector" - }, { "name": "NpmDetector" }, @@ -68,12 +56,6 @@ }, { "name": "SquareOAuthDetector" - }, - { - "name": "StripeDetector" - }, - { - "name": "TwilioKeyDetector" } ], "results": { @@ -560,7 +542,7 @@ "hashed_secret": "06d988e96c3d9325c9fbc7c0ef3c6c0f2b4eb8e7", "is_secret": false, "is_verified": false, - "line_number": 41, + "line_number": 42, "type": "Secret Keyword", "verified_result": null } @@ -786,7 +768,7 @@ "hashed_secret": "9184b0c38101bf24d78b2bb0d044deb1d33696fc", "is_secret": false, "is_verified": false, - "line_number": 132, + "line_number": 131, "type": "Secret Keyword", "verified_result": null }, @@ -794,7 +776,7 @@ "hashed_secret": "c427f185ddcb2440be9b77c8e45f1cd487a2e790", "is_secret": false, "is_verified": false, - "line_number": 1454, + "line_number": 1446, "type": "Base64 High Entropy String", "verified_result": null }, @@ -802,7 +784,7 @@ "hashed_secret": "1f7e33de15e22de9d2eaf502df284ed25ca40018", "is_secret": false, "is_verified": false, - "line_number": 1521, + "line_number": 1513, "type": "Secret Keyword", "verified_result": null }, @@ -810,7 +792,7 @@ "hashed_secret": "1f614c2eb6b3da22d89bd1b9fd47d7cb7c8fc670", "is_secret": false, "is_verified": false, - "line_number": 3342, + "line_number": 3319, "type": "Secret Keyword", "verified_result": null }, @@ -818,7 +800,7 @@ "hashed_secret": "7abfce65b8504403afc25c9790f358d513dfbcc6", "is_secret": false, "is_verified": false, - "line_number": 3355, + "line_number": 3332, "type": "Secret Keyword", "verified_result": null }, @@ -826,7 +808,7 @@ "hashed_secret": "0c2d85bf9a9b1579b16f220a4ea8c3d62b2e24b1", "is_secret": false, "is_verified": false, - "line_number": 3396, + "line_number": 3373, "type": "Secret Keyword", "verified_result": null } @@ -846,7 +828,7 @@ "hashed_secret": "da8cae6284528565678de15e03d461e23fe22538", "is_secret": false, "is_verified": false, - "line_number": 1895, + "line_number": 1899, "type": "Secret Keyword", "verified_result": null }, @@ -854,7 +836,7 @@ "hashed_secret": "1a0334cfa65f4be58b9d914b8e96e9d9478bfbac", "is_secret": false, "is_verified": false, - "line_number": 3276, + "line_number": 3280, "type": "Secret Keyword", "verified_result": null } @@ -864,7 +846,7 @@ "hashed_secret": "c8b6f5ef11b9223ac35a5663975a466ebe7ebba9", "is_secret": false, "is_verified": false, - "line_number": 1842, + "line_number": 1834, "type": "Secret Keyword", "verified_result": null }, @@ -872,7 +854,7 @@ "hashed_secret": "8abf4899c01104241510ba87685ad4de76b0c437", "is_secret": false, "is_verified": false, - "line_number": 1848, + "line_number": 1840, "type": "Secret Keyword", "verified_result": null } @@ -1928,57 +1910,19 @@ } ], "ibm/service/contextbasedrestrictions/data_source_ibm_cbr_rule_test.go": [ - { - "hashed_secret": "9b6e9b736d5aad4455eee13c6b2741e2271fb6c9", - "is_secret": false, - "is_verified": false, - "line_number": 107, - "type": "Hex High Entropy String", - "verified_result": null - }, - { - "hashed_secret": "ca8b3e9d1445b3218e3512da63b05c8f26f181e5", - "is_secret": false, - "is_verified": false, - "line_number": 113, - "type": "Hex High Entropy String", - "verified_result": null - } - ], - "ibm/service/contextbasedrestrictions/data_source_ibm_cbr_zone_test.go": [ { "hashed_secret": "ca8b3e9d1445b3218e3512da63b05c8f26f181e5", "is_secret": false, "is_verified": false, - "line_number": 89, - "type": "Hex High Entropy String", - "verified_result": null - } - ], - "ibm/service/contextbasedrestrictions/resource_ibm_cbr_rule_test.go": [ - { - "hashed_secret": "9b6e9b736d5aad4455eee13c6b2741e2271fb6c9", - "is_secret": false, - "is_verified": false, - "line_number": 111, + "line_number": 17, "type": "Hex High Entropy String", "verified_result": null }, { - "hashed_secret": "ca8b3e9d1445b3218e3512da63b05c8f26f181e5", - "is_secret": false, - "is_verified": false, - "line_number": 117, - "type": "Hex High Entropy String", - "verified_result": null - } - ], - "ibm/service/contextbasedrestrictions/resource_ibm_cbr_zone_test.go": [ - { - "hashed_secret": "ca8b3e9d1445b3218e3512da63b05c8f26f181e5", + "hashed_secret": "9b6e9b736d5aad4455eee13c6b2741e2271fb6c9", "is_secret": false, "is_verified": false, - "line_number": 82, + "line_number": 18, "type": "Hex High Entropy String", "verified_result": null } @@ -1998,7 +1942,7 @@ "hashed_secret": "884a58e4c2c5d195d3876787bdc63af6c5af2924", "is_secret": false, "is_verified": false, - "line_number": 1595, + "line_number": 1615, "type": "Secret Keyword", "verified_result": null } @@ -2326,7 +2270,7 @@ "hashed_secret": "4489f0af19dc8513caa9f822ba006d90095e492a", "is_secret": false, "is_verified": false, - "line_number": 230, + "line_number": 239, "type": "Secret Keyword", "verified_result": null } @@ -2346,7 +2290,7 @@ "hashed_secret": "f591b975c1668d110a6af6556a8e0067fd37d210", "is_secret": false, "is_verified": false, - "line_number": 185, + "line_number": 194, "type": "Secret Keyword", "verified_result": null } @@ -2366,7 +2310,7 @@ "hashed_secret": "f591b975c1668d110a6af6556a8e0067fd37d210", "is_secret": false, "is_verified": false, - "line_number": 187, + "line_number": 196, "type": "Secret Keyword", "verified_result": null } @@ -2386,7 +2330,7 @@ "hashed_secret": "730f01b99e162b57c5b0ac3e5206ee05e7bb3e33", "is_secret": false, "is_verified": false, - "line_number": 199, + "line_number": 208, "type": "Secret Keyword", "verified_result": null } @@ -2396,7 +2340,7 @@ "hashed_secret": "ea3b2250314d88f39bdc9d52e3c19b43d2f71fdd", "is_secret": false, "is_verified": false, - "line_number": 194, + "line_number": 203, "type": "Secret Keyword", "verified_result": null } @@ -2416,7 +2360,7 @@ "hashed_secret": "f591b975c1668d110a6af6556a8e0067fd37d210", "is_secret": false, "is_verified": false, - "line_number": 181, + "line_number": 190, "type": "Secret Keyword", "verified_result": null } @@ -2436,7 +2380,7 @@ "hashed_secret": "4489f0af19dc8513caa9f822ba006d90095e492a", "is_secret": false, "is_verified": false, - "line_number": 209, + "line_number": 218, "type": "Secret Keyword", "verified_result": null } @@ -2456,7 +2400,7 @@ "hashed_secret": "ea3b2250314d88f39bdc9d52e3c19b43d2f71fdd", "is_secret": false, "is_verified": false, - "line_number": 199, + "line_number": 208, "type": "Secret Keyword", "verified_result": null }, @@ -2464,7 +2408,7 @@ "hashed_secret": "4489f0af19dc8513caa9f822ba006d90095e492a", "is_secret": false, "is_verified": false, - "line_number": 207, + "line_number": 216, "type": "Secret Keyword", "verified_result": null } @@ -2492,7 +2436,7 @@ "hashed_secret": "2c3cbcd72f1d045c9511c23bb8dc003b61e83330", "is_secret": false, "is_verified": false, - "line_number": 80, + "line_number": 83, "type": "Secret Keyword", "verified_result": null } @@ -2502,7 +2446,7 @@ "hashed_secret": "ba96b0c05022d512af37716a585edf5d573f1e07", "is_secret": false, "is_verified": false, - "line_number": 77, + "line_number": 79, "type": "Secret Keyword", "verified_result": null } @@ -2512,7 +2456,7 @@ "hashed_secret": "f31b1e2c08066abe05972972fa811caea0153ce2", "is_secret": false, "is_verified": false, - "line_number": 76, + "line_number": 78, "type": "Secret Keyword", "verified_result": null } @@ -2522,7 +2466,7 @@ "hashed_secret": "61c15c3f4cd85ebe553f9067229845f699d32b9a", "is_secret": false, "is_verified": false, - "line_number": 77, + "line_number": 79, "type": "Secret Keyword", "verified_result": null } @@ -2532,7 +2476,7 @@ "hashed_secret": "58c7a8d929a8cf81f3ae641961651f1564c28936", "is_secret": false, "is_verified": false, - "line_number": 77, + "line_number": 79, "type": "Secret Keyword", "verified_result": null } @@ -2542,7 +2486,7 @@ "hashed_secret": "5a5241e2e938922ef2639bbbad51f5f0a6f5e4d9", "is_secret": false, "is_verified": false, - "line_number": 77, + "line_number": 79, "type": "Secret Keyword", "verified_result": null } @@ -2552,7 +2496,7 @@ "hashed_secret": "2c3cbcd72f1d045c9511c23bb8dc003b61e83330", "is_secret": false, "is_verified": false, - "line_number": 90, + "line_number": 92, "type": "Secret Keyword", "verified_result": null } @@ -2562,7 +2506,7 @@ "hashed_secret": "83f9f18903f3b785bde04f2c2db374c06ba4246a", "is_secret": false, "is_verified": false, - "line_number": 76, + "line_number": 78, "type": "Hex High Entropy String", "verified_result": null }, @@ -2570,7 +2514,7 @@ "hashed_secret": "7a1536c4159eebac1fd0112c2a4d61f69624bda8", "is_secret": false, "is_verified": false, - "line_number": 79, + "line_number": 81, "type": "Secret Keyword", "verified_result": null } @@ -2900,7 +2844,7 @@ "hashed_secret": "3046d9f6cfaaeea6eed9bb7a4ab010fe49b0cfd4", "is_secret": false, "is_verified": false, - "line_number": 341, + "line_number": 380, "type": "Secret Keyword", "verified_result": null }, @@ -2908,7 +2852,7 @@ "hashed_secret": "92f08f2d9a0dc3f0d4cb3796435a48508cf59ecd", "is_secret": false, "is_verified": false, - "line_number": 687, + "line_number": 709, "type": "Secret Keyword", "verified_result": null } @@ -2918,7 +2862,7 @@ "hashed_secret": "347cd9c53ff77d41a7b22aa56c7b4efaf54658e3", "is_secret": false, "is_verified": false, - "line_number": 58, + "line_number": 60, "type": "Secret Keyword", "verified_result": null } @@ -2946,7 +2890,7 @@ "hashed_secret": "347cd9c53ff77d41a7b22aa56c7b4efaf54658e3", "is_secret": false, "is_verified": false, - "line_number": 56, + "line_number": 57, "type": "Secret Keyword", "verified_result": null } @@ -2956,7 +2900,7 @@ "hashed_secret": "3046d9f6cfaaeea6eed9bb7a4ab010fe49b0cfd4", "is_secret": false, "is_verified": false, - "line_number": 236, + "line_number": 277, "type": "Secret Keyword", "verified_result": null }, @@ -2964,7 +2908,7 @@ "hashed_secret": "92f08f2d9a0dc3f0d4cb3796435a48508cf59ecd", "is_secret": false, "is_verified": false, - "line_number": 1107, + "line_number": 1061, "type": "Secret Keyword", "verified_result": null } @@ -2974,7 +2918,7 @@ "hashed_secret": "347cd9c53ff77d41a7b22aa56c7b4efaf54658e3", "is_secret": false, "is_verified": false, - "line_number": 61, + "line_number": 62, "type": "Secret Keyword", "verified_result": null } @@ -2992,7 +2936,7 @@ "hashed_secret": "92f08f2d9a0dc3f0d4cb3796435a48508cf59ecd", "is_secret": false, "is_verified": false, - "line_number": 509, + "line_number": 497, "type": "Secret Keyword", "verified_result": null } @@ -3002,7 +2946,7 @@ "hashed_secret": "347cd9c53ff77d41a7b22aa56c7b4efaf54658e3", "is_secret": false, "is_verified": false, - "line_number": 62, + "line_number": 63, "type": "Secret Keyword", "verified_result": null } @@ -3133,24 +3077,6 @@ "verified_result": null } ], - "ibm/service/secretsmanager/data_source_ibm_secrets_manager_secrets.go": [ - { - "hashed_secret": "09c0dfbba1f2b2576cfbac116e13b0258bc26bfa", - "is_secret": false, - "is_verified": false, - "line_number": 470, - "type": "Secret Keyword", - "verified_result": null - }, - { - "hashed_secret": "d282ab8a33d987146dda0381b4effdf2d91c0d65", - "is_secret": false, - "is_verified": false, - "line_number": 476, - "type": "Secret Keyword", - "verified_result": null - } - ], "ibm/service/secretsmanager/data_source_ibm_sm_configurations_test.go": [ { "hashed_secret": "347cd9c53ff77d41a7b22aa56c7b4efaf54658e3", @@ -3480,7 +3406,7 @@ "hashed_secret": "3046d9f6cfaaeea6eed9bb7a4ab010fe49b0cfd4", "is_secret": false, "is_verified": false, - "line_number": 157, + "line_number": 186, "type": "Secret Keyword", "verified_result": null }, @@ -3488,7 +3414,7 @@ "hashed_secret": "b732fb611fd46a38e8667f9972e0cde777fbe37f", "is_secret": false, "is_verified": false, - "line_number": 273, + "line_number": 314, "type": "Secret Keyword", "verified_result": null } @@ -3814,7 +3740,7 @@ "hashed_secret": "b732fb611fd46a38e8667f9972e0cde777fbe37f", "is_secret": false, "is_verified": false, - "line_number": 354, + "line_number": 390, "type": "Secret Keyword", "verified_result": null } @@ -3824,7 +3750,7 @@ "hashed_secret": "6d12fda3835a9f315af351d7df4ff82dbcfdb2e6", "is_secret": false, "is_verified": false, - "line_number": 22, + "line_number": 23, "type": "Secret Keyword", "verified_result": null }, @@ -3832,7 +3758,7 @@ "hashed_secret": "347cd9c53ff77d41a7b22aa56c7b4efaf54658e3", "is_secret": false, "is_verified": false, - "line_number": 111, + "line_number": 127, "type": "Secret Keyword", "verified_result": null } @@ -3872,7 +3798,7 @@ "hashed_secret": "f855f5027fd8fdb2df3f6a6f1cf858fffcbedb0c", "is_secret": false, "is_verified": false, - "line_number": 96613, + "line_number": 96618, "type": "Secret Keyword", "verified_result": null }, @@ -3880,7 +3806,7 @@ "hashed_secret": "5fb0fa884132a8724a8d7cba55853737e442adbd", "is_secret": false, "is_verified": false, - "line_number": 119402, + "line_number": 119412, "type": "Secret Keyword", "verified_result": null }, @@ -3888,7 +3814,7 @@ "hashed_secret": "1e5c2f367f02e47a8c160cda1cd9d91decbac441", "is_secret": false, "is_verified": false, - "line_number": 151610, + "line_number": 151620, "type": "Secret Keyword", "verified_result": null } @@ -4412,7 +4338,7 @@ "hashed_secret": "951d10e91b33958973a8ebf5f5d2ed80429ff471", "is_secret": false, "is_verified": false, - "line_number": 24, + "line_number": 25, "type": "Secret Keyword", "verified_result": null } @@ -4422,7 +4348,7 @@ "hashed_secret": "6363865be09354b861a5370ad9eb412142feec59", "is_secret": false, "is_verified": false, - "line_number": 23, + "line_number": 24, "type": "Secret Keyword", "verified_result": null } @@ -4432,7 +4358,7 @@ "hashed_secret": "e1e03a31507ee39abca8fc86cf37b8347dc32002", "is_secret": false, "is_verified": false, - "line_number": 49, + "line_number": 50, "type": "Secret Keyword", "verified_result": null } @@ -4442,7 +4368,7 @@ "hashed_secret": "e0fabca0317ce6a90c3df79b29214a269879bfb1", "is_secret": false, "is_verified": false, - "line_number": 23, + "line_number": 24, "type": "Secret Keyword", "verified_result": null } @@ -4452,7 +4378,7 @@ "hashed_secret": "e1e03a31507ee39abca8fc86cf37b8347dc32002", "is_secret": false, "is_verified": false, - "line_number": 37, + "line_number": 38, "type": "Secret Keyword", "verified_result": null } @@ -4462,7 +4388,7 @@ "hashed_secret": "7a1536c4159eebac1fd0112c2a4d61f69624bda8", "is_secret": false, "is_verified": false, - "line_number": 26, + "line_number": 27, "type": "Secret Keyword", "verified_result": null } @@ -4980,7 +4906,7 @@ "hashed_secret": "e3efaa78f2f6ca38f70ded91b232d8dac947315d", "is_secret": false, "is_verified": false, - "line_number": 31, + "line_number": 37, "type": "Secret Keyword", "verified_result": null }, @@ -4988,7 +4914,7 @@ "hashed_secret": "d47dcacc720a39e236679ac3e311a0d58bb6519e", "is_secret": false, "is_verified": false, - "line_number": 121, + "line_number": 134, "type": "Secret Keyword", "verified_result": null }, @@ -4996,7 +4922,7 @@ "hashed_secret": "e66e7d67fdf3c596c435fc7828b13205e4950a0f", "is_secret": false, "is_verified": false, - "line_number": 123, + "line_number": 136, "type": "Secret Keyword", "verified_result": null } @@ -5012,7 +4938,7 @@ } ] }, - "version": "0.13.1+ibm.61.dss", + "version": "0.13.1+ibm.62.dss", "word_list": { "file": null, "hash": null diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b45831b62..68769d63ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,105 @@ +# 1.63.0-beta0 (Feb 21, 2024) +Features +* Support for Virtual Private Cloud + - **Datasources** + - ibm_is_reservation + - **Resources** + - ibm_is_reservation + - ibm_is_reservation_activate + - ibm_is_bare_metal_server_network_attachment + - ibm_is_instance_network_attachment + - ibm_is_virtual_network_interface + - ibm_is_virtual_network_interface_floating_ip + - ibm_is_virtual_network_interface_ip + +* Support for Power Instance + - **Datasources** + - ibm_pi_instance_snapshot + - ibm_is_bare_metal_server_network_attachment + - ibm_is_bare_metal_server_network_attachments + - ibm_is_instance_network_attachment + - ibm_is_instance_network_attachments + - ibm_is_virtual_network_interface_floating_ip + - ibm_is_virtual_network_interface_floating_ips + - ibm_is_virtual_network_interface_ip + - ibm_is_virtual_network_interface_ips + +* Support for Event Notification + - **Datasources** + - ibm_en_email_template + - ibm_en_email_templates + - ibm_en_destination_custom_sms + - ibm_en_subscription_custom_sms + - ibm_en_integration_cos + - **Resources** + - ibm_en_email_template + - ibm_en_destination_custom_sms + - ibm_en_subscription_custom_sms + - ibm_en_integration_cos + +Enhancements +* Added new region eu-fr2 ([5073](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5073)) +* Update Forcenew instance fields ([5025](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5025)) +* Event Notifications: enabled private endpoint ([4989](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4989)) +* Adding OpenPages as part of UX030 ([5051](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5051)) +* add vpe_service_endpoint_url output ([5129](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5129)) +* Remove old deprecated features from terraform ([5049](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5049)) +* Remove deprecated Secrets Manager data sources ([5126](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5126)) +* Add Power VMRM ([4994](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4994)) +* Remove references for creating free clusters, no longer supported ([4987](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4987)) +* fix: CIS - added deafult value for min_tls_version ([5136](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5136)) +* fix: add vpe_service_endpoint_url output ([5129](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5129)) +* Secrets manager custom password generation policy ([5134](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5134)) +* deprecate(is-lb-listener-redirect): Deprecate lb listener https redirect ([5140](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5140)) +* Support for virtual network interfaces across instance, bare metal servers, instance templates, shares ([5112](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5112)) +* new feature "monitoring_enabled" for Project service ([5120](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5120)) +* feat(Catalog Management): update platform go sdk version, remove old catalog fields ([5145](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5145)) +* SCC eu-es update ([5135](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5135)) + +BugFixes +* Fix Satellite Locations recreation when updating, remove forcenew, add computed and applyonce +([5090](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5090)) +* updated is_images document ([5088](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5088)) +* reordered reservation on instance to avoid update and length check on templates ([5141](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5141)) +* fix(share-operations) : File shares operations and doc fixes ([5139](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5139)) +* Satellite Storage API Fix and Updated ODF Documentation ([5143](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5143)) +* fix(bare metal server) : fixed allow to float and ips issue ([5146](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5146)) +* fix(lb-and-routing-table) : Fix routing table and lbs datasource ([5149](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5149)) + +# 1.62.0 (Jan 30, 2024) +Features +* Support for Power Virtual Instance + - **Datasources** + - ibm_pi_volume_clone + - **Resources** + - ibm_pi_volume_clone +Enhancements +* Support security groups for Kuberentes workers ([4953](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4953)) +* Support service_subnet, pod_subnet for Satellite location ([4953](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4953)) +* Add resource instance sample config code part in the website doc ([5023](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5023)) +* fix(vpc-routing-table): support removing of advertise routes and accept routes from array ([5039](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5039)) +* support parameters for resource instance datasource ([5065](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5065)) +* remove forcenew from workerpool fields in cluster resource and added ApplyOnce ([4955](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4955)) +* SM fixes ([5045](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5045)) +* Terraform support for ICD isolated compute and multitenant cores ([4628](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4628)) +* Refactor Cloud connection refactor data source and documentation ([5053](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5053)) +* support empty lists for CBR rule contexts and zone addresses ([5058](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5058)) +* fix(IAM Policy Management): Add operator support to subject_attributes in Authorziation Policy ([5076](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5076)) +* fix(routing-table-route) - fix routing table route advertise patch and action ([5069](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5069)) +* encode test ids as constants for easy replacement ([5059](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5059)) +* Adding the fix for cos deletion access denied issue ([5083](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5083)) +* fix: fixed name update issue on is_instance boot_volume ([5084](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5084)) + +BugFixes +* CD scc doc updates ([4984](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/4984)) +* Fix mtu requirement bug ([5027](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5027)) +* listing all the connection for transit gateway over the pagination set ([5033](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5033)) +* Projects issue #2672 - "Terraform sees inputs as changed ([5042](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5033)) +* added a nil check on data source of bm servers ([5062](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5062)) +* Soft remove the datasources for secretManager v1 ([5063](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5063)) +* Schematics agent related fixes for GA ([5041](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5041)) +* SM docs fix ([5080](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5080)) + # 1.62.0-beta0 (Jan 21, 2024) Features * Support for Power Virtual Instance diff --git a/examples/ibm-cd-toolchain-simple-helm/variables.tf b/examples/ibm-cd-toolchain-simple-helm/variables.tf index af45ca1724..91b3e32217 100644 --- a/examples/ibm-cd-toolchain-simple-helm/variables.tf +++ b/examples/ibm-cd-toolchain-simple-helm/variables.tf @@ -48,7 +48,7 @@ variable "app_image_name" { variable "cluster_name" { type = string description = "Name of the kubernetes cluster where the application will be deployed." - default = "mycluster-free" + default = "mycluster" } variable "cluster_namespace" { diff --git a/examples/ibm-cluster-update/variables.tf b/examples/ibm-cluster-update/variables.tf index c298f52bdf..25c3f46989 100644 --- a/examples/ibm-cluster-update/variables.tf +++ b/examples/ibm-cluster-update/variables.tf @@ -38,7 +38,7 @@ variable "service_offering" { } variable "plan" { - default = "lite" + default = "standard" } variable "cluster_name" { diff --git a/examples/ibm-cluster/cluster-standalone-workers/variables.tf b/examples/ibm-cluster/cluster-standalone-workers/variables.tf index 8d069b5480..64c388aeca 100644 --- a/examples/ibm-cluster/cluster-standalone-workers/variables.tf +++ b/examples/ibm-cluster/cluster-standalone-workers/variables.tf @@ -47,7 +47,7 @@ variable "service_offering" { } variable "plan" { - default = "lite" + default = "standard" } variable "cluster_name" { diff --git a/examples/ibm-is-ng/main.tf b/examples/ibm-is-ng/main.tf index c344f98a6c..4f76a8a39b 100644 --- a/examples/ibm-is-ng/main.tf +++ b/examples/ibm-is-ng/main.tf @@ -3,11 +3,11 @@ resource "ibm_is_vpc" "vpc1" { } resource "ibm_is_vpc_address_prefix" "testacc_vpc_address_prefix" { - name = "vpcaddressprefix" - zone = var.zone1 - vpc = ibm_is_vpc.vpc1.id - cidr = var.cidr1 - is_default = true + name = "vpcaddressprefix" + zone = var.zone1 + vpc = ibm_is_vpc.vpc1.id + cidr = var.cidr1 + is_default = true } resource "ibm_is_subnet" "subnet1" { @@ -23,7 +23,7 @@ resource "ibm_is_instance_template" "instancetemplate1" { profile = "bx2-8x32" primary_network_interface { - subnet = ibm_is_subnet.subnet2.id + subnet = ibm_is_subnet.subnet2.id allow_ip_spoofing = true } @@ -36,13 +36,13 @@ resource "ibm_is_instance_template" "instancetemplate1" { delete_volume_on_instance_delete = true } volume_attachments { - delete_volume_on_instance_delete = true - name = "volatt-01" - volume_prototype { - iops = 3000 - profile = "general-purpose" - capacity = 200 - } + delete_volume_on_instance_delete = true + name = "volatt-01" + volume_prototype { + iops = 3000 + profile = "general-purpose" + capacity = 200 + } } } @@ -52,7 +52,7 @@ resource "ibm_is_instance_template" "instancetemplate2" { profile = "bx2-8x32" primary_network_interface { - subnet = ibm_is_subnet.subnet2.id + subnet = ibm_is_subnet.subnet2.id allow_ip_spoofing = true } @@ -64,16 +64,16 @@ resource "ibm_is_instance_template" "instancetemplate2" { name = "testbootvol" delete_volume_on_instance_delete = true } - volume_attachments { - delete_volume_on_instance_delete = true - name = "volatt-01" - volume = ibm_is_volume.vol1.id - } + volume_attachments { + delete_volume_on_instance_delete = true + name = "volatt-01" + volume = ibm_is_volume.vol1.id + } } // datasource for instance template data "ibm_is_instance_template" "instancetemplates" { - identifier = ibm_is_instance_template.instancetemplate2.id + identifier = ibm_is_instance_template.instancetemplate2.id } // Load balancer with private DNS @@ -81,9 +81,9 @@ resource "ibm_is_lb" "example" { name = "example-load-balancer" subnets = [ibm_is_subnet.subnet1.id] profile = "network-fixed" - dns { + dns { instance_crn = "crn:v1:staging:public:dns-svcs:global:a/exxxxxxxxxxxxx-xxxxxxxxxxxxxxxxx:5xxxxxxx-xxxxx-xxxxxxxxxxxxxxx-xxxxxxxxxxxxxxx::" - zone_id = "bxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx" + zone_id = "bxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx" } } @@ -124,74 +124,74 @@ resource "ibm_is_lb_listener_policy_rule" "lb_listener_policy_rule" { } resource "ibm_is_lb_pool" "testacc_pool" { - name = "test_pool" - lb = ibm_is_lb.lb2.id - algorithm = "round_robin" - protocol = "https" - health_delay = 60 - health_retries = 5 - health_timeout = 30 - health_type = "https" - proxy_protocol = "v1" - session_persistence_type = "app_cookie" + name = "test_pool" + lb = ibm_is_lb.lb2.id + algorithm = "round_robin" + protocol = "https" + health_delay = 60 + health_retries = 5 + health_timeout = 30 + health_type = "https" + proxy_protocol = "v1" + session_persistence_type = "app_cookie" session_persistence_app_cookie_name = "cookie1" } resource "ibm_is_lb_pool" "testacc_pool" { - name = "test_pool" - lb = ibm_is_lb.lb2.id - algorithm = "round_robin" - protocol = "https" - health_delay = 60 - health_retries = 5 - health_timeout = 30 - health_type = "https" - proxy_protocol = "v1" + name = "test_pool" + lb = ibm_is_lb.lb2.id + algorithm = "round_robin" + protocol = "https" + health_delay = 60 + health_retries = 5 + health_timeout = 30 + health_type = "https" + proxy_protocol = "v1" session_persistence_type = "http_cookie" } resource "ibm_is_lb_pool" "testacc_pool" { - name = "test_pool" - lb = ibm_is_lb.lb2.id - algorithm = "round_robin" - protocol = "https" - health_delay = 60 - health_retries = 5 - health_timeout = 30 - health_type = "https" - proxy_protocol = "v1" + name = "test_pool" + lb = ibm_is_lb.lb2.id + algorithm = "round_robin" + protocol = "https" + health_delay = 60 + health_retries = 5 + health_timeout = 30 + health_type = "https" + proxy_protocol = "v1" session_persistence_type = "source_ip" } data "ibm_is_lb_listener" "is_lb_listener" { - lb = "${ibm_is_lb.lb2.id}" - listener_id = ibm_is_lb_listener.lb_listener2.listener_id + lb = ibm_is_lb.lb2.id + listener_id = ibm_is_lb_listener.lb_listener2.listener_id } data "ibm_is_lb_listeners" "is_lb_listeners" { - lb = "${ibm_is_lb.lb2.id}" + lb = ibm_is_lb.lb2.id } data "ibm_is_lb_listener_policy" "is_lb_listener_policy" { - lb = "${ibm_is_lb.lb2.id}" - listener = ibm_is_lb_listener.lb_listener2.listener_id - policy_id = ibm_is_lb_listener_policy.lb_listener_policy.policy_id + lb = ibm_is_lb.lb2.id + listener = ibm_is_lb_listener.lb_listener2.listener_id + policy_id = ibm_is_lb_listener_policy.lb_listener_policy.policy_id } data "ibm_is_lb_listener_policies" "is_lb_listener_policies" { - lb = "${ibm_is_lb.lb2.id}" - listener = "${ibm_is_lb_listener.lb_listener2.listener_id}" + lb = ibm_is_lb.lb2.id + listener = ibm_is_lb_listener.lb_listener2.listener_id } data "ibm_is_lb_listener_policy_rule" "is_lb_listener_policy_rule" { - lb = "${ibm_is_lb.lb2.id}" - listener = "${ibm_is_lb_listener.lb_listener2.listener_id}" - policy = "${ibm_is_lb_listener_policy.lb_listener_policy.policy_id}" - rule = "${ibm_is_lb_listener_policy_rule.lb_listener_policy_rule.rule}" + lb = ibm_is_lb.lb2.id + listener = ibm_is_lb_listener.lb_listener2.listener_id + policy = ibm_is_lb_listener_policy.lb_listener_policy.policy_id + rule = ibm_is_lb_listener_policy_rule.lb_listener_policy_rule.rule } data "ibm_is_lb_listener_policy_rules" "is_lb_listener_policy_rules" { - lb = "${ibm_is_lb.lb2.id}" - listener = "${ibm_is_lb_listener.lb_listener2.listener_id}" - policy = "${ibm_is_lb_listener_policy.lb_listener_policy.policy_id}" + lb = ibm_is_lb.lb2.id + listener = ibm_is_lb_listener.lb_listener2.listener_id + policy = ibm_is_lb_listener_policy.lb_listener_policy.policy_id } resource "ibm_is_vpn_gateway" "VPNGateway1" { @@ -223,33 +223,33 @@ resource "ibm_is_instance" "instance1" { subnet = ibm_is_subnet.subnet1.id } - vpc = ibm_is_vpc.vpc1.id - zone = var.zone1 - keys = [ibm_is_ssh_key.sshkey.id] + vpc = ibm_is_vpc.vpc1.id + zone = var.zone1 + keys = [ibm_is_ssh_key.sshkey.id] } data "ibm_is_instance" "ds_instance" { - name = ibm_is_instance.instance1.name + name = ibm_is_instance.instance1.name private_key = file("~/.ssh/id_rsa") - passphrase = "" + passphrase = "" } resource "ibm_is_instance_network_interface" "is_instance_network_interface" { - instance = ibm_is_instance.instance1.id - subnet = ibm_is_subnet.subnet1.id - allow_ip_spoofing = true - name = "my-network-interface" + instance = ibm_is_instance.instance1.id + subnet = ibm_is_subnet.subnet1.id + allow_ip_spoofing = true + name = "my-network-interface" primary_ipv4_address = "10.0.0.5" } data "ibm_is_instance_network_interface" "is_instance_network_interface" { - instance_name = ibm_is_instance.instance1.name - network_interface_name = ibm_is_instance_network_interface.is_instance_network_interface.name + instance_name = ibm_is_instance.instance1.name + network_interface_name = ibm_is_instance_network_interface.is_instance_network_interface.name } data "ibm_is_instance_network_interfaces" "is_instance_network_interfaces" { - instance_name = ibm_is_instance.instance1.name + instance_name = ibm_is_instance.instance1.name } resource "ibm_is_floating_ip" "floatingip1" { @@ -344,9 +344,9 @@ resource "ibm_is_instance" "instance2" { subnet = ibm_is_subnet.subnet2.id } dedicated_host = ibm_is_dedicated_host.is_dedicated_host.id - vpc = ibm_is_vpc.vpc2.id - zone = var.zone2 - keys = [ibm_is_ssh_key.sshkey.id] + vpc = ibm_is_vpc.vpc2.id + zone = var.zone2 + keys = [ibm_is_ssh_key.sshkey.id] } resource "ibm_is_instance" "instance3" { @@ -358,9 +358,9 @@ resource "ibm_is_instance" "instance3" { subnet = ibm_is_subnet.subnet2.id } dedicated_host_group = ibm_is_dedicated_host_group.dh_group01.id - vpc = ibm_is_vpc.vpc2.id - zone = var.zone2 - keys = [ibm_is_ssh_key.sshkey.id] + vpc = ibm_is_vpc.vpc2.id + zone = var.zone2 + keys = [ibm_is_ssh_key.sshkey.id] } @@ -421,7 +421,7 @@ resource "ibm_is_volume" "vol2" { resource "ibm_is_network_acl" "isExampleACL" { name = "is-example-acl" - vpc = ibm_is_vpc.vpc1.id + vpc = ibm_is_vpc.vpc1.id rules { name = "outbound" action = "allow" @@ -452,11 +452,11 @@ resource "ibm_is_network_acl" "isExampleACL" { resource "ibm_is_network_acl_rule" "isExampleACLRule" { network_acl = ibm_is_network_acl.isExampleACL.id - name = "isexample-rule" - action = "allow" - source = "0.0.0.0/0" - destination = "0.0.0.0/0" - direction = "outbound" + name = "isexample-rule" + action = "allow" + source = "0.0.0.0/0" + destination = "0.0.0.0/0" + direction = "outbound" icmp { code = 1 type = 1 @@ -465,7 +465,7 @@ resource "ibm_is_network_acl_rule" "isExampleACLRule" { data "ibm_is_network_acl_rule" "testacc_dsnaclrule" { network_acl = ibm_is_network_acl.isExampleACL.id - name = ibm_is_network_acl_rule.isExampleACL.name + name = ibm_is_network_acl_rule.isExampleACL.name } data "ibm_is_network_acl_rules" "testacc_dsnaclrules" { @@ -473,12 +473,12 @@ data "ibm_is_network_acl_rules" "testacc_dsnaclrules" { } data "ibm_is_network_acl" "is_network_acl" { - network_acl = ibm_is_network_acl.isExampleACL.id + network_acl = ibm_is_network_acl.isExampleACL.id } data "ibm_is_network_acl" "is_network_acl1" { - name = ibm_is_network_acl.isExampleACL.name - vpc_name = ibm_is_vpc.vpc1.name + name = ibm_is_network_acl.isExampleACL.name + vpc_name = ibm_is_vpc.vpc1.name } data "ibm_is_network_acls" "is_network_acls" { @@ -492,15 +492,15 @@ resource "ibm_is_public_gateway" "publicgateway1" { // subnet public gateway attachment resource "ibm_is_subnet_public_gateway_attachment" "example" { - subnet = ibm_is_subnet.subnet1.id - public_gateway = ibm_is_public_gateway.publicgateway1.id + subnet = ibm_is_subnet.subnet1.id + public_gateway = ibm_is_public_gateway.publicgateway1.id } -data "ibm_is_public_gateway" "testacc_dspgw"{ +data "ibm_is_public_gateway" "testacc_dspgw" { name = ibm_is_public_gateway.publicgateway1.name } -data "ibm_is_public_gateways" "publicgateways"{ +data "ibm_is_public_gateways" "publicgateways" { } data "ibm_is_vpc" "vpc1" { @@ -508,34 +508,34 @@ data "ibm_is_vpc" "vpc1" { } // added for vpcs datasource -data "ibm_is_vpc" "vpcs"{ +data "ibm_is_vpc" "vpcs" { } -data "ibm_is_volume_profile" "volprofile"{ +data "ibm_is_volume_profile" "volprofile" { name = "general-purpose" } -data "ibm_is_volume_profiles" "volprofiles"{ +data "ibm_is_volume_profiles" "volprofiles" { } data "ibm_resource_group" "default" { -name = "Default" ///give your resource grp + name = "Default" ///give your resource grp } resource "ibm_is_dedicated_host_group" "dh_group01" { - family = "balanced" - class = "bx2d" - zone = "us-south-1" - name = "my-dh-group-01" + family = "balanced" + class = "bx2d" + zone = "us-south-1" + name = "my-dh-group-01" resource_group = data.ibm_resource_group.default.id } data "ibm_is_dedicated_host_group" "dgroup" { - name = ibm_is_dedicated_host_group.dh_group01.name + name = ibm_is_dedicated_host_group.dh_group01.name } resource "ibm_is_dedicated_host" "is_dedicated_host" { - profile = "bx2d-host-152x608" - name = "my-dedicated-host-01" - host_group = ibm_is_dedicated_host_group.dh_group01.id + profile = "bx2d-host-152x608" + name = "my-dedicated-host-01" + host_group = ibm_is_dedicated_host_group.dh_group01.id resource_group = data.ibm_resource_group.default.id } @@ -543,11 +543,11 @@ data "ibm_is_dedicated_host_groups" "dgroups" { } data "ibm_is_dedicated_host_profile" "ibm_is_dedicated_host_profile" { - name = "bx2d-host-152x608" -} + name = "bx2d-host-152x608" +} data "ibm_is_dedicated_host_profiles" "ibm_is_dedicated_host_profiles" { -} +} data "ibm_is_dedicated_hosts" "dhosts" { @@ -555,7 +555,7 @@ data "ibm_is_dedicated_hosts" "dhosts" { } data "ibm_is_dedicated_host" "dhost" { - name = ibm_is_dedicated_host.is_dedicated_host.name + name = ibm_is_dedicated_host.is_dedicated_host.name host_group = data.ibm_is_dedicated_host_group.dgroup.id } @@ -571,15 +571,15 @@ resource "ibm_is_instance" "instance4" { image = var.image profile = var.profile - volumes = [ ibm_is_volume.vol3.id ] + volumes = [ibm_is_volume.vol3.id] primary_network_interface { subnet = ibm_is_subnet.subnet1.id } - vpc = ibm_is_vpc.vpc1.id - zone = var.zone1 - keys = [ibm_is_ssh_key.sshkey.id] + vpc = ibm_is_vpc.vpc1.id + zone = var.zone1 + keys = [ibm_is_ssh_key.sshkey.id] } // creating a snapshot from boot volume with clone @@ -599,7 +599,7 @@ resource "ibm_is_snapshot" "d_snapshot" { // data source for snapshot by name data "ibm_is_snapshot" "ds_snapshot" { - name = "my-snapshot-boot" + name = "my-snapshot-boot" } // data source for snapshots @@ -644,28 +644,28 @@ resource "ibm_is_volume" "vol5" { // creating a volume attachment on an existing instance using an existing volume resource "ibm_is_instance_volume_attachment" "att1" { - instance = ibm_is_instance.instance5.id - volume = ibm_is_volume.vol5.id - name = "vol-att-1" - delete_volume_on_attachment_delete = false - delete_volume_on_instance_delete = false + instance = ibm_is_instance.instance5.id + volume = ibm_is_volume.vol5.id + name = "vol-att-1" + delete_volume_on_attachment_delete = false + delete_volume_on_instance_delete = false } // creating a volume attachment on an existing instance using a new volume resource "ibm_is_instance_volume_attachment" "att2" { - instance = ibm_is_instance.instance5.id - name = "vol-att-2" - profile = "general-purpose" - snapshot = ibm_is_snapshot.d_snapshot.id - delete_volume_on_instance_delete = true - delete_volume_on_attachment_delete = true - volume_name = "vol4-restore" + instance = ibm_is_instance.instance5.id + name = "vol-att-2" + profile = "general-purpose" + snapshot = ibm_is_snapshot.d_snapshot.id + delete_volume_on_instance_delete = true + delete_volume_on_attachment_delete = true + volume_name = "vol4-restore" } // data source for volume attachment data "ibm_is_instance_volume_attachment" "ds_vol_att" { - instance = ibm_is_instance.instance5.id - name = ibm_is_instance_volume_attachment.att2.name + instance = ibm_is_instance.instance5.id + name = ibm_is_instance_volume_attachment.att2.name } // data source for volume attachments @@ -676,7 +676,7 @@ data "ibm_is_instance_volume_attachment" "ds_vol_atts" { // creating an instance using an existing instance template resource "ibm_is_instance" "instance6" { name = "instance4" - instance_template = ibm_is_instance_template.instancetemplate1.id + instance_template = ibm_is_instance_template.instancetemplate1.id } resource "ibm_is_image" "image1" { @@ -697,11 +697,11 @@ data "ibm_is_image" "dsimage" { data "ibm_is_images" "dsimages" { } -resource "ibm_is_instance_disk_management" "disks"{ - instance = ibm_is_instance.instance1.id +resource "ibm_is_instance_disk_management" "disks" { + instance = ibm_is_instance.instance1.id disks { name = "mydisk01" - id = ibm_is_instance.instance1.disks.0.id + id = ibm_is_instance.instance1.disks.0.id } } @@ -721,11 +721,11 @@ resource "ibm_is_instance" "instance7" { auto_delete_volume = true primary_network_interface { primary_ip { - address = "10.0.0.5" + address = "10.0.0.5" auto_delete = true - } - name = "test-reserved-ip" - subnet = ibm_is_subnet.subnet2.id + } + name = "test-reserved-ip" + subnet = ibm_is_subnet.subnet2.id } vpc = ibm_is_vpc.vpc2.id zone = "us-south-2" @@ -738,16 +738,16 @@ data "ibm_is_images" "imageslist" { catalog_managed = true } resource "ibm_is_instance" "instance8" { - name = "instance8" - profile = var.profile + name = "instance8" + profile = var.profile auto_delete_volume = true primary_network_interface { primary_ip { - name = "example-reserved-ip" + name = "example-reserved-ip" auto_delete = true - } - name = "test-reserved-ip" - subnet = ibm_is_subnet.subnet2.id + } + name = "test-reserved-ip" + subnet = ibm_is_subnet.subnet2.id } catalog_offering { version_crn = data.ibm_is_images.imageslist.images.0.catalog_offering.0.version.0.crn @@ -758,7 +758,7 @@ resource "ibm_is_instance" "instance8" { } resource "ibm_is_instance_template" "instancetemplate3" { - name = "instancetemplate-3" + name = "instancetemplate-3" catalog_offering { version_crn = data.ibm_is_images.imageslist.images.0.catalog_offering.0.version.0.crn } @@ -768,26 +768,26 @@ resource "ibm_is_instance_template" "instancetemplate3" { subnet = ibm_is_subnet.subnet2.id } - vpc = ibm_is_vpc.vpc2.id - zone = "us-south-2" - keys = [ibm_is_ssh_key.sshkey.id] + vpc = ibm_is_vpc.vpc2.id + zone = "us-south-2" + keys = [ibm_is_ssh_key.sshkey.id] } data "ibm_is_instance_network_interface_reserved_ip" "data_reserved_ip" { - instance = ibm_is_instance.test_instance.id + instance = ibm_is_instance.test_instance.id network_interface = ibm_is_instance.test_instance.network_interfaces.0.id - reserved_ip = ibm_is_instance.test_instance.network_interfaces.0.ips.0.id + reserved_ip = ibm_is_instance.test_instance.network_interfaces.0.ips.0.id } data "ibm_is_instance_network_interface_reserved_ips" "data_reserved_ips" { - instance = ibm_is_instance.test_instance.id + instance = ibm_is_instance.test_instance.id network_interface = ibm_is_instance.test_instance.network_interfaces.0.id } data "ibm_is_instance_disk" "disk1" { instance = ibm_is_instance.instance1.id - disk = data.ibm_is_instance_disks.disk1.disks.0.id + disk = data.ibm_is_instance_disks.disk1.disks.0.id } data "ibm_is_dedicated_host_disks" "dhdisks" { @@ -796,28 +796,28 @@ data "ibm_is_dedicated_host_disks" "dhdisks" { data "ibm_is_dedicated_host_disk" "dhdisk" { dedicated_host = data.ibm_is_dedicated_host.dhost.id - disk = ibm_is_dedicated_host_disk_management.disks.disks.0.id + disk = ibm_is_dedicated_host_disk_management.disks.disks.0.id } resource "ibm_is_dedicated_host_disk_management" "disks" { dedicated_host = data.ibm_is_dedicated_host.dhost.id - disks { + disks { name = "newdisk01" - id = data.ibm_is_dedicated_host.dhost.disks.0.id - + id = data.ibm_is_dedicated_host.dhost.disks.0.id + } - disks { + disks { name = "newdisk02" - id = data.ibm_is_dedicated_host.dhost.disks.1.id - + id = data.ibm_is_dedicated_host.dhost.disks.1.id + } } -data "ibm_is_operating_system" "os"{ +data "ibm_is_operating_system" "os" { name = "red-8-amd64" } -data "ibm_is_operating_systems" "oslist"{ +data "ibm_is_operating_systems" "oslist" { } #### BARE METAL SERVER @@ -825,104 +825,104 @@ data "ibm_is_operating_systems" "oslist"{ resource "ibm_is_bare_metal_server" "bms" { profile = "bx2-metal-192x768" - name = "my-bms" - image = "r134-31c8ca90-2623-48d7-8cf7-737be6fc4c3e" - zone = "us-south-3" - keys = [ibm_is_ssh_key.sshkey.id] + name = "my-bms" + image = "r134-31c8ca90-2623-48d7-8cf7-737be6fc4c3e" + zone = "us-south-3" + keys = [ibm_is_ssh_key.sshkey.id] primary_network_interface { - subnet = ibm_is_subnet.subnet1.id + subnet = ibm_is_subnet.subnet1.id } vpc = ibm_is_vpc.vpc1.id } -resource ibm_is_bare_metal_server_disk this { +resource "ibm_is_bare_metal_server_disk" "this" { bare_metal_server = ibm_is_bare_metal_server.bms.id disk = ibm_is_bare_metal_server.bms.disks.0.id name = "bms-disk-update" } -resource ibm_is_bare_metal_server_action this { +resource "ibm_is_bare_metal_server_action" "this" { bare_metal_server = ibm_is_bare_metal_server.bms.id action = "stop" stop_type = "hard" } -data ibm_is_bare_metal_server_profiles this { +data "ibm_is_bare_metal_server_profiles" "this" { } -data ibm_is_bare_metal_server_profile this { - name = data.ibm_is_bare_metal_server_profiles.this.profiles.0.name +data "ibm_is_bare_metal_server_profile" "this" { + name = data.ibm_is_bare_metal_server_profiles.this.profiles.0.name } -data ibm_is_bare_metal_server_disk this { - bare_metal_server = ibm_is_bare_metal_server.this.id - disk = ibm_is_bare_metal_server.this.disks.0.id +data "ibm_is_bare_metal_server_disk" "this" { + bare_metal_server = ibm_is_bare_metal_server.this.id + disk = ibm_is_bare_metal_server.this.disks.0.id } -data ibm_is_bare_metal_server_disks this { - bare_metal_server = ibm_is_bare_metal_server.this.id -} - -resource ibm_is_bare_metal_server_network_interface bms_nic { - bare_metal_server = ibm_is_bare_metal_server.bms.id - - subnet = ibm_is_subnet.subnet1.id - name = "eth2" - allow_ip_spoofing = true - allowed_vlans = [101, 102] +data "ibm_is_bare_metal_server_disks" "this" { + bare_metal_server = ibm_is_bare_metal_server.this.id } -resource ibm_is_bare_metal_server_network_interface_allow_float bms_vlan_nic { - bare_metal_server = ibm_is_bare_metal_server.bms.id +resource "ibm_is_bare_metal_server_network_interface" "bms_nic" { + bare_metal_server = ibm_is_bare_metal_server.bms.id subnet = ibm_is_subnet.subnet1.id name = "eth2" - vlan = 102 + allow_ip_spoofing = true + allowed_vlans = [101, 102] } -resource ibm_is_bare_metal_server_network_interface bms_nic2 { +resource "ibm_is_bare_metal_server_network_interface_allow_float" "bms_vlan_nic" { bare_metal_server = ibm_is_bare_metal_server.bms.id subnet = ibm_is_subnet.subnet1.id name = "eth2" + vlan = 102 +} + +resource "ibm_is_bare_metal_server_network_interface" "bms_nic2" { + bare_metal_server = ibm_is_bare_metal_server.bms.id + + subnet = ibm_is_subnet.subnet1.id + name = "eth2" allow_ip_spoofing = true - vlan = 101 + vlan = 101 } -resource ibm_is_floating_ip testacc_fip { +resource "ibm_is_floating_ip" "testacc_fip" { name = "testaccfip" zone = ibm_is_subnet.subnet1.zone } -resource ibm_is_bare_metal_server_network_interface_floating_ip bms_nic_fip { +resource "ibm_is_bare_metal_server_network_interface_floating_ip" "bms_nic_fip" { bare_metal_server = ibm_is_bare_metal_server.bms.id network_interface = ibm_is_bare_metal_server_network_interface.bms_nic2.id floating_ip = ibm_is_floating_ip.testacc_fip.id } -data ibm_is_bare_metal_server_network_interface this { +data "ibm_is_bare_metal_server_network_interface" "this" { bare_metal_server = ibm_is_bare_metal_server.this.id network_interface = ibm_is_bare_metal_server.this.primary_network_interface.id } -data ibm_is_bare_metal_server_network_interfaces this { +data "ibm_is_bare_metal_server_network_interfaces" "this" { bare_metal_server = ibm_is_bare_metal_server.this.id } -data ibm_is_bare_metal_server this { +data "ibm_is_bare_metal_server" "this" { identifier = ibm_is_bare_metal_server.this.id } -data ibm_is_bare_metal_servers this { +data "ibm_is_bare_metal_servers" "this" { } - -data ibm_is_bare_metal_server_initialization this { + +data "ibm_is_bare_metal_server_initialization" "this" { bare_metal_server = ibm_is_bare_metal_server.this.id } resource "ibm_is_floating_ip" "floatingipbms" { - name = "fip1" - zone = ibm_is_subnet.subnet1.zone + name = "fip1" + zone = ibm_is_subnet.subnet1.zone } data "ibm_is_bare_metal_server_network_interface_floating_ip" "this" { @@ -937,8 +937,8 @@ data "ibm_is_bare_metal_server_network_interface_floating_ips" "this" { } resource "ibm_is_placement_group" "is_placement_group" { - strategy = "%s" - name = "%s" + strategy = "%s" + name = "%s" resource_group = data.ibm_resource_group.default.id } @@ -954,25 +954,25 @@ data "ibm_is_regions" "regions" { } data "ibm_is_vpc_address_prefix" "example" { - vpc = ibm_is_vpc.vpc1.id + vpc = ibm_is_vpc.vpc1.id address_prefix = ibm_is_vpc_address_prefix.testacc_vpc_address_prefix.address_prefix } data "ibm_is_vpc_address_prefix" "example-1" { - vpc_name = ibm_is_vpc.vpc1.name + vpc_name = ibm_is_vpc.vpc1.name address_prefix = ibm_is_vpc_address_prefix.testacc_vpc_address_prefix.address_prefix } data "ibm_is_vpc_address_prefix" "example-2" { - vpc = ibm_is_vpc.vpc1.id + vpc = ibm_is_vpc.vpc1.id address_prefix_name = ibm_is_vpc_address_prefix.testacc_vpc_address_prefix.name } data "ibm_is_vpc_address_prefix" "example-3" { - vpc_name = ibm_is_vpc.vpc1.name + vpc_name = ibm_is_vpc.vpc1.name address_prefix_name = ibm_is_vpc_address_prefix.testacc_vpc_address_prefix.name } - + ## Security Groups/Rules/Rule // Create is_security_groups data source data "ibm_is_security_groups" "example" { @@ -986,7 +986,7 @@ resource "ibm_is_security_group" "example" { resource "ibm_is_security_group_rule" "exampleudp" { depends_on = [ - ibm_is_security_group.example, + ibm_is_security_group.example, ] group = ibm_is_security_group.example.id direction = "inbound" @@ -999,10 +999,10 @@ resource "ibm_is_security_group_rule" "exampleudp" { data "ibm_is_security_group_rule" "example" { depends_on = [ - ibm_is_security_group_rule.exampleudp, + ibm_is_security_group_rule.exampleudp, ] - security_group_rule = ibm_is_security_group_rule.exampleudp.rule_id - security_group = ibm_is_security_group.example.id + security_group_rule = ibm_is_security_group_rule.exampleudp.rule_id + security_group = ibm_is_security_group.example.id } // Create is_security_group_rules data source @@ -1023,8 +1023,8 @@ data "ibm_is_security_group_rules" "example" { depends_on = [ ibm_is_security_group_rule.exampletcp, ] -} - +} + data "ibm_is_vpn_gateway" "example" { vpn_gateway = ibm_is_vpn_gateway.example.id } @@ -1032,19 +1032,19 @@ data "ibm_is_vpn_gateway" "example-1" { vpn_gateway_name = ibm_is_vpn_gateway.example.name } data "ibm_is_vpn_gateway_connection" "example" { - vpn_gateway = ibm_is_vpn_gateway.example.id + vpn_gateway = ibm_is_vpn_gateway.example.id vpn_gateway_connection = ibm_is_vpn_gateway_connection.example.gateway_connection } data "ibm_is_vpn_gateway_connection" "example-1" { - vpn_gateway = ibm_is_vpn_gateway.example-1.id + vpn_gateway = ibm_is_vpn_gateway.example-1.id vpn_gateway_connection_name = ibm_is_vpn_gateway_connection.example.name } data "ibm_is_vpn_gateway_connection" "example-2" { - vpn_gateway_name = ibm_is_vpn_gateway.example.name + vpn_gateway_name = ibm_is_vpn_gateway.example.name vpn_gateway_connection = ibm_is_vpn_gateway_connection.example.gateway_connection } data "ibm_is_vpn_gateway_connection" "example-3" { - vpn_gateway_name = ibm_is_vpn_gateway.example.name + vpn_gateway_name = ibm_is_vpn_gateway.example.name vpn_gateway_connection_name = ibm_is_vpn_gateway_connection.example.name } data "ibm_is_ike_policies" "example" { @@ -1111,7 +1111,7 @@ resource "ibm_is_backup_policy_plan" "is_backup_policy_plan" { cron_spec = "30 09 * * *" active = false attach_user_tags = ["tag2"] - copy_user_tags = true + copy_user_tags = true deletion_trigger { delete_after = 20 delete_over_count = "20" @@ -1123,15 +1123,15 @@ resource "ibm_is_backup_policy_plan" "is_backup_policy_plan_clone" { cron_spec = "30 09 * * *" active = false attach_user_tags = ["tag2"] - copy_user_tags = true + copy_user_tags = true deletion_trigger { delete_after = 20 delete_over_count = "20" } name = "my-backup-policy-plan-1" clone_policy { - zones = ["us-south-1", "us-south-2"] - max_snapshots = 3 + zones = ["us-south-1", "us-south-2"] + max_snapshots = 3 } } @@ -1200,29 +1200,29 @@ data "ibm_is_backup_policy_jobs" "is_backup_policy_jobs" { } data "ibm_is_vpn_server" "is_vpn_server" { - identifier = ibm_is_vpn_server.is_vpn_server.vpn_server + identifier = ibm_is_vpn_server.is_vpn_server.vpn_server } data "ibm_is_vpn_servers" "is_vpn_servers" { } data "ibm_is_vpn_server_routes" "is_vpn_server_routes" { - vpn_server_id = ibm_is_vpn_server.is_vpn_server.vpn_server + vpn_server_id = ibm_is_vpn_server.is_vpn_server.vpn_server } data "ibm_is_vpn_server_route" "is_vpn_server_route" { - vpn_server_id = ibm_is_vpn_server.is_vpn_server.vpn_server - identifier = ibm_is_vpn_server_route.is_vpn_server_route.vpn_route + vpn_server_id = ibm_is_vpn_server.is_vpn_server.vpn_server + identifier = ibm_is_vpn_server_route.is_vpn_server_route.vpn_route } data "ibm_is_vpn_server_clients" "is_vpn_server_clients" { - vpn_server_id = ibm_is_vpn_server.is_vpn_server.vpn_server + vpn_server_id = ibm_is_vpn_server.is_vpn_server.vpn_server } data "ibm_is_vpn_server_client" "is_vpn_server_client" { - vpn_server_id = ibm_is_vpn_server.is_vpn_server.vpn_server - identifier = "0726-61b2f53f-1e95-42a7-94ab-55de8f8cbdd5" + vpn_server_id = ibm_is_vpn_server.is_vpn_server.vpn_server + identifier = "0726-61b2f53f-1e95-42a7-94ab-55de8f8cbdd5" } resource "ibm_is_image_export_job" "example" { image = ibm_is_image.image1.id - name = "my-image-export" + name = "my-image-export" storage_bucket { name = "bucket-27200-lwx4cfvcue" } @@ -1233,29 +1233,29 @@ data "ibm_is_image_export_jobs" "example" { } data "ibm_is_image_export_job" "example" { - image = ibm_is_image_export_job.example.image + image = ibm_is_image_export_job.example.image image_export_job = ibm_is_image_export_job.example.image_export_job } resource "ibm_is_vpc" "vpc" { name = "my-vpc" } resource "ibm_is_share" "share" { - zone = "us-south-1" - size = 30000 - name = "my-share" - profile = "dp2" + zone = "us-south-1" + size = 30000 + name = "my-share" + profile = "dp2" tags = ["share1", "share3"] access_tags = ["access:dev"] } resource "ibm_is_share" "sharereplica" { - zone = "us-south-2" - name = "my-share-replica" - profile = "dp2" + zone = "us-south-2" + name = "my-share-replica" + profile = "dp2" replication_cron_spec = "0 */5 * * *" - source_share = ibm_is_share.share.id - tags = ["share1", "share3"] - access_tags = ["access:dev"] + source_share = ibm_is_share.share.id + tags = ["share1", "share3"] + access_tags = ["access:dev"] } resource "ibm_is_share_mount_target" "is_share_mount_target" { @@ -1282,28 +1282,28 @@ data "ibm_is_shares" "is_shares" { // vpc dns resolution bindings - // list all dns resolution bindings on a vpc +// list all dns resolution bindings on a vpc data "ibm_is_vpc_dns_resolution_bindings" "is_vpc_dns_resolution_bindings" { - vpc_id = ibm_is_vpc.vpc1.id + vpc_id = ibm_is_vpc.vpc1.id } - // get a dns resolution bindings on a vpc +// get a dns resolution bindings on a vpc data "ibm_is_vpc_dns_resolution_binding" "is_vpc_dns_resolution_binding" { - vpc_id = ibm_is_vpc.vpc1.id - id = ibm_is_vpc.vpc2.id + vpc_id = ibm_is_vpc.vpc1.id + id = ibm_is_vpc.vpc2.id } data "ibm_resource_group" "rg" { - is_default = true + is_default = true } - // creating a hub enabled vpc, hub disabled vpc, creating custom resolvers for both then - // delegating the vpc by uncommenting the configuration in hub_false_delegated vpc -resource ibm_is_vpc hub_true { +// creating a hub enabled vpc, hub disabled vpc, creating custom resolvers for both then +// delegating the vpc by uncommenting the configuration in hub_false_delegated vpc +resource "ibm_is_vpc" "hub_true" { name = "${var.name}-vpc-hub-true" dns { enable_hub = true } } -resource ibm_is_vpc hub_false_delegated { +resource "ibm_is_vpc" "hub_false_delegated" { name = "${var.name}-vpc-hub-false-del" dns { enable_hub = false @@ -1315,70 +1315,70 @@ resource ibm_is_vpc hub_false_delegated { } resource "ibm_is_subnet" "hub_true_sub1" { - name = "hub-true-subnet1" - vpc = ibm_is_vpc.hub_true.id - zone = "${var.region}-2" - total_ipv4_address_count = 16 + name = "hub-true-subnet1" + vpc = ibm_is_vpc.hub_true.id + zone = "${var.region}-2" + total_ipv4_address_count = 16 } resource "ibm_is_subnet" "hub_true_sub2" { - name = "hub-true-subnet2" - vpc = ibm_is_vpc.hub_true.id - zone = "${var.region}-2" - total_ipv4_address_count = 16 + name = "hub-true-subnet2" + vpc = ibm_is_vpc.hub_true.id + zone = "${var.region}-2" + total_ipv4_address_count = 16 } resource "ibm_is_subnet" "hub_false_delegated_sub1" { - name = "hub-false-delegated-subnet1" - vpc = ibm_is_vpc.hub_false_delegated.id - zone = "${var.region}-2" - total_ipv4_address_count = 16 + name = "hub-false-delegated-subnet1" + vpc = ibm_is_vpc.hub_false_delegated.id + zone = "${var.region}-2" + total_ipv4_address_count = 16 } resource "ibm_is_subnet" "hub_false_delegated_sub2" { - name = "hub-false-delegated-subnet2" - vpc = ibm_is_vpc.hub_false_delegated.id - zone = "${var.region}-2" - total_ipv4_address_count = 16 + name = "hub-false-delegated-subnet2" + vpc = ibm_is_vpc.hub_false_delegated.id + zone = "${var.region}-2" + total_ipv4_address_count = 16 } resource "ibm_resource_instance" "dns-cr-instance" { - name = "dns-cr-instance" - resource_group_id = data.ibm_resource_group.rg.id - location = "global" - service = "dns-svcs" - plan = "standard-dns" + name = "dns-cr-instance" + resource_group_id = data.ibm_resource_group.rg.id + location = "global" + service = "dns-svcs" + plan = "standard-dns" } resource "ibm_dns_custom_resolver" "test_hub_true" { - name = "test-hub-true-customresolver" - instance_id = ibm_resource_instance.dns-cr-instance.guid - description = "new test CR - TF" - high_availability = true - enabled = true + name = "test-hub-true-customresolver" + instance_id = ibm_resource_instance.dns-cr-instance.guid + description = "new test CR - TF" + high_availability = true + enabled = true locations { - subnet_crn = ibm_is_subnet.hub_true_sub1.crn - enabled = true + subnet_crn = ibm_is_subnet.hub_true_sub1.crn + enabled = true } locations { - subnet_crn = ibm_is_subnet.hub_true_sub2.crn - enabled = true + subnet_crn = ibm_is_subnet.hub_true_sub2.crn + enabled = true } } resource "ibm_dns_custom_resolver" "test_hub_false_delegated" { - name = "test-hub-false-customresolver" - instance_id = ibm_resource_instance.dns-cr-instance.guid - description = "new test CR - TF" - high_availability = true - enabled = true + name = "test-hub-false-customresolver" + instance_id = ibm_resource_instance.dns-cr-instance.guid + description = "new test CR - TF" + high_availability = true + enabled = true locations { - subnet_crn = ibm_is_subnet.hub_false_delegated_sub1.crn - enabled = true + subnet_crn = ibm_is_subnet.hub_false_delegated_sub1.crn + enabled = true } locations { - subnet_crn = ibm_is_subnet.hub_false_delegated_sub2.crn - enabled = true + subnet_crn = ibm_is_subnet.hub_false_delegated_sub2.crn + enabled = true } } -resource ibm_is_vpc_dns_resolution_binding dnstrue { - name = "hub-spoke-binding" - vpc_id = ibm_is_vpc.hub_false_delegated.id +resource "ibm_is_vpc_dns_resolution_binding" "dnstrue" { + name = "hub-spoke-binding" + vpc_id = ibm_is_vpc.hub_false_delegated.id vpc { id = ibm_is_vpc.hub_true.id } @@ -1388,8 +1388,8 @@ resource ibm_is_vpc_dns_resolution_binding dnstrue { // snapshot cross region provider "ibm" { - alias = "eu-de" - region = "eu-de" + alias = "eu-de" + region = "eu-de" } resource "ibm_is_snapshot" "b_snapshot_copy" { @@ -1401,20 +1401,160 @@ resource "ibm_is_snapshot" "b_snapshot_copy" { // image deprecate and obsolete resource "ibm_is_image_deprecate" "example" { - image = ibm_is_image.image1.id + image = ibm_is_image.image1.id } resource "ibm_is_image_obsolete" "example" { - image = ibm_is_image.image1.id + image = ibm_is_image.image1.id +} + + +// vni + +resource "ibm_is_vpc" "testacc_vpc" { + name = "${var.name}-vpc" +} + +resource "ibm_is_subnet" "testacc_subnet" { + name = "${var.name}-subnet" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "${var.region}-2" + total_ipv4_address_count = 16 + +} + +resource "ibm_is_virtual_network_interface" "testacc_vni" { + name = var.name + subnet = ibm_is_subnet.testacc_subnet.id + enable_infrastructure_nat = true + allow_ip_spoofing = true +} + +resource "ibm_is_floating_ip" "testacc_floatingip" { + name = "${var.name}-floating" + zone = ibm_is_subnet.testacc_subnet.zone +} +resource "ibm_is_virtual_network_interface_floating_ip" "testacc_vni_floatingip" { + virtual_network_interface = ibm_is_virtual_network_interface.testacc_vni.id + floating_ip = ibm_is_floating_ip.testacc_floatingip.id +} +data "ibm_is_virtual_network_interface_floating_ip" "is_vni_floating_ip" { + depends_on = [ibm_is_virtual_network_interface_floating_ip.testacc_vni_floatingip] + virtual_network_interface = ibm_is_virtual_network_interface.testacc_vni.id + floating_ip = ibm_is_floating_ip.testacc_floatingip.id +} +data "ibm_is_virtual_network_interface_floating_ips" "is_vni_floating_ips" { + depends_on = [ibm_is_virtual_network_interface_floating_ip.testacc_vni_floatingip] + virtual_network_interface = ibm_is_virtual_network_interface.testacc_vni.id +} + +data "ibm_is_virtual_network_interface_ips" "is_vni_reservedips" { + depends_on = [ibm_is_virtual_network_interface_ip.testacc_vni_reservedip] + virtual_network_interface = ibm_is_virtual_network_interface.testacc_vni.id +} +data "ibm_is_virtual_network_interface_ip" "is_vni_reservedip" { + depends_on = [ibm_is_virtual_network_interface_ip.testacc_vni_reservedip] + virtual_network_interface = ibm_is_virtual_network_interface.testacc_vni.id + reserved_ip = ibm_is_subnet_reserved_ip.testacc_reservedip.reserved_ip +} + +resource "ibm_is_subnet_reserved_ip" "testacc_reservedip" { + subnet = ibm_is_subnet.testacc_subnet.id + name = "${var.name}-reserved-ip" +} +resource "ibm_is_virtual_network_interface_ip" "testacc_vni_reservedip" { + virtual_network_interface = ibm_is_virtual_network_interface.testacc_vni.id + reserved_ip = ibm_is_subnet_reserved_ip.testacc_reservedip.reserved_ip +} + +resource "ibm_is_virtual_network_interface" "testacc_vni2" { + name = "${var.name}-2" + subnet = ibm_is_subnet.testacc_subnet.id + enable_infrastructure_nat = true + allow_ip_spoofing = true +} +resource "ibm_is_virtual_network_interface" "testacc_vni3" { + name = "${var.name}-3" + subnet = ibm_is_subnet.testacc_subnet.id + enable_infrastructure_nat = true + allow_ip_spoofing = true +} +resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "${var.name}-ssh" + public_key = file("~/.ssh/id_rsa.pub") +} + + +resource "ibm_is_bare_metal_server" "testacc_bms" { + profile = "cx2-metal-96x192" + name = "${var.name}-bms" + image = "r134-f47cc24c-e020-4db5-ad96-1e5be8b5853b" + zone = "${var.region}-2" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + primary_network_attachment { + name = "vni-221" + virtual_network_interface { + id = ibm_is_virtual_network_interface.testacc_vni.id + } + allowed_vlans = [100, 102] + } + vpc = ibm_is_vpc.testacc_vpc.id +} + +resource "ibm_is_bare_metal_server_network_attachment" "na" { + bare_metal_server = ibm_is_bare_metal_server.testacc_bms.id + # interface_type = "vlan" + vlan = 100 +} +resource "ibm_is_bare_metal_server_network_attachment" "na2" { + bare_metal_server = ibm_is_bare_metal_server.testacc_bms.id + # interface_type = "pci" + allowed_vlans = [200, 202] +} + +resource "ibm_is_instance_network_attachment" "ina" { + instance = ibm_is_instance.ins.id + name = "viability-undecided-jalapeno-unbuilt" + virtual_network_interface { + id = ibm_is_virtual_network_interface.testacc_vni2.id + } +} +resource "ibm_is_instance" "ins" { + name = "${var.name}-vsi2" + profile = "bx2-2x8" + image = "r134-f47cc24c-e020-4db5-ad96-1e5be8b5853b" + primary_network_attachment { + name = "vni-test" + virtual_network_interface { + id = ibm_is_virtual_network_interface.testacc_vni3.id + } + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "${var.region}-2" + keys = [ibm_is_ssh_key.testacc_sshkey.id] +} +resource "ibm_is_instance_template" "ins_temp" { + name = "${var.name}-vsi2" + profile = "bx2-2x8" + image = "r134-f47cc24c-e020-4db5-ad96-1e5be8b5853b" + primary_network_attachment { + name = "vni-test" + virtual_network_interface { + id = ibm_is_virtual_network_interface.testacc_vni3.id + } + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "${var.region}-2" + keys = [ibm_is_ssh_key.testacc_sshkey.id] } resource "ibm_is_share" "share" { - zone = "us-east-1" - source_share_crn = "crn:v1:staging:public:is:us-south-1:a/efe5afc483594adaa8325e2b4d1290df::share:r134-d8c8821c-a227-451d-a9ed-0c0cd2358829" - encryption_key = "crn:v1:staging:public:kms:us-south:a/efe5afc483594adaa8325e2b4d1290df:1be45161-6dae-44ca-b248-837f98004057:key:3dd21cc5-cc20-4f7c-bc62-8ec9a8a3d1bd" + zone = "us-east-1" + source_share_crn = "crn:v1:staging:public:is:us-south-1:a/efe5afc483594adaa8325e2b4d1290df::share:r134-d8c8821c-a227-451d-a9ed-0c0cd2358829" + encryption_key = "crn:v1:staging:public:kms:us-south:a/efe5afc483594adaa8325e2b4d1290df:1be45161-6dae-44ca-b248-837f98004057:key:3dd21cc5-cc20-4f7c-bc62-8ec9a8a3d1bd" replication_cron_spec = "5 * * * *" - name = "tfp-temp-crr" - profile = "dp2" + name = "tfp-temp-crr" + profile = "dp2" } //snapshot consistency group @@ -1440,4 +1580,31 @@ data "ibm_is_snapshot_consistency_group" "is_snapshot_consistency_group_instance data "ibm_is_snapshot_consistency_groups" "is_snapshot_consistency_group_instance" { depends_on = [ibm_is_snapshot_consistency_group.is_snapshot_consistency_group_instance] name = "example-snapshot-consistency-group" -} \ No newline at end of file +} + +//reservation + +resource "ibm_is_reservation" "example" { + capacity { + total = 5 + } + committed_use { + term = "one_year" + } + profile { + name = "ba2-2x8" + resource_type = "instance_profile" + } + zone = "us-east-3" +} + +resource "ibm_is_reservation_activate" "example" { + reservation = ibm_is_reservation.example.id +} + +data "ibm_is_reservations" "example" { +} + +data "ibm_is_reservation" "example" { + identifier = ibm_is_reservation.example.id +} diff --git a/examples/ibm-openpages/README.md b/examples/ibm-openpages/README.md new file mode 100644 index 0000000000..4372bfdf17 --- /dev/null +++ b/examples/ibm-openpages/README.md @@ -0,0 +1,58 @@ +# OpenPages example + +This example shows 1 usage scenario. + +#### Scenario 1: Create an OpenPages service instance. + +```terraform +resource "ibm_resource_instance" "openpages_instance" { + name = "terraform-automation" + service = "openpages" + plan = "essentials" + location = "global" + resource_group_id = data.ibm_resource_group.default_group.id + parameters_json = < "true" | 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 | `string` | no | false +| 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 | 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 +| disableNoobaaLB | Specify true to disable to NooBaa public load balancer. | `bool` | no | false Refer - https://cloud.ibm.com/docs/openshift?topic=openshift-deploy-odf-vpc&interface=ui#odf-vpc-param-ref diff --git a/examples/openshift-data-foundation/addon/4.13.0/ocscluster/main.tf b/examples/openshift-data-foundation/addon/4.13.0/ocscluster/main.tf index 077c9f38d7..d100f8a31b 100644 --- a/examples/openshift-data-foundation/addon/4.13.0/ocscluster/main.tf +++ b/examples/openshift-data-foundation/addon/4.13.0/ocscluster/main.tf @@ -5,7 +5,7 @@ terraform { } ibm = { source = "IBM-Cloud/ibm" - version = "1.56.0" + version = ">= 1.56.0" } } } @@ -51,7 +51,8 @@ resource "kubernetes_manifest" "ocscluster_ocscluster_auto" { "osdSize" = var.osdSize, "osdStorageClassName" = var.osdStorageClassName, "workerNodes" = var.workerNodes==null ? null : split(",", var.workerNodes), - "encryptionInTransit" = var.encryptionInTransit + "encryptionInTransit" = var.encryptionInTransit, + "disableNoobaaLB" = var.disableNoobaaLB } } diff --git a/examples/openshift-data-foundation/addon/4.13.0/schematics.tfvars b/examples/openshift-data-foundation/addon/4.13.0/schematics.tfvars index a023a4ee16..0d1bc15ba5 100644 --- a/examples/openshift-data-foundation/addon/4.13.0/schematics.tfvars +++ b/examples/openshift-data-foundation/addon/4.13.0/schematics.tfvars @@ -19,11 +19,12 @@ hpcsInstanceId = null hpcsSecretName = null hpcsServiceName = null hpcsTokenUrl = null -ignoreNoobaa = "false" +ignoreNoobaa = false numOfOsd = "1" ocsUpgrade = "false" osdDevicePaths = null -osdSize = "250Gi" +osdSize = "512Gi" osdStorageClassName = "ibmc-vpc-block-metro-10iops-tier" workerNodes = null encryptionInTransit = false +disableNoobaaLB = false \ No newline at end of file diff --git a/examples/openshift-data-foundation/addon/4.13.0/variables.tf b/examples/openshift-data-foundation/addon/4.13.0/variables.tf index aac6101f11..30fb77a3b7 100644 --- a/examples/openshift-data-foundation/addon/4.13.0/variables.tf +++ b/examples/openshift-data-foundation/addon/4.13.0/variables.tf @@ -149,4 +149,12 @@ variable "encryptionInTransit" { 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." + } \ No newline at end of file diff --git a/examples/openshift-data-foundation/addon/4.14.0/README.md b/examples/openshift-data-foundation/addon/4.14.0/README.md new file mode 100644 index 0000000000..ed309e2bce --- /dev/null +++ b/examples/openshift-data-foundation/addon/4.14.0/README.md @@ -0,0 +1,190 @@ +# 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 +``` + +```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.14.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" +workerNodes = null +encryptionInTransit = false +taintNodes = false +addSingleReplicaPool = false +prepareForDisasterRecovery = false +ignore-noobaa = false +disableNoobaaLB = false +``` + +### 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 + +```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.14.0" -> "4.15.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 +| 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 + +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.14.0/createaddon.sh b/examples/openshift-data-foundation/addon/4.14.0/createaddon.sh new file mode 100644 index 0000000000..68fb4a3223 --- /dev/null +++ b/examples/openshift-data-foundation/addon/4.14.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.14.0/createcrd.sh b/examples/openshift-data-foundation/addon/4.14.0/createcrd.sh new file mode 100644 index 0000000000..6a32158224 --- /dev/null +++ b/examples/openshift-data-foundation/addon/4.14.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.14.0/deleteaddon.sh b/examples/openshift-data-foundation/addon/4.14.0/deleteaddon.sh new file mode 100644 index 0000000000..e23f9be4f9 --- /dev/null +++ b/examples/openshift-data-foundation/addon/4.14.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.14.0/deletecrd.sh b/examples/openshift-data-foundation/addon/4.14.0/deletecrd.sh new file mode 100644 index 0000000000..42127bc595 --- /dev/null +++ b/examples/openshift-data-foundation/addon/4.14.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.14.0/ibm_odf_addon/main.tf b/examples/openshift-data-foundation/addon/4.14.0/ibm_odf_addon/main.tf new file mode 100644 index 0000000000..2b35dd21d7 --- /dev/null +++ b/examples/openshift-data-foundation/addon/4.14.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 +``` +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 + +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.13" -> "4.14" +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 +| 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 +| disableNoobaaLB | Specify true to disable to NooBaa public load balancer. | `bool` | no | false + +Refer - https://cloud.ibm.com/docs/satellite?topic=satellite-storage-odf-local&interface=ui#odf-local-4.13-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. +* `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.13/input.tfvars b/examples/openshift-data-foundation/satellite/odf-local/4.13/input.tfvars new file mode 100644 index 0000000000..31e5668cb0 --- /dev/null +++ b/examples/openshift-data-foundation/satellite/odf-local/4.13/input.tfvars @@ -0,0 +1,53 @@ +## 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.13" + +## 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" +workerNodes = null +encryptionInTransit = false +disableNoobaaLB = false +performCleanup = false + +## 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 \ No newline at end of file diff --git a/examples/openshift-data-foundation/satellite/odf-local/4.13/main.tf b/examples/openshift-data-foundation/satellite/odf-local/4.13/main.tf new file mode 100644 index 0000000000..1038eaec22 --- /dev/null +++ b/examples/openshift-data-foundation/satellite/odf-local/4.13/main.tf @@ -0,0 +1,57 @@ +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-nodes"= var.workerNodes + } + 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.13/variables.tf b/examples/openshift-data-foundation/satellite/odf-local/4.13/variables.tf new file mode 100644 index 0000000000..f9794a34a2 --- /dev/null +++ b/examples/openshift-data-foundation/satellite/odf-local/4.13/variables.tf @@ -0,0 +1,221 @@ +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.13.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 "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" +} diff --git a/examples/openshift-data-foundation/satellite/odf-local/4.14/README.md b/examples/openshift-data-foundation/satellite/odf-local/4.14/README.md new file mode 100644 index 0000000000..94485d609d --- /dev/null +++ b/examples/openshift-data-foundation/satellite/odf-local/4.14/README.md @@ -0,0 +1,183 @@ +# Openshift Data Foundation - Local 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 local devices](https://cloud.ibm.com/docs/satellite?topic=satellite-storage-odf-local&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-local" +storageTemplateVersion = "4.14" + +## 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" +workerNodes = null +encryptionInTransit = false +disableNoobaaLB = false +performCleanup = false +taintNodes = false +addSingleReplicaPool = false +prepareForDisasterRecovery = false + +## 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 + +```hcl +numOfOsd = "1" -> "2" +workerNodes = null -> "worker_1_ID,worker_2_ID" +updateConfigRevision = true +``` +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 + +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 +| 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 + +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. +* `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.14/input.tfvars b/examples/openshift-data-foundation/satellite/odf-local/4.14/input.tfvars new file mode 100644 index 0000000000..1b94fe8c44 --- /dev/null +++ b/examples/openshift-data-foundation/satellite/odf-local/4.14/input.tfvars @@ -0,0 +1,56 @@ +## 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.14" + +## 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" +workerNodes = null +encryptionInTransit = false +disableNoobaaLB = false +performCleanup = false +taintNodes = false +addSingleReplicaPool = false +prepareForDisasterRecovery = false + +## 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 \ No newline at end of file diff --git a/examples/openshift-data-foundation/satellite/odf-local/4.14/main.tf b/examples/openshift-data-foundation/satellite/odf-local/4.14/main.tf new file mode 100644 index 0000000000..0c42812549 --- /dev/null +++ b/examples/openshift-data-foundation/satellite/odf-local/4.14/main.tf @@ -0,0 +1,60 @@ +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-nodes"= var.workerNodes, + "add-single-replica-pool" = var.addSingleReplicaPool, + "taint-nodes" = var.taintNodes, + "prepare-for-disaster-recovery" = var.prepareForDisasterRecovery + } + 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.14/variables.tf b/examples/openshift-data-foundation/satellite/odf-local/4.14/variables.tf new file mode 100644 index 0000000000..016e74bfc4 --- /dev/null +++ b/examples/openshift-data-foundation/satellite/odf-local/4.14/variables.tf @@ -0,0 +1,239 @@ +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.13.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 "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." +} \ No newline at end of file diff --git a/examples/openshift-data-foundation/satellite/odf-remote/4.13/README.md b/examples/openshift-data-foundation/satellite/odf-remote/4.13/README.md new file mode 100644 index 0000000000..602b9327c8 --- /dev/null +++ b/examples/openshift-data-foundation/satellite/odf-remote/4.13/README.md @@ -0,0 +1,177 @@ +# 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.13" + +## 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" +workerNodes = null +encryptionInTransit = false +disableNoobaaLB = false +performCleanup = false + +## 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 + +```hcl +numOfOsd = "1" -> "2" +workerNodes = null -> "worker_1_ID,worker_2_ID" +updateConfigRevision = true +``` +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 + +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.13" -> "4.14" +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 +| 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 +| disableNoobaaLB | Specify true to disable to NooBaa public load balancer. | `bool` | no | false + +Refer - https://cloud.ibm.com/docs/satellite?topic=satellite-storage-odf-remote&interface=ui#odf-remote-4.13-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. +* `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.13/input.tfvars b/examples/openshift-data-foundation/satellite/odf-remote/4.13/input.tfvars new file mode 100644 index 0000000000..33a739dedf --- /dev/null +++ b/examples/openshift-data-foundation/satellite/odf-remote/4.13/input.tfvars @@ -0,0 +1,53 @@ +## 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.13" + +## 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" +workerNodes = null +encryptionInTransit = false +disableNoobaaLB = false +performCleanup = false + +## 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 \ No newline at end of file diff --git a/examples/openshift-data-foundation/satellite/odf-remote/4.13/main.tf b/examples/openshift-data-foundation/satellite/odf-remote/4.13/main.tf new file mode 100644 index 0000000000..435a11cd5d --- /dev/null +++ b/examples/openshift-data-foundation/satellite/odf-remote/4.13/main.tf @@ -0,0 +1,57 @@ +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-nodes"= var.workerNodes + } + 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.13/variables.tf b/examples/openshift-data-foundation/satellite/odf-remote/4.13/variables.tf new file mode 100644 index 0000000000..f9794a34a2 --- /dev/null +++ b/examples/openshift-data-foundation/satellite/odf-remote/4.13/variables.tf @@ -0,0 +1,221 @@ +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.13.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 "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" +} diff --git a/examples/openshift-data-foundation/satellite/odf-remote/4.14/README.md b/examples/openshift-data-foundation/satellite/odf-remote/4.14/README.md new file mode 100644 index 0000000000..b29fd228ec --- /dev/null +++ b/examples/openshift-data-foundation/satellite/odf-remote/4.14/README.md @@ -0,0 +1,183 @@ +# 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.14" + +## 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" +workerNodes = null +encryptionInTransit = false +disableNoobaaLB = false +performCleanup = false +taintNodes = false +addSingleReplicaPool = false +prepareForDisasterRecovery = false + +## 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 + +```hcl +numOfOsd = "1" -> "2" +workerNodes = null -> "worker_1_ID,worker_2_ID" +updateConfigRevision = true +``` +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 + +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-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 +| 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 + +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. +* `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.14/input.tfvars b/examples/openshift-data-foundation/satellite/odf-remote/4.14/input.tfvars new file mode 100644 index 0000000000..5198408b61 --- /dev/null +++ b/examples/openshift-data-foundation/satellite/odf-remote/4.14/input.tfvars @@ -0,0 +1,56 @@ +## 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.14" + +## 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" +workerNodes = null +encryptionInTransit = false +disableNoobaaLB = false +performCleanup = false +taintNodes = false +addSingleReplicaPool = false +prepareForDisasterRecovery = false + +## 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 \ No newline at end of file diff --git a/examples/openshift-data-foundation/satellite/odf-remote/4.14/main.tf b/examples/openshift-data-foundation/satellite/odf-remote/4.14/main.tf new file mode 100644 index 0000000000..8c58612df9 --- /dev/null +++ b/examples/openshift-data-foundation/satellite/odf-remote/4.14/main.tf @@ -0,0 +1,60 @@ +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-nodes"= var.workerNodes, + "add-single-replica-pool" = var.addSingleReplicaPool, + "taint-nodes" = var.taintNodes, + "prepare-for-disaster-recovery" = var.prepareForDisasterRecovery + } + 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.14/variables.tf b/examples/openshift-data-foundation/satellite/odf-remote/4.14/variables.tf new file mode 100644 index 0000000000..016e74bfc4 --- /dev/null +++ b/examples/openshift-data-foundation/satellite/odf-remote/4.14/variables.tf @@ -0,0 +1,239 @@ +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.13.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 "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." +} \ No newline at end of file diff --git a/go.mod b/go.mod index a04cb8f158..9124601aae 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.19 require ( github.com/IBM-Cloud/bluemix-go v0.0.0-20240110132033-6ead1f81a985 - github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20231207111718-a3b74cc935fa + github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20240216115622-a311507b4b5b github.com/IBM-Cloud/power-go-client v1.5.8 github.com/IBM/apigateway-go-sdk v0.0.0-20210714141226-a5d5d49caaca github.com/IBM/appconfiguration-go-admin-sdk v0.3.0 @@ -14,34 +14,34 @@ require ( github.com/IBM/code-engine-go-sdk v0.0.0-20231106200405-99e81b3ee752 github.com/IBM/container-registry-go-sdk v1.1.0 github.com/IBM/continuous-delivery-go-sdk v1.3.0 - github.com/IBM/event-notifications-go-admin-sdk v0.2.7 + github.com/IBM/event-notifications-go-admin-sdk v0.4.0 github.com/IBM/eventstreams-go-sdk v1.4.0 github.com/IBM/go-sdk-core/v3 v3.2.4 - github.com/IBM/go-sdk-core/v5 v5.15.0 + github.com/IBM/go-sdk-core/v5 v5.15.1 github.com/IBM/ibm-cos-sdk-go v1.10.0 github.com/IBM/ibm-cos-sdk-go-config v1.2.0 github.com/IBM/ibm-hpcs-tke-sdk v0.0.0-20211109141421-a4b61b05f7d1 github.com/IBM/ibm-hpcs-uko-sdk v0.0.20-beta github.com/IBM/keyprotect-go-client v0.12.2 github.com/IBM/networking-go-sdk v0.44.0 - github.com/IBM/platform-services-go-sdk v0.55.0 - github.com/IBM/project-go-sdk v0.1.6 + github.com/IBM/platform-services-go-sdk v0.59.0 + github.com/IBM/project-go-sdk v0.2.1 github.com/IBM/push-notifications-go-sdk v0.0.0-20210310100607-5790b96c47f5 - github.com/IBM/scc-go-sdk/v5 v5.1.4 + github.com/IBM/scc-go-sdk/v5 v5.1.5 github.com/IBM/schematics-go-sdk v0.2.3 - github.com/IBM/secrets-manager-go-sdk/v2 v2.0.2 + github.com/IBM/secrets-manager-go-sdk/v2 v2.0.3 github.com/IBM/vpc-beta-go-sdk v0.6.0 - github.com/IBM/vpc-go-sdk v0.47.0 + github.com/IBM/vpc-go-sdk v0.48.0 github.com/ScaleFT/sshkeys v0.0.0-20200327173127-6142f742bca5 github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 github.com/akamai/AkamaiOPEN-edgegrid-golang/v5 v5.0.0 github.com/apache/openwhisk-client-go v0.0.0-20200201143223-a804fb82d105 github.com/apparentlymart/go-cidr v1.1.0 github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 - github.com/go-openapi/strfmt v0.21.10 + github.com/go-openapi/strfmt v0.22.0 github.com/golang-jwt/jwt v3.2.2+incompatible github.com/google/go-cmp v0.6.0 - github.com/google/uuid v1.4.0 + github.com/google/uuid v1.6.0 github.com/hashicorp/go-uuid v1.0.3 github.com/hashicorp/go-version v1.6.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.29.0 @@ -53,7 +53,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/rook/rook v1.11.4 github.com/softlayer/softlayer-go v1.0.3 - golang.org/x/crypto v0.17.0 + golang.org/x/crypto v0.19.0 gopkg.in/yaml.v3 v3.0.1 gotest.tools v2.2.0+incompatible k8s.io/api v0.26.3 @@ -114,7 +114,7 @@ require ( github.com/go-ozzo/ozzo-validation/v4 v4.3.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.16.0 // indirect + github.com/go-playground/validator/v10 v10.18.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.4 // indirect @@ -129,7 +129,7 @@ require ( github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-plugin v1.5.1 // indirect - github.com/hashicorp/go-retryablehttp v0.7.4 // indirect + github.com/hashicorp/go-retryablehttp v0.7.5 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect @@ -163,7 +163,7 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.16.7 // indirect github.com/kube-object-storage/lib-bucket-provisioner v0.0.0-20221122204822-d1a8c34382f1 // indirect - github.com/leodido/go-urn v1.2.4 // indirect + github.com/leodido/go-urn v1.4.0 // indirect github.com/libopenstorage/secrets v0.0.0-20220823020833-2ecadaf59d8a // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect @@ -202,16 +202,16 @@ require ( github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/zclconf/go-cty v1.14.1 // indirect - go.mongodb.org/mongo-driver v1.13.1 // indirect + go.mongodb.org/mongo-driver v1.14.0 // indirect go.opentelemetry.io/otel v1.14.0 // indirect go.opentelemetry.io/otel/trace v1.14.0 // indirect go.uber.org/ratelimit v0.2.0 // indirect golang.org/x/mod v0.14.0 // indirect - golang.org/x/net v0.19.0 // indirect + golang.org/x/net v0.21.0 // indirect golang.org/x/oauth2 v0.7.0 // indirect golang.org/x/sync v0.5.0 // indirect - golang.org/x/sys v0.16.0 // indirect - golang.org/x/term v0.15.0 // indirect + golang.org/x/sys v0.17.0 // indirect + golang.org/x/term v0.17.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.16.0 // indirect diff --git a/go.sum b/go.sum index d08e8b1bb3..ff0a6f718a 100644 --- a/go.sum +++ b/go.sum @@ -103,8 +103,8 @@ github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3 github.com/DataDog/zstd v1.4.4/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/IBM-Cloud/bluemix-go v0.0.0-20240110132033-6ead1f81a985 h1:Rsi0y9dJZNkF9zIa0Yjf9rdYHb5UqMMGbZvOcsESq90= github.com/IBM-Cloud/bluemix-go v0.0.0-20240110132033-6ead1f81a985/go.mod h1:jIGLnIfj+uBv2ALz3rVHzNbNwt0V/bEWNeJKECa8Q+k= -github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20231207111718-a3b74cc935fa h1:tsgTFGt4j1V3PQmzZbA4wJAeT5rz24OgY4AvY2QGek0= -github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20231207111718-a3b74cc935fa/go.mod h1:xUQL9SGAjoZFd4GNjrjjtEpjpkgU7RFXRyHesbKTjiY= +github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20240216115622-a311507b4b5b h1:Wnq0BuprazpP41+nQlRpxpmAs8+8jyOqU50KrvFdJQ4= +github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20240216115622-a311507b4b5b/go.mod h1:xUQL9SGAjoZFd4GNjrjjtEpjpkgU7RFXRyHesbKTjiY= github.com/IBM-Cloud/ibm-cloud-cli-sdk v0.5.3/go.mod h1:RiUvKuHKTBmBApDMUQzBL14pQUGKcx/IioKQPIcRQjs= github.com/IBM-Cloud/power-go-client v1.5.8 h1:4l9PmnYRXV/KfVNBRuc9hya6kW5cQZhN4UMUMdpn1JU= github.com/IBM-Cloud/power-go-client v1.5.8/go.mod h1:y4WDw/l9+29CKX98ngCCvGoHdzX49LL00B1euoAbWzQ= @@ -126,8 +126,8 @@ github.com/IBM/container-registry-go-sdk v1.1.0 h1:sYyknIod8R4RJZQqAheiduP6wbSTp github.com/IBM/container-registry-go-sdk v1.1.0/go.mod h1:4TwsCnQtVfZ4Vkapy/KPvQBKFc3VOyUZYkwRU4FTPrs= github.com/IBM/continuous-delivery-go-sdk v1.3.0 h1:WsILMVpNWD/5G40ltWeXbOj4y5ODQSq1hKXAnDJuNjw= github.com/IBM/continuous-delivery-go-sdk v1.3.0/go.mod h1:oW51tS5/MDCcEM7lUvjK1H9GFC/oKsRbyYfmvGyMGmw= -github.com/IBM/event-notifications-go-admin-sdk v0.2.7 h1:Y6YPiXZO3/oAhs7rY6ekowJAsf9J05g2UFq3wjFkuCs= -github.com/IBM/event-notifications-go-admin-sdk v0.2.7/go.mod h1:iI6/TJt4GQBDsl8NYzoIYGnsNjMG0kOVIEl7mcM5v1E= +github.com/IBM/event-notifications-go-admin-sdk v0.4.0 h1:7nqtybv8GNVjuB5QBfx/kejI90lCXBnSuERNnJB4gZY= +github.com/IBM/event-notifications-go-admin-sdk v0.4.0/go.mod h1:m6WD+q9AHJhybK929vOK8Kfx4BsKO7AmROKRpR2uQP8= github.com/IBM/eventstreams-go-sdk v1.4.0 h1:yS/Ns29sBOe8W2tynQmz9HTKqQZ0ckse4Py5Oy/F2rM= github.com/IBM/eventstreams-go-sdk v1.4.0/go.mod h1:2tuAxaYLctfqfr5jvyqSrxxEQGMwYPm3yJGWSj85YVQ= github.com/IBM/go-sdk-core/v3 v3.0.0/go.mod h1:JI5NS2+iCoY/D8Oq3JNEZNA7qO42agu6fnaUmDsRcJA= @@ -140,8 +140,8 @@ github.com/IBM/go-sdk-core/v5 v5.7.0/go.mod h1:+YbdhrjCHC84ls4MeBp+Hj4NZCni+tDAc github.com/IBM/go-sdk-core/v5 v5.9.2/go.mod h1:YlOwV9LeuclmT/qi/LAK2AsobbAP42veV0j68/rlZsE= github.com/IBM/go-sdk-core/v5 v5.9.5/go.mod h1:YlOwV9LeuclmT/qi/LAK2AsobbAP42veV0j68/rlZsE= github.com/IBM/go-sdk-core/v5 v5.10.2/go.mod h1:WZPFasUzsKab/2mzt29xPcfruSk5js2ywAPwW4VJjdI= -github.com/IBM/go-sdk-core/v5 v5.15.0 h1:AhFoWVk3i58f9vnDoEoZumI/zbtRoP5moWIz5YQOmZg= -github.com/IBM/go-sdk-core/v5 v5.15.0/go.mod h1:5Obavm/s1Tc2PxivEIfgCvj/HJ5h3QIOjLHS5y8QJf0= +github.com/IBM/go-sdk-core/v5 v5.15.1 h1:XOzNZbBgnlxOGK1JMMBtZJYSVguK4TFPJiYutuzFmdA= +github.com/IBM/go-sdk-core/v5 v5.15.1/go.mod h1:so2mbdIgSp6X8Zm/qLV+whdchTGgi04c3j4xFMsqlCc= github.com/IBM/ibm-cos-sdk-go v1.3.1/go.mod h1:YLBAYobEA8bD27P7xpMwSQeNQu6W3DNBtBComXrRzRY= github.com/IBM/ibm-cos-sdk-go v1.10.0 h1:/2VIev2/jBei39OqU2+nSZQnoWJ+KtkiSAIDkqsd7uU= github.com/IBM/ibm-cos-sdk-go v1.10.0/go.mod h1:C8KRTRaoD3CWPPBOa6FCOpdh0ZMlUjKAAA4i3F+Q/sc= @@ -158,24 +158,24 @@ github.com/IBM/mqcloud-go-sdk v0.0.4 h1:gqMpoU5a0qJ0GETG4PQrkgeEEoaQLvbxRJnEe6yt github.com/IBM/mqcloud-go-sdk v0.0.4/go.mod h1:gQptHC6D+rxfg0muRFFGvTDmvl4YfiDE0uXkaRRewRk= github.com/IBM/networking-go-sdk v0.44.0 h1:6acyMd6hwxcjK3bJ2suiUBTjzg8mRFAvYD76zbx0adk= github.com/IBM/networking-go-sdk v0.44.0/go.mod h1:XtqYRInR5NHmFUXhOL6RovpDdv6PnJfZ1lPFvssA8MA= -github.com/IBM/platform-services-go-sdk v0.55.0 h1:W598xZanL61bwd8O2DQexr4qjIr+/tP0Y845zoms5yA= -github.com/IBM/platform-services-go-sdk v0.55.0/go.mod h1:CWSprvsCsXWvujmBzbtoJSmbRZS9FVV3O594b0t/GiM= -github.com/IBM/project-go-sdk v0.1.6 h1:sGrR0ej5wgBDhR2Xvf8Tgi5NmgMAJ77yep/CPGhvOx8= -github.com/IBM/project-go-sdk v0.1.6/go.mod h1:lqe0M4cKvABI1iHR1b+KfasVcxQL6nl2VJ8eOyQs8Ig= +github.com/IBM/platform-services-go-sdk v0.59.0 h1:FSRM3oKHxzShLCsIIb6Dl+JSaVOXpBWnfWFITJR6DDk= +github.com/IBM/platform-services-go-sdk v0.59.0/go.mod h1:+U6Kg7o5u/Bh4ZkLxjymSgfdpVsaWAtsMtzhwclUry0= +github.com/IBM/project-go-sdk v0.2.1 h1:Xo7ITrfyfVm0eCsaC2SADlhcEjqjx9rtU37fwnzGMCI= +github.com/IBM/project-go-sdk v0.2.1/go.mod h1:lqe0M4cKvABI1iHR1b+KfasVcxQL6nl2VJ8eOyQs8Ig= github.com/IBM/push-notifications-go-sdk v0.0.0-20210310100607-5790b96c47f5 h1:NPUhkoOCRuv3OFWt19PmwjXGGTKlvmbuPg9fUrBUNe4= github.com/IBM/push-notifications-go-sdk v0.0.0-20210310100607-5790b96c47f5/go.mod h1:b07XHUVh0XYnQE9s2mqgjYST1h9buaQNqN4EcKhOsX0= github.com/IBM/sarama v1.41.2 h1:ZDBZfGPHAD4uuAtSv4U22fRZBgst0eEwGFzLj0fb85c= github.com/IBM/sarama v1.41.2/go.mod h1:xdpu7sd6OE1uxNdjYTSKUfY8FaKkJES9/+EyjSgiGQk= -github.com/IBM/scc-go-sdk/v5 v5.1.4 h1:+HoeUJCyGAJpQv2hBskKdMC1I6K617zbHF5lpbK5VYI= -github.com/IBM/scc-go-sdk/v5 v5.1.4/go.mod h1:YtAVlzq10bwR82QX4ZavhDIwa1s85RuVO9N/KmXVcuk= +github.com/IBM/scc-go-sdk/v5 v5.1.5 h1:c17/7CfUjjgHXQe1fIY3GVsahqij1vDu9/dKPak8Tes= +github.com/IBM/scc-go-sdk/v5 v5.1.5/go.mod h1:YtAVlzq10bwR82QX4ZavhDIwa1s85RuVO9N/KmXVcuk= github.com/IBM/schematics-go-sdk v0.2.3 h1:lgTt0Sbudii3cuSk1YSQgrtiZAXDbBABAoVj3eQuBrU= github.com/IBM/schematics-go-sdk v0.2.3/go.mod h1:Tw2OSAPdpC69AxcwoyqcYYaGTTW6YpERF9uNEU+BFRQ= -github.com/IBM/secrets-manager-go-sdk/v2 v2.0.2 h1:+Svh1OmoFxMBnZQSOUtp2UUzrOGFsSQlE5TFL/ptJco= -github.com/IBM/secrets-manager-go-sdk/v2 v2.0.2/go.mod h1:WII+LS4VkQYykmq65NWSuPb5xGNvsqkcK1aCWZoU2x4= +github.com/IBM/secrets-manager-go-sdk/v2 v2.0.3 h1:28x9ksuRllUbDHmbwk15snNZgaEDc+BtY5Ey8oMqKn8= +github.com/IBM/secrets-manager-go-sdk/v2 v2.0.3/go.mod h1:5gq8D8uWOIbqOm1uztay6lpOysgJaxxEsaVZLWGWb40= github.com/IBM/vpc-beta-go-sdk v0.6.0 h1:wfM3AcW3zOM3xsRtZ+EA6+sESlGUjQ6Yf4n5QQyz4uc= github.com/IBM/vpc-beta-go-sdk v0.6.0/go.mod h1:fzHDAQIqH/5yJmYsKodKHLcqxMDT+yfH6vZjdiw8CQA= -github.com/IBM/vpc-go-sdk v0.47.0 h1:2Qcjd4zQQRYjz+y4ZMDP6+aWGifyXCZ9uMmlpW7p9To= -github.com/IBM/vpc-go-sdk v0.47.0/go.mod h1:4Hs5d/aClmsxAzwDQkwG+ri0vW2ykPJdpM6hDLRwKcA= +github.com/IBM/vpc-go-sdk v0.48.0 h1:4yeSxVX9mizsIW2F0rsVI47rZoNKBrZ1QK9RwwRas9Q= +github.com/IBM/vpc-go-sdk v0.48.0/go.mod h1:FDJpiokOmaYG2hNYDfqKVxUPe8mm/dPi3mdz8Zt4o/Q= 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= @@ -552,8 +552,8 @@ github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrC github.com/go-openapi/strfmt v0.21.2/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k= github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg= github.com/go-openapi/strfmt v0.21.7/go.mod h1:adeGTkxE44sPyLk0JV235VQAO/ZXUr8KAzYjclFs3ew= -github.com/go-openapi/strfmt v0.21.10 h1:JIsly3KXZB/Qf4UzvzJpg4OELH/0ASDQsyk//TTBDDk= -github.com/go-openapi/strfmt v0.21.10/go.mod h1:vNDMwbilnl7xKiO/Ve/8H8Bb2JIInBnH+lqiw6QWgis= +github.com/go-openapi/strfmt v0.22.0 h1:Ew9PnEYc246TwrEspvBdDHS4BVKXy/AOVsfqGDgAcaI= +github.com/go-openapi/strfmt v0.22.0/go.mod h1:HzJ9kokGIju3/K6ap8jL+OlGAbjpSv27135Yr9OivU4= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= @@ -580,8 +580,8 @@ github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+ github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.16.0 h1:x+plE831WK4vaKHO/jpgUGsvLKIqRRkz6M78GuJAfGE= -github.com/go-playground/validator/v10 v10.16.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-playground/validator/v10 v10.18.0 h1:BvolUXjp4zuvkZ5YN5t7ebzbhlUtPsPm2S9NAZ5nl9U= +github.com/go-playground/validator/v10 v10.18.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= @@ -729,8 +729,8 @@ github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= -github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= @@ -840,8 +840,8 @@ github.com/hashicorp/go-retryablehttp v0.6.2/go.mod h1:gEx6HMUGxYYhJScX7W1Il64m6 github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= -github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA= -github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M= +github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= @@ -1090,8 +1090,8 @@ github.com/kubernetes-csi/external-snapshotter/client/v4 v4.0.0/go.mod h1:YBCo4D github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= -github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= -github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/libopenstorage/autopilot-api v0.6.1-0.20210128210103-5fbb67948648/go.mod h1:6JLrPbR3ZJQFbUY/+QJMl/aF00YdIrLf8/GWAplgvJs= github.com/libopenstorage/openstorage v8.0.0+incompatible/go.mod h1:Sp1sIObHjat1BeXhfMqLZ14wnOzEhNx2YQedreMcUyc= @@ -1523,10 +1523,8 @@ github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= -github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= -github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= @@ -1564,8 +1562,8 @@ go.mongodb.org/mongo-driver v1.7.0/go.mod h1:Q4oFMbo1+MSNqICAdYMlC/zSTrwCogR4R8N go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= go.mongodb.org/mongo-driver v1.11.3/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g= -go.mongodb.org/mongo-driver v1.13.1 h1:YIc7HTYsKndGK4RFzJ3covLz1byri52x0IoMB0Pt/vk= -go.mongodb.org/mongo-driver v1.13.1/go.mod h1:wcDf1JBCXy2mOW0bWHwO/IOYqdca1MPCwDtFu/Z9+eo= +go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80= +go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= go.opencensus.io v0.19.1/go.mod h1:gug0GbSHa8Pafr0d2urOSgoXHZ6x/RUlaiT0d9pqb4A= go.opencensus.io v0.19.2/go.mod h1:NO/8qkisMZLZ1FCsKNqtJPwc8/TaclWyY0B6wcYNg9M= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= @@ -1635,8 +1633,8 @@ golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1759,8 +1757,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190130055435-99b60b757ec1/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1904,8 +1902,8 @@ golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1920,8 +1918,8 @@ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= -golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= -golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= +golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1933,7 +1931,6 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= diff --git a/ibm/acctest/acctest.go b/ibm/acctest/acctest.go index 3066238605..e8941f3f00 100644 --- a/ibm/acctest/acctest.go +++ b/ibm/acctest/acctest.go @@ -84,6 +84,7 @@ var ( ISZoneName2 string ISZoneName3 string IsResourceGroupID string + ISResourceCrn string ISCIDR string ISCIDR2 string ISPublicSSHKeyFilePath string @@ -205,6 +206,7 @@ var ( Pi_volume_onboarding_id string Pi_network_name string Pi_cloud_instance_id string + Pi_snapshot_id string Pi_instance_name string Pi_dhcp_id string PiCloudConnectionName string @@ -232,6 +234,7 @@ var ISDelegegatedVPC string var ( IsImageName string IsImage string + IsImage2 string IsImageEncryptedDataKey string IsImageEncryptionKey string IsWinImage string @@ -707,6 +710,11 @@ func init() { IsResourceGroupID = "c01d34dff4364763476834c990398zz8" fmt.Println("[INFO] Set the environment variable SL_RESOURCE_GROUP_ID for testing with different resource group id else it is set to default value 'c01d34dff4364763476834c990398zz8'") } + ISResourceCrn = os.Getenv("IS_RESOURCE_INSTANCE_CRN") + if ISResourceCrn == "" { + ISResourceCrn = "crn:v1:bluemix:public:cloud-object-storage:global:a/fugeggfcgjebvrburvgurgvugfr:236764224-f48fu4-f4h84-9db3-4f94fh::" + fmt.Println("[INFO] Set the environment variable IS_RESOURCE_CRN for testing with created resource instance") + } IsImage = os.Getenv("IS_IMAGE") if IsImage == "" { @@ -715,6 +723,12 @@ func init() { fmt.Println("[INFO] Set the environment variable IS_IMAGE for testing ibm_is_instance, ibm_is_floating_ip else it is set to default value 'r006-907911a7-0ffe-467e-8821-3cc9a0d82a39'") } + IsImage2 = os.Getenv("IS_IMAGE2") + if IsImage2 == "" { + IsImage2 = "r134-f47cc24c-e020-4db5-ad96-1e5be8b5853b" // for next gen infrastructure ibm-centos-7-9-minimal-amd64-10 image + fmt.Println("[INFO] Set the environment variable IS_IMAGE2 for testing ibm_is_instance, ibm_is_floating_ip else it is set to default value 'r134-f47cc24c-e020-4db5-ad96-1e5be8b5853b'") + } + IsWinImage = os.Getenv("IS_WIN_IMAGE") if IsWinImage == "" { // IsWinImage = "a7a0626c-f97e-4180-afbe-0331ec62f32a" // classic windows machine: ibm-windows-server-2012-full-standard-amd64-1 @@ -783,8 +797,8 @@ func init() { IsBareMetalServerProfileName = os.Getenv("IS_BARE_METAL_SERVER_PROFILE") if IsBareMetalServerProfileName == "" { - IsBareMetalServerProfileName = "bx2-metal-192x768" // for next gen infrastructure - fmt.Println("[INFO] Set the environment variable IS_BARE_METAL_SERVER_PROFILE for testing ibm_is_bare_metal_server resource else it is set to default value 'bx2-metal-192x768'") + IsBareMetalServerProfileName = "bx2-metal-96x384" // for next gen infrastructure + fmt.Println("[INFO] Set the environment variable IS_BARE_METAL_SERVER_PROFILE for testing ibm_is_bare_metal_server resource else it is set to default value 'bx2-metal-96x384'") } IsBareMetalServerImage = os.Getenv("IS_BARE_METAL_SERVER_IMAGE") @@ -1029,6 +1043,12 @@ func init() { fmt.Println("[INFO] Set the environment variable PI_CLOUDINSTANCE_ID for testing ibm_pi_image resource else it is set to default value 'd16705bd-7f1a-48c9-9e0e-1c17b71e7331'") } + Pi_snapshot_id = os.Getenv("PI_SNAPSHOT_ID") + if Pi_snapshot_id == "" { + Pi_snapshot_id = "1ea33118-4c43-4356-bfce-904d0658de82" + fmt.Println("[INFO] Set the environment variable PI_SNAPSHOT_ID for testing ibm_pi_instance_snapshot data source else it is set to default value '1ea33118-4c43-4356-bfce-904d0658de82'") + } + Pi_instance_name = os.Getenv("PI_PVM_INSTANCE_NAME") if Pi_instance_name == "" { Pi_instance_name = "terraform-test-power" @@ -1269,18 +1289,6 @@ func init() { fmt.Println("[INFO] Set the environment variable SECRETS_MANAGER_SERVICE_CREDENTIALS_COS_CRN for testing service credentials' tests, else tests fail if not set correctly") } - SecretsManagerSecretType = os.Getenv("SECRETS_MANAGER_SECRET_TYPE") - if SecretsManagerSecretType == "" { - SecretsManagerSecretType = "username_password" - fmt.Println("[INFO] Set the environment variable SECRETS_MANAGER_SECRET_TYPE for testing data_source_ibm_secrets_manager_secrets_test, else it is set to default value. For data_source_ibm_secrets_manager_secret_test, tests will fail if this is not set correctly") - } - - SecretsManagerSecretID = os.Getenv("SECRETS_MANAGER_SECRET_ID") - if SecretsManagerSecretID == "" { - // SecretsManagerSecretID = "644f4a69-0d17-198f-3b58-23f2746c706d" - fmt.Println("[WARN] Set the environment variable SECRETS_MANAGER_SECRET_ID for testing data_source_ibm_secrets_manager_secret_test else tests will fail if this is not set correctly") - } - Tg_cross_network_account_api_key = os.Getenv("IBM_TG_CROSS_ACCOUNT_API_KEY") if Tg_cross_network_account_api_key == "" { fmt.Println("[INFO] Set the environment variable IBM_TG_CROSS_ACCOUNT_API_KEY for testing ibm_tg_connection resource else tests will fail if this is not set correctly") diff --git a/ibm/conns/config.go b/ibm/conns/config.go index c2fc691288..38d3afc484 100644 --- a/ibm/conns/config.go +++ b/ibm/conns/config.go @@ -119,7 +119,6 @@ import ( "github.com/IBM/eventstreams-go-sdk/pkg/schemaregistryv1" "github.com/IBM/ibm-hpcs-uko-sdk/ukov4" scc "github.com/IBM/scc-go-sdk/v5/securityandcompliancecenterapiv3" - "github.com/IBM/secrets-manager-go-sdk/v2/secretsmanagerv1" "github.com/IBM/secrets-manager-go-sdk/v2/secretsmanagerv2" ) @@ -283,7 +282,6 @@ type ClientSession interface { CatalogManagementV1() (*catalogmanagementv1.CatalogManagementV1, error) EnterpriseManagementV1() (*enterprisemanagementv1.EnterpriseManagementV1, error) ResourceControllerV2API() (*resourcecontroller.ResourceControllerV2, error) - SecretsManagerV1() (*secretsmanagerv1.SecretsManagerV1, error) SecretsManagerV2() (*secretsmanagerv2.SecretsManagerV2, error) SchematicsV1() (*schematicsv1.SchematicsV1, error) SatelliteClientSession() (*kubernetesserviceapiv1.KubernetesServiceApiV1, error) @@ -540,7 +538,6 @@ type clientSession struct { // Resource Controller Option resourceControllerErr error resourceControllerAPI *resourcecontroller.ResourceControllerV2 - secretsManagerClientV1 *secretsmanagerv1.SecretsManagerV1 secretsManagerClient *secretsmanagerv2.SecretsManagerV2 secretsManagerClientErr error @@ -1086,11 +1083,6 @@ func (sess clientSession) ResourceControllerV2API() (*resourcecontroller.Resourc return sess.resourceControllerAPI, sess.resourceControllerErr } -// IBM Cloud Secrets Manager V1 Basic API -func (session clientSession) SecretsManagerV1() (*secretsmanagerv1.SecretsManagerV1, error) { - return session.secretsManagerClientV1, session.secretsManagerClientErr -} - // IBM Cloud Secrets Manager V2 Basic API func (session clientSession) SecretsManagerV2() (*secretsmanagerv2.SecretsManagerV2, error) { return session.secretsManagerClient, session.secretsManagerClientErr @@ -1332,20 +1324,8 @@ func (c *Config) ClientSession() (interface{}, error) { session.functionConfigErr = fmt.Errorf("[ERROR] Error occured while fetching auth key for function: %q", err) } } - err = authenticateCF(sess.BluemixSession) - if err != nil { - for count := c.RetryCount; count >= 0; count-- { - if err == nil || !isRetryable(err) { - break - } - time.Sleep(c.RetryDelay) - log.Printf("Retrying CF Authentication %d", count) - err = authenticateCF(sess.BluemixSession) - } - if err != nil { - session.functionConfigErr = fmt.Errorf("[ERROR] Error occured while fetching auth key for function: %q", err) - } - } + + session.functionConfigErr = fmt.Errorf("[ERROR] Error occured while fetching auth key for function: %q", err) } if c.IAMTrustedProfileID == "" && sess.BluemixSession.Config.IAMAccessToken != "" && sess.BluemixSession.Config.BluemixAPIKey == "" { @@ -1577,7 +1557,7 @@ func (c *Config) ClientSession() (interface{}, error) { session.ukoClientErr = fmt.Errorf("Error occurred while configuring HPCS UKO service: %q", err) } - // APPID Service + // APP ID Service appIDEndpoint := fmt.Sprintf("https://%s.appid.cloud.ibm.com", c.Region) if c.Visibility == "private" { session.appidErr = fmt.Errorf("App Id resources doesnot support private endpoints") @@ -1884,11 +1864,14 @@ func (c *Config) ClientSession() (interface{}, error) { }) } session.pushServiceClient = pnclient + // event notifications enurl := fmt.Sprintf("https://%s.event-notifications.cloud.ibm.com/event-notifications", c.Region) - if c.Visibility == "private" { - session.eventNotificationsApiClientErr = fmt.Errorf("Event Notifications Service does not support private endpoints") + + if c.Visibility == "private" || c.Visibility == "public-and-private" { + enurl = fmt.Sprintf("https://private.%s.event-notifications.cloud.ibm.com/event-notifications", c.Region) } + if fileMap != nil && c.Visibility != "public-and-private" { enurl = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_EVENT_NOTIFICATIONS_API_ENDPOINT", c.Region, enurl) } @@ -3084,24 +3067,6 @@ func (c *Config) ClientSession() (interface{}, error) { } session.resourceControllerAPI = resourceControllerClient - // SECRETS MANAGER Service - secretsManagerClientOptions := &secretsmanagerv1.SecretsManagerV1Options{ - Authenticator: authenticator, - } - /// Construct the service client. - session.secretsManagerClientV1, err = secretsmanagerv1.NewSecretsManagerV1(secretsManagerClientOptions) - if err != nil { - session.secretsManagerClientErr = fmt.Errorf("[ERROR] Error occurred while configuring IBM Cloud Secrets Manager API service: %q", err) - } - if session.secretsManagerClient != nil && session.secretsManagerClient.Service != nil { - // Enable retries for API calls - session.secretsManagerClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) - // Add custom header for analytics - session.secretsManagerClient.SetDefaultHeaders(gohttp.Header{ - "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, - }) - } - // SECRETS MANAGER Service V2 // Construct an "options" struct for creating the service client. var smBaseUrl string @@ -3429,20 +3394,6 @@ func authenticateAPIKey(sess *bxsession.Session) error { return tokenRefresher.AuthenticateAPIKey(config.BluemixAPIKey) } -func authenticateCF(sess *bxsession.Session) error { - config := sess.Config - tokenRefresher, err := authentication.NewUAARepository(config, &rest.Client{ - DefaultHeader: gohttp.Header{ - "User-Agent": []string{http.UserAgent()}, - "X-Original-User-Agent": []string{http.UserAgent()}, - }, - }) - if err != nil { - return err - } - return tokenRefresher.AuthenticateAPIKey(config.BluemixAPIKey) -} - func fetchUserDetails(sess *bxsession.Session, retries int, retryDelay time.Duration) (*UserConfig, error) { config := sess.Config user := UserConfig{} diff --git a/ibm/flex/structures.go b/ibm/flex/structures.go index 3429894e39..90027e1cbe 100644 --- a/ibm/flex/structures.go +++ b/ibm/flex/structures.go @@ -1,4 +1,4 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Copyright IBM Corp. 2017, 2024 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 package flex @@ -1215,9 +1215,9 @@ func IntValue(i64 *int64) (i int) { return } -func float64Value(f32 *float32) (f float64) { - if f32 != nil { - f = float64(*f32) +func StringValue(strPtr *string) (_ string) { + if strPtr != nil { + return *strPtr } return } @@ -1639,7 +1639,11 @@ func FlattenV2PolicyResource(resource iampolicymanagementv1.V2PolicyResource) [] if len(customAttributes) > 0 { out := make(map[string]string) for _, a := range customAttributes { - out[*a.Key] = fmt.Sprint(a.Value) + if *a.Operator == "stringExists" && a.Value == true { + out[*a.Key] = fmt.Sprint("*") + } else if *a.Operator == "stringMatch" || *a.Operator == "stringEquals" { + out[*a.Key] = fmt.Sprint(a.Value) + } } l["attributes"] = out } @@ -2710,43 +2714,6 @@ func ResourceValidateAccessTags(diff *schema.ResourceDiff, meta interface{}) err return nil } -func ResourceLBListenerPolicyCustomizeDiff(diff *schema.ResourceDiff) error { - policyActionIntf, _ := diff.GetOk(isLBListenerPolicyAction) - policyAction := policyActionIntf.(string) - - if policyAction == "forward" { - _, policyTargetIDSet := diff.GetOk(isLBListenerPolicyTargetID) - - if !policyTargetIDSet && diff.NewValueKnown(isLBListenerPolicyTargetID) { - return fmt.Errorf("Load balancer listener policy: When action is forward please specify target_id") - } - } else if policyAction == "redirect" { - _, httpsStatusCodeSet := diff.GetOk(isLBListenerPolicyTargetHTTPStatusCode) - _, targetURLSet := diff.GetOk(isLBListenerPolicyTargetURL) - - if !httpsStatusCodeSet && diff.NewValueKnown(isLBListenerPolicyTargetHTTPStatusCode) { - return fmt.Errorf("Load balancer listener policy: When action is redirect please specify target_http_status_code") - } - - if !targetURLSet && diff.NewValueKnown(isLBListenerPolicyTargetURL) { - return fmt.Errorf("Load balancer listener policy: When action is redirect please specify target_url") - } - } else if policyAction == "https_redirect" { - _, listenerSet := diff.GetOk(isLBListenerPolicyHTTPSRedirectListener) - _, httpsStatusSet := diff.GetOk(isLBListenerPolicyHTTPSRedirectStatusCode) - - if !listenerSet && diff.NewValueKnown(isLBListenerPolicyHTTPSRedirectListener) { - return fmt.Errorf("Load balancer listener policy: When action is https_redirect please specify target_https_redirect_listener") - } - - if !httpsStatusSet && diff.NewValueKnown(isLBListenerPolicyHTTPSRedirectStatusCode) { - return fmt.Errorf("When action is https_redirect please specify target_https_redirect_status_code") - } - } - - return nil -} - func ResourceIBMISLBPoolCookieValidate(diff *schema.ResourceDiff) error { _, sessionPersistenceTypeIntf := diff.GetChange(isLBPoolSessPersistenceType) _, sessionPersistenceCookieNameIntf := diff.GetChange(isLBPoolSessPersistenceAppCookieName) @@ -3345,10 +3312,12 @@ func GetResourceAttribute(name string, r iampolicymanagementv1.PolicyResource) * func GetV2PolicyResourceAttribute(key string, r iampolicymanagementv1.V2PolicyResource) string { for _, a := range r.Attributes { - if *a.Key == key && - (*a.Operator == "stringMatch" || - *a.Operator == "stringEquals") { - return a.Value.(string) + if *a.Key == key { + if *a.Operator == "stringExists" && a.Value == true { + return fmt.Sprint("*") + } else if *a.Operator == "stringMatch" || *a.Operator == "stringEquals" { + return a.Value.(string) + } } } return *core.StringPtr("") @@ -3363,7 +3332,7 @@ func GetSubjectAttribute(name string, s iampolicymanagementv1.PolicySubject) *st return core.StringPtr("") } -func GetV2PolicySubjectAttribute(key string, s iampolicymanagementv1.V2PolicySubject) *string { +func GetV2PolicySubjectAttribute(key string, s iampolicymanagementv1.V2PolicySubject) interface{} { for _, a := range s.Attributes { if *a.Key == key && (*a.Operator == "stringMatch" || @@ -3371,7 +3340,7 @@ func GetV2PolicySubjectAttribute(key string, s iampolicymanagementv1.V2PolicySub return a.Value } } - return core.StringPtr("") + return interface{}(core.StringPtr("")) } func SetResourceAttribute(name *string, value *string, r []iampolicymanagementv1.ResourceAttribute) []iampolicymanagementv1.ResourceAttribute { @@ -3512,6 +3481,7 @@ func GetRoleNamesFromPolicyResponse(policy iampolicymanagementv1.V2PolicyTemplat controlResponse := policy.Control.(*iampolicymanagementv1.ControlResponse) policyRoles := MapRolesToPolicyRoles(controlResponse.Grant.Roles) resourceAttributes := policy.Resource.Attributes + subjectAttributes := policy.Subject.Attributes userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() if err != nil { @@ -3519,11 +3489,20 @@ func GetRoleNamesFromPolicyResponse(policy iampolicymanagementv1.V2PolicyTemplat } var ( - serviceName string - resourceType string - serviceGroupID string + serviceName string + sourceServiceName string + resourceType string + serviceGroupID string ) + for _, a := range subjectAttributes { + if *a.Key == "serviceName" && + (*a.Operator == "stringMatch" || + *a.Operator == "stringEquals") { + sourceServiceName = a.Value.(string) + } + } + for _, a := range resourceAttributes { if *a.Key == "serviceName" && (*a.Operator == "stringMatch" || @@ -3550,6 +3529,11 @@ func GetRoleNamesFromPolicyResponse(policy iampolicymanagementv1.V2PolicyTemplat if accountManagement, ok := d.GetOk("account_management"); ok { isAccountManagementPolicy = accountManagement.(bool) } + + if serviceName == "" && resourceType == "resource-group" { + serviceName = "resource-controller" + } + if serviceName == "" && // no specific service specified !isAccountManagementPolicy && // not all account management services resourceType != "resource-group" && // not to a resource group @@ -3565,6 +3549,14 @@ func GetRoleNamesFromPolicyResponse(policy iampolicymanagementv1.V2PolicyTemplat listRoleOptions.ServiceGroupID = &serviceGroupID } + if sourceServiceName != "" { + listRoleOptions.SourceServiceName = &sourceServiceName + } + + if *policy.Type != "" { + listRoleOptions.PolicyType = policy.Type + } + roleList, _, err := iamPolicyManagementClient.ListRoles(listRoleOptions) if err != nil { diff --git a/ibm/provider/provider.go b/ibm/provider/provider.go index 9f5ff9a6e8..5f111c505d 100644 --- a/ibm/provider/provider.go +++ b/ibm/provider/provider.go @@ -388,6 +388,8 @@ func Provider() *schema.Provider { "ibm_is_bare_metal_server_disk": vpc.DataSourceIBMIsBareMetalServerDisk(), "ibm_is_bare_metal_server_disks": vpc.DataSourceIBMIsBareMetalServerDisks(), "ibm_is_bare_metal_server_initialization": vpc.DataSourceIBMIsBareMetalServerInitialization(), + "ibm_is_bare_metal_server_network_attachment": vpc.DataSourceIBMIsBareMetalServerNetworkAttachment(), + "ibm_is_bare_metal_server_network_attachments": vpc.DataSourceIBMIsBareMetalServerNetworkAttachments(), "ibm_is_bare_metal_server_network_interface_floating_ip": vpc.DataSourceIBMIsBareMetalServerNetworkInterfaceFloatingIP(), "ibm_is_bare_metal_server_network_interface_floating_ips": vpc.DataSourceIBMIsBareMetalServerNetworkInterfaceFloatingIPs(), "ibm_is_bare_metal_server_network_interface_reserved_ip": vpc.DataSourceIBMISBareMetalServerNICReservedIP(), @@ -437,6 +439,8 @@ func Provider() *schema.Provider { "ibm_is_instance_profiles": vpc.DataSourceIBMISInstanceProfiles(), "ibm_is_instance": vpc.DataSourceIBMISInstance(), "ibm_is_instances": vpc.DataSourceIBMISInstances(), + "ibm_is_instance_network_attachment": vpc.DataSourceIBMIsInstanceNetworkAttachment(), + "ibm_is_instance_network_attachments": vpc.DataSourceIBMIsInstanceNetworkAttachments(), "ibm_is_instance_network_interface": vpc.DataSourceIBMIsInstanceNetworkInterface(), "ibm_is_instance_network_interfaces": vpc.DataSourceIBMIsInstanceNetworkInterfaces(), "ibm_is_instance_disk": vpc.DataSourceIbmIsInstanceDisk(), @@ -446,55 +450,65 @@ func Provider() *schema.Provider { "ibm_is_instance_network_interface_reserved_ip": vpc.DataSourceIBMISInstanceNICReservedIP(), "ibm_is_instance_network_interface_reserved_ips": vpc.DataSourceIBMISInstanceNICReservedIPs(), - "ibm_is_instance_volume_attachment": vpc.DataSourceIBMISInstanceVolumeAttachment(), - "ibm_is_instance_volume_attachments": vpc.DataSourceIBMISInstanceVolumeAttachments(), - "ibm_is_ipsec_policy": vpc.DataSourceIBMIsIpsecPolicy(), - "ibm_is_ipsec_policies": vpc.DataSourceIBMIsIpsecPolicies(), - "ibm_is_ike_policies": vpc.DataSourceIBMIsIkePolicies(), - "ibm_is_ike_policy": vpc.DataSourceIBMIsIkePolicy(), - "ibm_is_lb": vpc.DataSourceIBMISLB(), - "ibm_is_lb_listener": vpc.DataSourceIBMISLBListener(), - "ibm_is_lb_listeners": vpc.DataSourceIBMISLBListeners(), - "ibm_is_lb_listener_policies": vpc.DataSourceIBMISLBListenerPolicies(), - "ibm_is_lb_listener_policy": vpc.DataSourceIBMISLBListenerPolicy(), - "ibm_is_lb_listener_policy_rule": vpc.DataSourceIBMISLBListenerPolicyRule(), - "ibm_is_lb_listener_policy_rules": vpc.DataSourceIBMISLBListenerPolicyRules(), - "ibm_is_lb_pool": vpc.DataSourceIBMISLBPool(), - "ibm_is_lb_pools": vpc.DataSourceIBMISLBPools(), - "ibm_is_lb_pool_member": vpc.DataSourceIBMIBLBPoolMember(), - "ibm_is_lb_pool_members": vpc.DataSourceIBMISLBPoolMembers(), - "ibm_is_lb_profile": vpc.DataSourceIBMISLbProfile(), - "ibm_is_lb_profiles": vpc.DataSourceIBMISLbProfiles(), - "ibm_is_lbs": vpc.DataSourceIBMISLBS(), - "ibm_is_public_gateway": vpc.DataSourceIBMISPublicGateway(), - "ibm_is_public_gateways": vpc.DataSourceIBMISPublicGateways(), - "ibm_is_region": vpc.DataSourceIBMISRegion(), - "ibm_is_regions": vpc.DataSourceIBMISRegions(), - "ibm_is_ssh_key": vpc.DataSourceIBMISSSHKey(), - "ibm_is_ssh_keys": vpc.DataSourceIBMIsSshKeys(), - "ibm_is_subnet": vpc.DataSourceIBMISSubnet(), - "ibm_is_subnets": vpc.DataSourceIBMISSubnets(), - "ibm_is_subnet_reserved_ip": vpc.DataSourceIBMISReservedIP(), - "ibm_is_subnet_reserved_ips": vpc.DataSourceIBMISReservedIPs(), - "ibm_is_security_group": vpc.DataSourceIBMISSecurityGroup(), - "ibm_is_security_groups": vpc.DataSourceIBMIsSecurityGroups(), - "ibm_is_security_group_rule": vpc.DataSourceIBMIsSecurityGroupRule(), - "ibm_is_security_group_rules": vpc.DataSourceIBMIsSecurityGroupRules(), - "ibm_is_security_group_target": vpc.DataSourceIBMISSecurityGroupTarget(), - "ibm_is_security_group_targets": vpc.DataSourceIBMISSecurityGroupTargets(), - "ibm_is_snapshot_clone": vpc.DataSourceSnapshotClone(), - "ibm_is_snapshot_clones": vpc.DataSourceSnapshotClones(), - "ibm_is_snapshot": vpc.DataSourceSnapshot(), - "ibm_is_snapshot_consistency_group": vpc.DataSourceIBMIsSnapshotConsistencyGroup(), - "ibm_is_snapshot_consistency_groups": vpc.DataSourceIBMIsSnapshotConsistencyGroups(), - "ibm_is_snapshots": vpc.DataSourceSnapshots(), - "ibm_is_share": vpc.DataSourceIbmIsShare(), - "ibm_is_source_share": vpc.DataSourceIbmIsSourceShare(), - "ibm_is_shares": vpc.DataSourceIbmIsShares(), - "ibm_is_share_profile": vpc.DataSourceIbmIsShareProfile(), - "ibm_is_share_profiles": vpc.DataSourceIbmIsShareProfiles(), - "ibm_is_virtual_network_interface": vpc.DataSourceIBMIsVirtualNetworkInterface(), - "ibm_is_virtual_network_interfaces": vpc.DataSourceIBMIsVirtualNetworkInterfaces(), + "ibm_is_instance_volume_attachment": vpc.DataSourceIBMISInstanceVolumeAttachment(), + "ibm_is_instance_volume_attachments": vpc.DataSourceIBMISInstanceVolumeAttachments(), + "ibm_is_ipsec_policy": vpc.DataSourceIBMIsIpsecPolicy(), + "ibm_is_ipsec_policies": vpc.DataSourceIBMIsIpsecPolicies(), + "ibm_is_ike_policies": vpc.DataSourceIBMIsIkePolicies(), + "ibm_is_ike_policy": vpc.DataSourceIBMIsIkePolicy(), + "ibm_is_lb": vpc.DataSourceIBMISLB(), + "ibm_is_lb_listener": vpc.DataSourceIBMISLBListener(), + "ibm_is_lb_listeners": vpc.DataSourceIBMISLBListeners(), + "ibm_is_lb_listener_policies": vpc.DataSourceIBMISLBListenerPolicies(), + "ibm_is_lb_listener_policy": vpc.DataSourceIBMISLBListenerPolicy(), + "ibm_is_lb_listener_policy_rule": vpc.DataSourceIBMISLBListenerPolicyRule(), + "ibm_is_lb_listener_policy_rules": vpc.DataSourceIBMISLBListenerPolicyRules(), + "ibm_is_lb_pool": vpc.DataSourceIBMISLBPool(), + "ibm_is_lb_pools": vpc.DataSourceIBMISLBPools(), + "ibm_is_lb_pool_member": vpc.DataSourceIBMIBLBPoolMember(), + "ibm_is_lb_pool_members": vpc.DataSourceIBMISLBPoolMembers(), + "ibm_is_lb_profile": vpc.DataSourceIBMISLbProfile(), + "ibm_is_lb_profiles": vpc.DataSourceIBMISLbProfiles(), + "ibm_is_lbs": vpc.DataSourceIBMISLBS(), + "ibm_is_public_gateway": vpc.DataSourceIBMISPublicGateway(), + "ibm_is_public_gateways": vpc.DataSourceIBMISPublicGateways(), + "ibm_is_region": vpc.DataSourceIBMISRegion(), + "ibm_is_regions": vpc.DataSourceIBMISRegions(), + "ibm_is_reservation": vpc.DataSourceIBMIsReservation(), + "ibm_is_reservations": vpc.DataSourceIBMIsReservations(), + "ibm_is_ssh_key": vpc.DataSourceIBMISSSHKey(), + "ibm_is_ssh_keys": vpc.DataSourceIBMIsSshKeys(), + "ibm_is_subnet": vpc.DataSourceIBMISSubnet(), + "ibm_is_subnets": vpc.DataSourceIBMISSubnets(), + "ibm_is_subnet_reserved_ip": vpc.DataSourceIBMISReservedIP(), + "ibm_is_subnet_reserved_ips": vpc.DataSourceIBMISReservedIPs(), + "ibm_is_security_group": vpc.DataSourceIBMISSecurityGroup(), + "ibm_is_security_groups": vpc.DataSourceIBMIsSecurityGroups(), + "ibm_is_security_group_rule": vpc.DataSourceIBMIsSecurityGroupRule(), + "ibm_is_security_group_rules": vpc.DataSourceIBMIsSecurityGroupRules(), + "ibm_is_security_group_target": vpc.DataSourceIBMISSecurityGroupTarget(), + "ibm_is_security_group_targets": vpc.DataSourceIBMISSecurityGroupTargets(), + "ibm_is_snapshot_clone": vpc.DataSourceSnapshotClone(), + "ibm_is_snapshot_clones": vpc.DataSourceSnapshotClones(), + "ibm_is_snapshot": vpc.DataSourceSnapshot(), + "ibm_is_snapshot_consistency_group": vpc.DataSourceIBMIsSnapshotConsistencyGroup(), + "ibm_is_snapshot_consistency_groups": vpc.DataSourceIBMIsSnapshotConsistencyGroups(), + "ibm_is_snapshots": vpc.DataSourceSnapshots(), + "ibm_is_share": vpc.DataSourceIbmIsShare(), + "ibm_is_source_share": vpc.DataSourceIbmIsSourceShare(), + "ibm_is_shares": vpc.DataSourceIbmIsShares(), + "ibm_is_share_profile": vpc.DataSourceIbmIsShareProfile(), + "ibm_is_share_profiles": vpc.DataSourceIbmIsShareProfiles(), + "ibm_is_virtual_network_interface": vpc.DataSourceIBMIsVirtualNetworkInterface(), + "ibm_is_virtual_network_interfaces": vpc.DataSourceIBMIsVirtualNetworkInterfaces(), + + // vni + + "ibm_is_virtual_network_interface_floating_ip": vpc.DataSourceIBMIsVirtualNetworkInterfaceFloatingIP(), + "ibm_is_virtual_network_interface_floating_ips": vpc.DataSourceIBMIsVirtualNetworkInterfaceFloatingIPs(), + "ibm_is_virtual_network_interface_ip": vpc.DataSourceIBMIsVirtualNetworkInterfaceIP(), + "ibm_is_virtual_network_interface_ips": vpc.DataSourceIBMIsVirtualNetworkInterfaceIPs(), + "ibm_is_share_mount_target": vpc.DataSourceIBMIsShareTarget(), "ibm_is_share_mount_targets": vpc.DataSourceIBMIsShareTargets(), "ibm_is_volume": vpc.DataSourceIBMISVolume(), @@ -596,7 +610,8 @@ func Provider() *schema.Provider { "ibm_pi_instance": power.DataSourceIBMPIInstance(), "ibm_pi_instances": power.DataSourceIBMPIInstances(), "ibm_pi_instance_ip": power.DataSourceIBMPIInstanceIP(), - "ibm_pi_instance_snapshots": power.DataSourceIBMPISnapshots(), + "ibm_pi_instance_snapshot": power.DataSourceIBMPIInstanceSnapshot(), + "ibm_pi_instance_snapshots": power.DataSourceIBMPIInstanceSnapshots(), "ibm_pi_instance_volumes": power.DataSourceIBMPIInstanceVolumes(), "ibm_pi_key": power.DataSourceIBMPIKey(), "ibm_pi_keys": power.DataSourceIBMPIKeys(), @@ -605,7 +620,7 @@ func Provider() *schema.Provider { "ibm_pi_placement_group": power.DataSourceIBMPIPlacementGroup(), "ibm_pi_placement_groups": power.DataSourceIBMPIPlacementGroups(), "ibm_pi_public_network": power.DataSourceIBMPIPublicNetwork(), - "ibm_pi_pvm_snapshots": power.DataSourceIBMPISnapshot(), + "ibm_pi_pvm_snapshots": power.DataSourceIBMPIPVMSnapshot(), "ibm_pi_sap_profile": power.DataSourceIBMPISAPProfile(), "ibm_pi_sap_profiles": power.DataSourceIBMPISAPProfiles(), "ibm_pi_shared_processor_pool": power.DataSourceIBMPISharedProcessorPool(), @@ -684,11 +699,6 @@ func Provider() *schema.Provider { "ibm_billing_snapshot_list": usagereports.DataSourceIBMBillingSnapshotList(), // Added for Secrets Manager - // V1 data sources: - "ibm_secrets_manager_secrets": secretsmanager.DataSourceIBMSecretsManagerSecrets(), - "ibm_secrets_manager_secret": secretsmanager.DataSourceIBMSecretsManagerSecret(), - - // V2 data sources "ibm_sm_secret_group": secretsmanager.AddInstanceFields(secretsmanager.DataSourceIbmSmSecretGroup()), "ibm_sm_secret_groups": secretsmanager.AddInstanceFields(secretsmanager.DataSourceIbmSmSecretGroups()), "ibm_sm_private_certificate_configuration_intermediate_ca": secretsmanager.AddInstanceFields(secretsmanager.DataSourceIbmSmPrivateCertificateConfigurationIntermediateCA()), @@ -718,7 +728,7 @@ func Provider() *schema.Provider { "ibm_sm_service_credentials_secret": secretsmanager.AddInstanceFields(secretsmanager.DataSourceIbmSmServiceCredentialsSecret()), "ibm_sm_en_registration": secretsmanager.AddInstanceFields(secretsmanager.DataSourceIbmSmEnRegistration()), - // //Added for Satellite + // Added for Satellite "ibm_satellite_location": satellite.DataSourceIBMSatelliteLocation(), "ibm_satellite_location_nlb_dns": satellite.DataSourceIBMSatelliteLocationNLBDNS(), "ibm_satellite_attach_host_script": satellite.DataSourceIBMSatelliteAttachHostScript(), @@ -827,6 +837,11 @@ func Provider() *schema.Provider { "ibm_en_sources": eventnotification.DataSourceIBMEnSources(), "ibm_en_destination_custom_email": eventnotification.DataSourceIBMEnCustomEmailDestination(), "ibm_en_subscription_custom_email": eventnotification.DataSourceIBMEnCustomEmailSubscription(), + "ibm_en_email_template": eventnotification.DataSourceIBMEnEmailTemplate(), + "ibm_en_email_templates": eventnotification.DataSourceIBMEnTemplates(), + "ibm_en_destination_custom_sms": eventnotification.DataSourceIBMEnCustomSMSDestination(), + "ibm_en_subscription_custom_sms": eventnotification.DataSourceIBMEnCustomSMSSubscription(), + "ibm_en_integration_cos": eventnotification.DataSourceIBMEnCOSIntegration(), // Added for Toolchain "ibm_cd_toolchain": cdtoolchain.DataSourceIBMCdToolchain(), @@ -1045,6 +1060,7 @@ func Provider() *schema.Provider { // bare_metal_server "ibm_is_bare_metal_server_action": vpc.ResourceIBMIsBareMetalServerAction(), "ibm_is_bare_metal_server_disk": vpc.ResourceIBMIsBareMetalServerDisk(), + "ibm_is_bare_metal_server_network_attachment": vpc.ResourceIBMIsBareMetalServerNetworkAttachment(), "ibm_is_bare_metal_server_network_interface_allow_float": vpc.ResourceIBMIsBareMetalServerNetworkInterfaceAllowFloat(), "ibm_is_bare_metal_server_network_interface_floating_ip": vpc.ResourceIBMIsBareMetalServerNetworkInterfaceFloatingIp(), "ibm_is_bare_metal_server_network_interface": vpc.ResourceIBMIsBareMetalServerNetworkInterface(), @@ -1058,6 +1074,7 @@ func Provider() *schema.Provider { "ibm_is_flow_log": vpc.ResourceIBMISFlowLog(), "ibm_is_instance": vpc.ResourceIBMISInstance(), "ibm_is_instance_action": vpc.ResourceIBMISInstanceAction(), + "ibm_is_instance_network_attachment": vpc.ResourceIBMIsInstanceNetworkAttachment(), "ibm_is_instance_network_interface": vpc.ResourceIBMIsInstanceNetworkInterface(), "ibm_is_instance_network_interface_floating_ip": vpc.ResourceIBMIsInstanceNetworkInterfaceFloatingIp(), "ibm_is_instance_disk_management": vpc.ResourceIBMISInstanceDiskManagement(), @@ -1088,12 +1105,17 @@ func Provider() *schema.Provider { "ibm_is_share_replica_operations": vpc.ResourceIbmIsShareReplicaOperations(), "ibm_is_share_mount_target": vpc.ResourceIBMIsShareMountTarget(), "ibm_is_subnet": vpc.ResourceIBMISSubnet(), + "ibm_is_reservation": vpc.ResourceIBMISReservation(), + "ibm_is_reservation_activate": vpc.ResourceIBMISReservationActivate(), "ibm_is_subnet_reserved_ip": vpc.ResourceIBMISReservedIP(), "ibm_is_subnet_network_acl_attachment": vpc.ResourceIBMISSubnetNetworkACLAttachment(), "ibm_is_subnet_public_gateway_attachment": vpc.ResourceIBMISSubnetPublicGatewayAttachment(), "ibm_is_subnet_routing_table_attachment": vpc.ResourceIBMISSubnetRoutingTableAttachment(), "ibm_is_ssh_key": vpc.ResourceIBMISSSHKey(), "ibm_is_snapshot": vpc.ResourceIBMSnapshot(), + "ibm_is_virtual_network_interface": vpc.ResourceIBMIsVirtualNetworkInterface(), + "ibm_is_virtual_network_interface_floating_ip": vpc.ResourceIBMIsVirtualNetworkInterfaceFloatingIP(), + "ibm_is_virtual_network_interface_ip": vpc.ResourceIBMIsVirtualNetworkInterfaceIP(), "ibm_is_snapshot_consistency_group": vpc.ResourceIBMIsSnapshotConsistencyGroup(), "ibm_is_volume": vpc.ResourceIBMISVolume(), "ibm_is_vpn_gateway": vpc.ResourceIBMISVPNGateway(), @@ -1174,7 +1196,6 @@ func Provider() *schema.Provider { "ibm_pi_capture": power.ResourceIBMPICapture(), "ibm_pi_image": power.ResourceIBMPIImage(), "ibm_pi_image_export": power.ResourceIBMPIImageExport(), - "ibm_pi_network_port": power.ResourceIBMPINetworkPort(), "ibm_pi_snapshot": power.ResourceIBMPISnapshot(), "ibm_pi_network_port_attach": power.ResourceIBMPINetworkPortAttach(), "ibm_pi_dhcp": power.ResourceIBMPIDhcp(), @@ -1355,6 +1376,10 @@ func Provider() *schema.Provider { "ibm_en_ibmsource": eventnotification.ResourceIBMEnIBMSource(), "ibm_en_destination_custom_email": eventnotification.ResourceIBMEnCustomEmailDestination(), "ibm_en_subscription_custom_email": eventnotification.ResourceIBMEnCustomEmailSubscription(), + "ibm_en_email_template": eventnotification.ResourceIBMEnEmailTemplate(), + "ibm_en_integration_cos": eventnotification.ResourceIBMEnCOSIntegration(), + "ibm_en_destination_custom_sms": eventnotification.ResourceIBMEnCustomSMSDestination(), + "ibm_en_subscription_custom_sms": eventnotification.ResourceIBMEnCustomSMSSubscription(), // Added for Toolchain "ibm_cd_toolchain": cdtoolchain.ResourceIBMCdToolchain(), @@ -1497,9 +1522,10 @@ func Validator() validate.ValidatorDict { "ibm_is_backup_policy_plan": vpc.ResourceIBMIsBackupPolicyPlanValidator(), // bare_metal_server - "ibm_is_bare_metal_server_disk": vpc.ResourceIBMIsBareMetalServerDiskValidator(), - "ibm_is_bare_metal_server_network_interface": vpc.ResourceIBMIsBareMetalServerNetworkInterfaceValidator(), - "ibm_is_bare_metal_server": vpc.ResourceIBMIsBareMetalServerValidator(), + "ibm_is_bare_metal_server_disk": vpc.ResourceIBMIsBareMetalServerDiskValidator(), + "ibm_is_bare_metal_server_network_attachment": vpc.ResourceIBMIsBareMetalServerNetworkAttachmentValidator(), + "ibm_is_bare_metal_server_network_interface": vpc.ResourceIBMIsBareMetalServerNetworkInterfaceValidator(), + "ibm_is_bare_metal_server": vpc.ResourceIBMIsBareMetalServerValidator(), "ibm_is_dedicated_host_group": vpc.ResourceIbmIsDedicatedHostGroupValidator(), "ibm_is_dedicated_host": vpc.ResourceIbmIsDedicatedHostValidator(), @@ -1517,6 +1543,7 @@ func Validator() validate.ValidatorDict { "ibm_is_instance_template": vpc.ResourceIBMISInstanceTemplateValidator(), "ibm_is_instance": vpc.ResourceIBMISInstanceValidator(), "ibm_is_instance_action": vpc.ResourceIBMISInstanceActionValidator(), + "ibm_is_instance_network_attachment": vpc.ResourceIBMIsInstanceNetworkAttachmentValidator(), "ibm_is_instance_network_interface": vpc.ResourceIBMIsInstanceNetworkInterfaceValidator(), "ibm_is_instance_disk_management": vpc.ResourceIBMISInstanceDiskManagementValidator(), "ibm_is_instance_volume_attachment": vpc.ResourceIBMISInstanceVolumeAttachmentValidator(), @@ -1543,6 +1570,7 @@ func Validator() validate.ValidatorDict { "ibm_is_subnet": vpc.ResourceIBMISSubnetValidator(), "ibm_is_subnet_reserved_ip": vpc.ResourceIBMISSubnetReservedIPValidator(), "ibm_is_volume": vpc.ResourceIBMISVolumeValidator(), + "ibm_is_virtual_network_interface": vpc.ResourceIBMIsVirtualNetworkInterfaceValidator(), "ibm_is_address_prefix": vpc.ResourceIBMISAddressPrefixValidator(), "ibm_is_vpc": vpc.ResourceIBMISVPCValidator(), "ibm_is_vpc_routing_table": vpc.ResourceIBMISVPCRoutingTableValidator(), @@ -1551,6 +1579,7 @@ func Validator() validate.ValidatorDict { "ibm_is_vpn_gateway": vpc.ResourceIBMISVPNGatewayValidator(), "ibm_is_vpn_server": vpc.ResourceIBMIsVPNServerValidator(), "ibm_is_vpn_server_route": vpc.ResourceIBMIsVPNServerRouteValidator(), + "ibm_is_reservation": vpc.ResourceIBMISReservationValidator(), "ibm_kms_key_rings": kms.ResourceIBMKeyRingValidator(), "ibm_dns_glb_monitor": dnsservices.ResourceIBMPrivateDNSGLBMonitorValidator(), "ibm_dns_custom_resolver_forwarding_rule": dnsservices.ResourceIBMPrivateDNSForwardingRuleValidator(), @@ -1687,8 +1716,6 @@ func Validator() validate.ValidatorDict { "ibm_is_vpc": vpc.DataSourceIBMISVpcValidator(), "ibm_is_volume": vpc.DataSourceIBMISVolumeValidator(), - "ibm_secrets_manager_secret": secretsmanager.DataSourceIBMSecretsManagerSecretValidator(), - "ibm_secrets_manager_secrets": secretsmanager.DataSourceIBMSecretsManagerSecretsValidator(), "ibm_cis_webhooks": cis.DataSourceIBMCISAlertWebhooksValidator(), "ibm_cis_alerts": cis.DataSourceIBMCISAlertsValidator(), "ibm_cis_bot_managements": cis.DataSourceIBMCISBotManagementValidator(), diff --git a/ibm/service/atracker/resource_ibm_atracker_settings_test.go b/ibm/service/atracker/resource_ibm_atracker_settings_test.go index 07d7ad0efe..29f9c5138e 100644 --- a/ibm/service/atracker/resource_ibm_atracker_settings_test.go +++ b/ibm/service/atracker/resource_ibm_atracker_settings_test.go @@ -17,9 +17,8 @@ import ( func TestAccIBMAtrackerSettingsBasic(t *testing.T) { var conf atrackerv2.Settings - metadataRegionPrimary := "us-east" + metadataRegionPrimary := "us-south" privateAPIEndpointOnly := "false" - metadataRegionPrimaryUpdate := "us-south" resource.Test(t, resource.TestCase{ PreCheck: func() { acc.TestAccPreCheck(t) }, @@ -36,15 +35,6 @@ func TestAccIBMAtrackerSettingsBasic(t *testing.T) { resource.TestCheckResourceAttr("ibm_atracker_settings.atracker_settings", "private_api_endpoint_only", privateAPIEndpointOnly), ), }, - resource.TestStep{ - Config: testAccCheckIBMAtrackerSettingsConfigBasic(metadataRegionPrimaryUpdate, - metadataRegionPrimary, privateAPIEndpointOnly), - Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("ibm_atracker_settings.atracker_settings", "metadata_region_primary", metadataRegionPrimaryUpdate), - resource.TestCheckResourceAttr("ibm_atracker_settings.atracker_settings", "metadata_region_backup", metadataRegionPrimary), - resource.TestCheckResourceAttr("ibm_atracker_settings.atracker_settings", "private_api_endpoint_only", privateAPIEndpointOnly), - ), - }, }, }) } diff --git a/ibm/service/catalogmanagement/data_source_ibm_cm_object.go b/ibm/service/catalogmanagement/data_source_ibm_cm_object.go index c2a11bd386..d46e887163 100644 --- a/ibm/service/catalogmanagement/data_source_ibm_cm_object.go +++ b/ibm/service/catalogmanagement/data_source_ibm_cm_object.go @@ -326,12 +326,6 @@ func dataSourceIBMCmObjectPublishObjectToMap(model *catalogmanagementv1.PublishO if model.PublicApproved != nil { modelMap["public_approved"] = *model.PublicApproved } - if model.PortalApprovalRecord != nil { - modelMap["portal_approval_record"] = *model.PortalApprovalRecord - } - if model.PortalURL != nil { - modelMap["portal_url"] = *model.PortalURL - } return modelMap, nil } diff --git a/ibm/service/catalogmanagement/resource_ibm_cm_object.go b/ibm/service/catalogmanagement/resource_ibm_cm_object.go index 2ab4f8ae86..86676b23c9 100644 --- a/ibm/service/catalogmanagement/resource_ibm_cm_object.go +++ b/ibm/service/catalogmanagement/resource_ibm_cm_object.go @@ -545,12 +545,6 @@ func resourceIBMCmObjectMapToPublishObject(modelMap map[string]interface{}) (*ca if modelMap["public_approved"] != nil { model.PublicApproved = core.BoolPtr(modelMap["public_approved"].(bool)) } - if modelMap["portal_approval_record"] != nil && modelMap["portal_approval_record"].(string) != "" { - model.PortalApprovalRecord = core.StringPtr(modelMap["portal_approval_record"].(string)) - } - if modelMap["portal_url"] != nil && modelMap["portal_url"].(string) != "" { - model.PortalURL = core.StringPtr(modelMap["portal_url"].(string)) - } return model, nil } @@ -585,12 +579,6 @@ func resourceIBMCmObjectPublishObjectToMap(model *catalogmanagementv1.PublishObj if model.PublicApproved != nil { modelMap["public_approved"] = model.PublicApproved } - if model.PortalApprovalRecord != nil { - modelMap["portal_approval_record"] = model.PortalApprovalRecord - } - if model.PortalURL != nil { - modelMap["portal_url"] = model.PortalURL - } return modelMap, nil } diff --git a/ibm/service/cis/resource_ibm_cis_domain_settings.go b/ibm/service/cis/resource_ibm_cis_domain_settings.go index 47bb6046a7..64ddb7047b 100644 --- a/ibm/service/cis/resource_ibm_cis_domain_settings.go +++ b/ibm/service/cis/resource_ibm_cis_domain_settings.go @@ -127,6 +127,7 @@ func ResourceIBMCISSettings() *schema.Resource { ValidateFunc: validate.InvokeValidator( ibmCISDomainSettings, cisDomainSettingsTLSVersionValidatorID), + Default: "1.2", }, cisDomainSettingsCNAMEFlattening: { Type: schema.TypeString, diff --git a/ibm/service/cis/resource_ibm_cis_tls_settings.go b/ibm/service/cis/resource_ibm_cis_tls_settings.go index 76fab72351..9aa5e38c55 100644 --- a/ibm/service/cis/resource_ibm_cis_tls_settings.go +++ b/ibm/service/cis/resource_ibm_cis_tls_settings.go @@ -56,6 +56,7 @@ func ResourceIBMCISTLSSettings() *schema.Resource { Description: "Minimum version of TLS required", Optional: true, ValidateFunc: validate.InvokeValidator(ibmCISTLSSettings, cisTLSSettingsMinTLSVersion), + Default: "1.2", }, }, Create: resourceCISTLSSettingsUpdate, diff --git a/ibm/service/contextbasedrestrictions/data_source_ibm_cbr_rule_test.go b/ibm/service/contextbasedrestrictions/data_source_ibm_cbr_rule_test.go index b2fa07dd41..f8c6982b37 100644 --- a/ibm/service/contextbasedrestrictions/data_source_ibm_cbr_rule_test.go +++ b/ibm/service/contextbasedrestrictions/data_source_ibm_cbr_rule_test.go @@ -13,6 +13,11 @@ import ( acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" ) +const ( + testAccountID = "12ab34cd56ef78ab90cd12ef34ab56cd" + testZoneID = "559052eb8f43302824e7ae490c0281eb" +) + func TestAccIBMCbrRuleDataSourceBasic(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { acc.TestAccPreCheck(t) }, @@ -77,13 +82,13 @@ func testAccCheckIBMCbrRuleDataSourceConfigBasic() string { contexts { attributes { name = "networkZoneId" - value = "559052eb8f43302824e7ae490c0281eb" + value = "%s" } } resources { attributes { name = "accountId" - value = "12ab34cd56ef78ab90cd12ef34ab56cd" + value = "%s" } attributes { name = "serviceName" @@ -94,7 +99,7 @@ func testAccCheckIBMCbrRuleDataSourceConfigBasic() string { data "ibm_cbr_rule" "cbr_rule" { rule_id = ibm_cbr_rule.cbr_rule.id } - `) + `, testZoneID, testAccountID) } func testAccCheckIBMCbrRuleDataSourceConfig(ruleDescription string, ruleEnforcementMode string) string { @@ -104,13 +109,13 @@ func testAccCheckIBMCbrRuleDataSourceConfig(ruleDescription string, ruleEnforcem contexts { attributes { name = "networkZoneId" - value = "559052eb8f43302824e7ae490c0281eb" + value = "%s" } } resources { attributes { name = "accountId" - value = "12ab34cd56ef78ab90cd12ef34ab56cd" + value = "%s" } attributes { name = "serviceName" @@ -133,5 +138,5 @@ func testAccCheckIBMCbrRuleDataSourceConfig(ruleDescription string, ruleEnforcem data "ibm_cbr_rule" "cbr_rule" { rule_id = ibm_cbr_rule.cbr_rule.id } - `, ruleDescription, ruleEnforcementMode) + `, ruleDescription, testZoneID, testAccountID, ruleEnforcementMode) } diff --git a/ibm/service/contextbasedrestrictions/data_source_ibm_cbr_zone_test.go b/ibm/service/contextbasedrestrictions/data_source_ibm_cbr_zone_test.go index 1a1e027648..22817af9fb 100644 --- a/ibm/service/contextbasedrestrictions/data_source_ibm_cbr_zone_test.go +++ b/ibm/service/contextbasedrestrictions/data_source_ibm_cbr_zone_test.go @@ -45,7 +45,7 @@ func TestAccIBMCbrZoneDataSourceBasic(t *testing.T) { func TestAccIBMCbrZoneDataSourceAllArgs(t *testing.T) { zoneName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) - zoneAccountID := "12ab34cd56ef78ab90cd12ef34ab56cd" + zoneAccountID := testAccountID zoneDescription := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ @@ -86,7 +86,7 @@ func testAccCheckIBMCbrZoneDataSourceConfigBasic() string { resource "ibm_cbr_zone" "cbr_zone" { name = "Test Zone Data Source Config Basic" description = "Test Zone Data Source Config Basic" - account_id = "12ab34cd56ef78ab90cd12ef34ab56cd" + account_id = "%s" addresses { type = "ipRange" value = "169.23.22.0-169.23.22.255" @@ -96,7 +96,7 @@ func testAccCheckIBMCbrZoneDataSourceConfigBasic() string { data "ibm_cbr_zone" "cbr_zone" { zone_id = ibm_cbr_zone.cbr_zone.id } - `) + `, testAccountID) } func testAccCheckIBMCbrZoneDataSourceConfig(zoneName string, zoneAccountID string, zoneDescription string) string { diff --git a/ibm/service/contextbasedrestrictions/resource_ibm_cbr_rule.go b/ibm/service/contextbasedrestrictions/resource_ibm_cbr_rule.go index dfcbd65ddb..18c7154623 100644 --- a/ibm/service/contextbasedrestrictions/resource_ibm_cbr_rule.go +++ b/ibm/service/contextbasedrestrictions/resource_ibm_cbr_rule.go @@ -35,7 +35,7 @@ func ResourceIBMCbrRule() *schema.Resource { }, "contexts": &schema.Schema{ Type: schema.TypeList, - Required: true, + Optional: true, Description: "The contexts this rule applies to.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -122,6 +122,7 @@ func ResourceIBMCbrRule() *schema.Resource { Type: schema.TypeList, MaxItems: 1, Optional: true, + Computed: true, Description: "The operations this rule applies to.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -144,7 +145,7 @@ func ResourceIBMCbrRule() *schema.Resource { "enforcement_mode": &schema.Schema{ Type: schema.TypeString, Optional: true, - Default: "enabled", + Computed: true, ValidateFunc: validate.InvokeValidator("ibm_cbr_rule", "enforcement_mode"), Description: "The rule enforcement mode: * `enabled` - The restrictions are enforced and reported. This is the default. * `disabled` - The restrictions are disabled. Nothing is enforced or reported. * `report` - The restrictions are evaluated and reported, but not enforced.", }, @@ -252,8 +253,8 @@ func resourceIBMCbrRuleCreate(context context.Context, d *schema.ResourceData, m if _, ok := d.GetOk("description"); ok { createRuleOptions.SetDescription(d.Get("description").(string)) } + contexts := []contextbasedrestrictionsv1.RuleContext{} if _, ok := d.GetOk("contexts"); ok { - var contexts []contextbasedrestrictionsv1.RuleContext for _, e := range d.Get("contexts").([]interface{}) { value := e.(map[string]interface{}) contextsItem, err := resourceIBMCbrRuleMapToRuleContext(value) @@ -262,8 +263,8 @@ func resourceIBMCbrRuleCreate(context context.Context, d *schema.ResourceData, m } contexts = append(contexts, *contextsItem) } - createRuleOptions.SetContexts(contexts) } + createRuleOptions.SetContexts(contexts) if _, ok := d.GetOk("resources"); ok { var resources []contextbasedrestrictionsv1.Resource for _, e := range d.Get("resources").([]interface{}) { @@ -408,8 +409,8 @@ func resourceIBMCbrRuleUpdate(context context.Context, d *schema.ResourceData, m if _, ok := d.GetOk("description"); ok { replaceRuleOptions.SetDescription(d.Get("description").(string)) } + contexts := []contextbasedrestrictionsv1.RuleContext{} if _, ok := d.GetOk("contexts"); ok { - var contexts []contextbasedrestrictionsv1.RuleContext for _, e := range d.Get("contexts").([]interface{}) { value := e.(map[string]interface{}) contextsItem, err := resourceIBMCbrRuleMapToRuleContext(value) @@ -418,8 +419,8 @@ func resourceIBMCbrRuleUpdate(context context.Context, d *schema.ResourceData, m } contexts = append(contexts, *contextsItem) } - replaceRuleOptions.SetContexts(contexts) } + replaceRuleOptions.SetContexts(contexts) if _, ok := d.GetOk("resources"); ok { var resources []contextbasedrestrictionsv1.Resource for _, e := range d.Get("resources").([]interface{}) { diff --git a/ibm/service/contextbasedrestrictions/resource_ibm_cbr_rule_test.go b/ibm/service/contextbasedrestrictions/resource_ibm_cbr_rule_test.go index 8434734ae3..a790388835 100644 --- a/ibm/service/contextbasedrestrictions/resource_ibm_cbr_rule_test.go +++ b/ibm/service/contextbasedrestrictions/resource_ibm_cbr_rule_test.go @@ -78,13 +78,13 @@ func testAccCheckIBMCbrRuleConfigBasic() string { contexts { attributes { name = "networkZoneId" - value = "559052eb8f43302824e7ae490c0281eb" + value = "%s" } } resources { attributes { name = "accountId" - value = "12ab34cd56ef78ab90cd12ef34ab56cd" + value = "%s" } attributes { name = "serviceName" @@ -97,7 +97,7 @@ func testAccCheckIBMCbrRuleConfigBasic() string { } enforcement_mode = "disabled" } - `) + `, testZoneID, testAccountID) } func testAccCheckIBMCbrRuleConfig(description string, enforcementMode string) string { @@ -108,13 +108,13 @@ func testAccCheckIBMCbrRuleConfig(description string, enforcementMode string) st contexts { attributes { name = "networkZoneId" - value = "559052eb8f43302824e7ae490c0281eb" + value = "%s" } } resources { attributes { name = "accountId" - value = "12ab34cd56ef78ab90cd12ef34ab56cd" + value = "%s" } attributes { name = "serviceName" @@ -133,7 +133,7 @@ func testAccCheckIBMCbrRuleConfig(description string, enforcementMode string) st } enforcement_mode = "%s" } - `, description, enforcementMode) + `, description, testZoneID, testAccountID, enforcementMode) } func testAccCheckIBMCbrRuleExists(n string, obj contextbasedrestrictionsv1.Rule) resource.TestCheckFunc { diff --git a/ibm/service/contextbasedrestrictions/resource_ibm_cbr_zone.go b/ibm/service/contextbasedrestrictions/resource_ibm_cbr_zone.go index d525000caa..f8be760a0a 100644 --- a/ibm/service/contextbasedrestrictions/resource_ibm_cbr_zone.go +++ b/ibm/service/contextbasedrestrictions/resource_ibm_cbr_zone.go @@ -47,7 +47,7 @@ func ResourceIBMCbrZone() *schema.Resource { }, "addresses": &schema.Schema{ Type: schema.TypeList, - Required: true, + Optional: true, Description: "The list of addresses in the zone.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -249,8 +249,8 @@ func resourceIBMCbrZoneCreate(context context.Context, d *schema.ResourceData, m if _, ok := d.GetOk("description"); ok { createZoneOptions.SetDescription(d.Get("description").(string)) } + addresses := []contextbasedrestrictionsv1.AddressIntf{} if _, ok := d.GetOk("addresses"); ok { - var addresses []contextbasedrestrictionsv1.AddressIntf for _, e := range d.Get("addresses").([]interface{}) { value := e.(map[string]interface{}) addressesItem, err := resourceIBMCbrZoneMapToAddress(value) @@ -259,8 +259,8 @@ func resourceIBMCbrZoneCreate(context context.Context, d *schema.ResourceData, m } addresses = append(addresses, addressesItem) } - createZoneOptions.SetAddresses(addresses) } + createZoneOptions.SetAddresses(addresses) if _, ok := d.GetOk("excluded"); ok { var excluded []contextbasedrestrictionsv1.AddressIntf for _, e := range d.Get("excluded").([]interface{}) { @@ -401,8 +401,8 @@ func resourceIBMCbrZoneUpdate(context context.Context, d *schema.ResourceData, m if _, ok := d.GetOk("description"); ok { replaceZoneOptions.SetDescription(d.Get("description").(string)) } + addresses := []contextbasedrestrictionsv1.AddressIntf{} if _, ok := d.GetOk("addresses"); ok { - var addresses []contextbasedrestrictionsv1.AddressIntf for _, e := range d.Get("addresses").([]interface{}) { value := e.(map[string]interface{}) addressesItem, err := resourceIBMCbrZoneMapToAddress(value) @@ -411,8 +411,8 @@ func resourceIBMCbrZoneUpdate(context context.Context, d *schema.ResourceData, m } addresses = append(addresses, addressesItem) } - replaceZoneOptions.SetAddresses(addresses) } + replaceZoneOptions.SetAddresses(addresses) if _, ok := d.GetOk("excluded"); ok { var excluded []contextbasedrestrictionsv1.AddressIntf for _, e := range d.Get("excluded").([]interface{}) { diff --git a/ibm/service/contextbasedrestrictions/resource_ibm_cbr_zone_test.go b/ibm/service/contextbasedrestrictions/resource_ibm_cbr_zone_test.go index 9910b07885..c627dd1a5c 100644 --- a/ibm/service/contextbasedrestrictions/resource_ibm_cbr_zone_test.go +++ b/ibm/service/contextbasedrestrictions/resource_ibm_cbr_zone_test.go @@ -37,10 +37,10 @@ func TestAccIBMCbrZoneBasic(t *testing.T) { func TestAccIBMCbrZoneAllArgs(t *testing.T) { var conf contextbasedrestrictionsv1.Zone name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) - accountID := fmt.Sprintf("12ab34cd56ef78ab90cd12ef34ab56cd") + accountID := testAccountID description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) nameUpdate := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) - accountIDUpdate := fmt.Sprintf("12ab34cd56ef78ab90cd12ef34ab56cd") + accountIDUpdate := testAccountID descriptionUpdate := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ @@ -79,13 +79,13 @@ func testAccCheckIBMCbrZoneConfigBasic() string { resource "ibm_cbr_zone" "cbr_zone" { name = "Test Zone Resource Config Basic" description = "Test Zone Resource Config Basic" - account_id = "12ab34cd56ef78ab90cd12ef34ab56cd" + account_id = "%s" addresses { type = "ipRange" value = "169.23.22.0-169.23.22.255" } } - `) + `, testAccountID) } func testAccCheckIBMCbrZoneConfig(name string, accountID string, description string) string { diff --git a/ibm/service/cos/resource_ibm_cos_bucket.go b/ibm/service/cos/resource_ibm_cos_bucket.go index abcc543635..fabf40bc9d 100644 --- a/ibm/service/cos/resource_ibm_cos_bucket.go +++ b/ibm/service/cos/resource_ibm_cos_bucket.go @@ -20,6 +20,7 @@ import ( token "github.com/IBM/ibm-cos-sdk-go/aws/credentials/ibmiam/token" "github.com/IBM/ibm-cos-sdk-go/aws/session" "github.com/IBM/ibm-cos-sdk-go/service/s3" + rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -1550,7 +1551,26 @@ func resourceIBMCOSBucketExists(d *schema.ResourceData, meta interface{}) (bool, if len(bucket_meta) < 2 || len(strings.Split(bucket_meta[1], ":")) < 2 { return false, fmt.Errorf("[ERROR] Error parsing bucket ID. Bucket ID format must be: $CRN:meta:$buckettype:$bucketlocation") } - + resourceInstanceId := strings.Split(d.Id(), ":bucket:")[0] + resourceInstanceIdInput := resourceInstanceId + "::" + resourceInstanceGet := rc.GetResourceInstanceOptions{ + ID: &resourceInstanceIdInput, + } + rsConClientV2, errConf := meta.(conns.ClientSession).ResourceControllerV2API() + if errConf != nil { + return false, errConf + } + instance, resp, err := rsConClientV2.GetResourceInstance(&resourceInstanceGet) + if err != nil { + if resp != nil && resp.StatusCode == 404 { + return false, nil + } + return false, fmt.Errorf("[WARN] Error getting resource instance from cos bucket: %s with resp code: %s", err, resp) + } + if instance != nil && (strings.Contains(*instance.State, "removed") || strings.Contains(*instance.State, "pending_reclamation")) { + log.Printf("[WARN] Removing instance from state because it's in removed or pending_reclamation state from the cos bucket resource") + return false, nil + } bucketName := parseBucketId(d.Id(), "bucketName") serviceID := parseBucketId(d.Id(), "serviceID") diff --git a/ibm/service/eventnotification/data_source_ibm_en_destination_apns.go b/ibm/service/eventnotification/data_source_ibm_en_destination_apns.go index 0aaa5734d5..3fa2c72fb8 100644 --- a/ibm/service/eventnotification/data_source_ibm_en_destination_apns.go +++ b/ibm/service/eventnotification/data_source_ibm_en_destination_apns.go @@ -45,6 +45,11 @@ func DataSourceIBMEnAPNSDestination() *schema.Resource { Computed: true, Description: "Destination type push_ios.", }, + "collect_failed_events": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether to collect the failed event in Cloud Object Storage bucket", + }, "certificate_content_type": { Type: schema.TypeString, Computed: true, @@ -161,6 +166,10 @@ func dataSourceIBMEnAPNSDestinationRead(context context.Context, d *schema.Resou return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) } + if err = d.Set("collect_failed_events", result.CollectFailedEvents); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting CollectFailedEvents: %s", err)) + } + if err = d.Set("certificate_content_type", result.Type); err != nil { return diag.FromErr(fmt.Errorf("[ERROR] Error setting certificate content type: %s", err)) } diff --git a/ibm/service/eventnotification/data_source_ibm_en_destination_ce.go b/ibm/service/eventnotification/data_source_ibm_en_destination_ce.go index 4c70872198..89c8beb1cd 100644 --- a/ibm/service/eventnotification/data_source_ibm_en_destination_ce.go +++ b/ibm/service/eventnotification/data_source_ibm_en_destination_ce.go @@ -45,6 +45,11 @@ func DataSourceIBMEnCodeEngineDestination() *schema.Resource { Computed: true, Description: "Destination type Webhook.", }, + "collect_failed_events": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether to collect the failed event in Cloud Object Storage bucket", + }, "config": { Type: schema.TypeList, Computed: true, @@ -142,6 +147,10 @@ func dataSourceIBMEnCodeEngineDestinationRead(context context.Context, d *schema return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) } + if err = d.Set("collect_failed_events", result.CollectFailedEvents); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting CollectFailedEvents: %s", err)) + } + if result.Config != nil { err = d.Set("config", enCodeEngineDestinationFlattenConfig(*result.Config)) if err != nil { @@ -205,6 +214,5 @@ func enCodeEngineDestinationConfigParamsToMap(paramsItem en.DestinationConfigOne if params.SensitiveHeaders != nil { paramsMap["sensitive_headers"] = params.SensitiveHeaders } - return paramsMap } diff --git a/ibm/service/eventnotification/data_source_ibm_en_destination_cf.go b/ibm/service/eventnotification/data_source_ibm_en_destination_cf.go index 5061fcc50e..a99caeeb46 100644 --- a/ibm/service/eventnotification/data_source_ibm_en_destination_cf.go +++ b/ibm/service/eventnotification/data_source_ibm_en_destination_cf.go @@ -45,6 +45,11 @@ func DataSourceIBMEnCFDestination() *schema.Resource { Computed: true, Description: "Destination type ibmcf.", }, + "collect_failed_events": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether to collect the failed event in Cloud Object Storage bucket", + }, "config": { Type: schema.TypeList, Computed: true, @@ -126,6 +131,10 @@ func dataSourceIBMEnCFDestinationRead(context context.Context, d *schema.Resourc return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) } + if err = d.Set("collect_failed_events", result.CollectFailedEvents); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting CollectFailedEvents: %s", err)) + } + if result.Config != nil { err = d.Set("config", enCFDestinationFlattenConfig(*result.Config)) if err != nil { @@ -184,5 +193,6 @@ func enCFDestinationConfigParamsToMap(paramsItem en.DestinationConfigOneOfIntf) if params.APIKey != nil { paramsMap["api_key"] = params.APIKey } + return paramsMap } diff --git a/ibm/service/eventnotification/data_source_ibm_en_destination_chrome.go b/ibm/service/eventnotification/data_source_ibm_en_destination_chrome.go index 3b2c01edaf..e0d0ecdbb3 100644 --- a/ibm/service/eventnotification/data_source_ibm_en_destination_chrome.go +++ b/ibm/service/eventnotification/data_source_ibm_en_destination_chrome.go @@ -45,6 +45,11 @@ func DataSourceIBMEnChromeDestination() *schema.Resource { Computed: true, Description: "Destination type push_chrome.", }, + "collect_failed_events": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether to collect the failed event in Cloud Object Storage bucket", + }, "config": { Type: schema.TypeList, Computed: true, @@ -132,6 +137,10 @@ func dataSourceIBMEnChromeDestinationRead(context context.Context, d *schema.Res return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) } + if err = d.Set("collect_failed_events", result.CollectFailedEvents); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting CollectFailedEvents: %s", err)) + } + if result.Config != nil { err = d.Set("config", enChromeDestinationFlattenConfig(*result.Config)) if err != nil { diff --git a/ibm/service/eventnotification/data_source_ibm_en_destination_cos.go b/ibm/service/eventnotification/data_source_ibm_en_destination_cos.go index 927bb7e089..2c682616ab 100644 --- a/ibm/service/eventnotification/data_source_ibm_en_destination_cos.go +++ b/ibm/service/eventnotification/data_source_ibm_en_destination_cos.go @@ -45,6 +45,11 @@ func DataSourceIBMEnCOSDestination() *schema.Resource { Computed: true, Description: "Destination type ibmcf.", }, + "collect_failed_events": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether to collect the failed event in Cloud Object Storage bucket", + }, "config": { Type: schema.TypeList, Computed: true, @@ -131,6 +136,10 @@ func dataSourceIBMEnCOSDestinationRead(context context.Context, d *schema.Resour return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) } + if err = d.Set("collect_failed_events", result.CollectFailedEvents); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting CollectFailedEvents: %s", err)) + } + if result.Config != nil { err = d.Set("config", enCOSDestinationFlattenConfig(*result.Config)) if err != nil { @@ -193,5 +202,6 @@ func enCOSDestinationConfigParamsToMap(paramsItem en.DestinationConfigOneOfIntf) if params.Endpoint != nil { paramsMap["endpoint"] = params.Endpoint } + return paramsMap } diff --git a/ibm/service/eventnotification/data_source_ibm_en_destination_custom_email.go b/ibm/service/eventnotification/data_source_ibm_en_destination_custom_email.go index c5480a1901..26da1ae7e0 100644 --- a/ibm/service/eventnotification/data_source_ibm_en_destination_custom_email.go +++ b/ibm/service/eventnotification/data_source_ibm_en_destination_custom_email.go @@ -45,6 +45,11 @@ func DataSourceIBMEnCustomEmailDestination() *schema.Resource { Computed: true, Description: "Destination type slack.", }, + "collect_failed_events": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether to collect the failed event in Cloud Object Storage bucket", + }, "config": { Type: schema.TypeList, Computed: true, @@ -121,6 +126,10 @@ func dataSourceIBMEnCustomEmailDestinationRead(context context.Context, d *schem return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) } + if err = d.Set("collect_failed_events", result.CollectFailedEvents); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting CollectFailedEvents: %s", err)) + } + if result.Config != nil { err = d.Set("config", enSlackDestinationFlattenConfig(*result.Config)) if err != nil { @@ -175,5 +184,6 @@ func enCustomEmailDestinationConfigParamsToMap(paramsItem en.DestinationConfigOn if params.URL != nil { paramsMap["domain"] = params.Domain } + return paramsMap } diff --git a/ibm/service/eventnotification/data_source_ibm_en_destination_custom_sms.go b/ibm/service/eventnotification/data_source_ibm_en_destination_custom_sms.go new file mode 100644 index 0000000000..ff4b57763f --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_destination_custom_sms.go @@ -0,0 +1,167 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func DataSourceIBMEnCustomSMSDestination() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMEnCustomSMSDestinationRead, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "destination_id": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for Destination.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Destination name.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Destination description.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Destination type slack.", + }, + "collect_failed_events": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether to collect the failed event in Cloud Object Storage bucket", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + "subscription_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Number of subscriptions.", + }, + "subscription_names": { + Type: schema.TypeList, + Computed: true, + Description: "List of subscriptions.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + } +} + +func dataSourceIBMEnCustomSMSDestinationRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.GetDestinationOptions{} + + options.SetInstanceID(d.Get("instance_guid").(string)) + options.SetID(d.Get("destination_id").(string)) + + result, response, err := enClient.GetDestinationWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("GetDestination failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *options.InstanceID, *options.ID)) + + if err = d.Set("name", result.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if result.Description != nil { + if err = d.Set("description", result.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + } + + if err = d.Set("type", result.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) + } + + if err = d.Set("collect_failed_events", result.CollectFailedEvents); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting CollectFailedEvents: %s", err)) + } + + if result.Config != nil { + err = d.Set("config", enSlackDestinationFlattenConfig(*result.Config)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting config %s", err)) + } + } + + if result.SubscriptionNames != nil { + err = d.Set("subscription_names", result.SubscriptionNames) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_names %s", err)) + } + } + + if err = d.Set("updated_at", flex.DateTimeToString(result.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + if err = d.Set("subscription_count", flex.IntValue(result.SubscriptionCount)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_count: %s", err)) + } + + return nil +} + +func enCustomSMSDestinationFlattenConfig(result en.DestinationConfig) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := enCustomEmailDestinationConfigToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func enCustomSMSDestinationConfigToMap(configItem en.DestinationConfig) (configMap map[string]interface{}) { + configMap = map[string]interface{}{} + + if configItem.Params != nil { + paramsList := []map[string]interface{}{} + paramsMap := enCustomSMSDestinationConfigParamsToMap(configItem.Params) + paramsList = append(paramsList, paramsMap) + configMap["params"] = paramsList + } + + return configMap +} + +func enCustomSMSDestinationConfigParamsToMap(paramsItem en.DestinationConfigOneOfIntf) (paramsMap map[string]interface{}) { + paramsMap = map[string]interface{}{} + + params := paramsItem.(*en.DestinationConfigOneOf) + + if params.URL != nil { + paramsMap["domain"] = params.Domain + } + + return paramsMap +} diff --git a/ibm/service/eventnotification/data_source_ibm_en_destination_custom_sms_test.go b/ibm/service/eventnotification/data_source_ibm_en_destination_custom_sms_test.go new file mode 100644 index 0000000000..981ad3ec0b --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_destination_custom_sms_test.go @@ -0,0 +1,62 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMEnCustomSMSDestinationDataSourceBasic(t *testing.T) { + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + instanceName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMEnCustomSMSDestinationDataSourceConfigBasic(instanceName, name, description), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_en_destination_custom_sms.en_destination_data_6", "id"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_custom_sms.en_destination_data_6", "instance_guid"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_custom_sms.en_destination_data_6", "name"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_custom_sms.en_destination_data_6", "description"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_custom_sms.en_destination_data_6", "type"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_custom_sms.en_destination_data_6", "updated_at"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_custom_sms.en_destination_data_6", "destination_id"), + resource.TestCheckResourceAttrSet("data.ibm_en_destination_custom_sms.en_destination_data_6", "subscription_count"), + ), + }, + }, + }) +} + +func testAccCheckIBMEnCustomSMSDestinationDataSourceConfigBasic(instanceName, name, description string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "en_destination_datasource2" { + name = "%s" + location = "us-south" + plan = "standard" + service = "event-notifications" + } + + resource "ibm_en_destination_custom_sms" "en_destination_datasource_4" { + instance_guid = ibm_resource_instance.en_destination_resource.guid + name = "%s" + type = "sms_custom" + description = "%s" + } + + data "ibm_en_destination_custom_sms" "en_destination_data_6" { + instance_guid = ibm_resource_instance.en_destination_datasource2.guid + destination_id = ibm_en_destination_custom_sms.en_destination_datasource_4.destination_id + } + `, instanceName, name, description) +} diff --git a/ibm/service/eventnotification/data_source_ibm_en_destination_fcm.go b/ibm/service/eventnotification/data_source_ibm_en_destination_fcm.go index c5edc21a93..87f60d1002 100644 --- a/ibm/service/eventnotification/data_source_ibm_en_destination_fcm.go +++ b/ibm/service/eventnotification/data_source_ibm_en_destination_fcm.go @@ -45,6 +45,11 @@ func DataSourceIBMEnFCMDestination() *schema.Resource { Computed: true, Description: "Destination type push_android.", }, + "collect_failed_events": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether to collect the failed event in Cloud Object Storage bucket", + }, "config": { Type: schema.TypeList, Computed: true, @@ -136,6 +141,10 @@ func dataSourceIBMEnFCMDestinationRead(context context.Context, d *schema.Resour return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) } + if err = d.Set("collect_failed_events", result.CollectFailedEvents); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting CollectFailedEvents: %s", err)) + } + if result.Config != nil { err = d.Set("config", enFCMDestinationFlattenConfig(*result.Config)) if err != nil { diff --git a/ibm/service/eventnotification/data_source_ibm_en_destination_firefox.go b/ibm/service/eventnotification/data_source_ibm_en_destination_firefox.go index a52a821f07..cc8359af77 100644 --- a/ibm/service/eventnotification/data_source_ibm_en_destination_firefox.go +++ b/ibm/service/eventnotification/data_source_ibm_en_destination_firefox.go @@ -45,6 +45,11 @@ func DataSourceIBMEnFirefoxDestination() *schema.Resource { Computed: true, Description: "Destination type push_firefox.", }, + "collect_failed_events": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether to collect the failed event in Cloud Object Storage bucket", + }, "config": { Type: schema.TypeList, Computed: true, @@ -126,6 +131,10 @@ func dataSourceIBMEnFirefoxDestinationRead(context context.Context, d *schema.Re return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) } + if err = d.Set("collect_failed_events", result.CollectFailedEvents); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting CollectFailedEvents: %s", err)) + } + if result.Config != nil { err = d.Set("config", enFirefoxDestinationFlattenConfig(*result.Config)) if err != nil { diff --git a/ibm/service/eventnotification/data_source_ibm_en_destination_huawei.go b/ibm/service/eventnotification/data_source_ibm_en_destination_huawei.go index 53c2219a83..a21a5d9839 100644 --- a/ibm/service/eventnotification/data_source_ibm_en_destination_huawei.go +++ b/ibm/service/eventnotification/data_source_ibm_en_destination_huawei.go @@ -45,6 +45,11 @@ func DataSourceIBMEnHuaweiDestination() *schema.Resource { Computed: true, Description: "Destination type push_android.", }, + "collect_failed_events": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether to collect the failed event in Cloud Object Storage bucket", + }, "config": { Type: schema.TypeList, Computed: true, @@ -131,6 +136,10 @@ func dataSourceIBMEnHuaweiDestinationRead(context context.Context, d *schema.Res return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) } + if err = d.Set("collect_failed_events", result.CollectFailedEvents); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting CollectFailedEvents: %s", err)) + } + if result.Config != nil { err = d.Set("config", enHuaweiDestinationFlattenConfig(*result.Config)) if err != nil { @@ -193,6 +202,5 @@ func enHuaweiDestinationConfigParamsToMap(paramsItem en.DestinationConfigOneOfIn if params.ClientSecret != nil { paramsMap["client_secret"] = params.ClientSecret } - return paramsMap } diff --git a/ibm/service/eventnotification/data_source_ibm_en_destination_msteams.go b/ibm/service/eventnotification/data_source_ibm_en_destination_msteams.go index ad2a8431cf..186c087541 100644 --- a/ibm/service/eventnotification/data_source_ibm_en_destination_msteams.go +++ b/ibm/service/eventnotification/data_source_ibm_en_destination_msteams.go @@ -45,6 +45,11 @@ func DataSourceIBMEnMSTeamsDestination() *schema.Resource { Computed: true, Description: "Destination type msteams.", }, + "collect_failed_events": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether to collect the failed event in Cloud Object Storage bucket", + }, "config": { Type: schema.TypeList, Computed: true, @@ -121,6 +126,10 @@ func dataSourceIBMEnMSTeamsDestinationRead(context context.Context, d *schema.Re return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) } + if err = d.Set("collect_failed_events", result.CollectFailedEvents); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting CollectFailedEvents: %s", err)) + } + if result.Config != nil { err = d.Set("config", enMSTeamsDestinationFlattenConfig(*result.Config)) if err != nil { diff --git a/ibm/service/eventnotification/data_source_ibm_en_destination_pagerduty.go b/ibm/service/eventnotification/data_source_ibm_en_destination_pagerduty.go index 3f5a7e2ca4..789908463d 100644 --- a/ibm/service/eventnotification/data_source_ibm_en_destination_pagerduty.go +++ b/ibm/service/eventnotification/data_source_ibm_en_destination_pagerduty.go @@ -45,6 +45,11 @@ func DataSourceIBMEnPagerDutyDestination() *schema.Resource { Computed: true, Description: "Destination type push_chrome.", }, + "collect_failed_events": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether to collect the failed event in Cloud Object Storage bucket", + }, "config": { Type: schema.TypeList, Computed: true, @@ -126,6 +131,10 @@ func dataSourceIBMEnPagerDutyeDestinationRead(context context.Context, d *schema return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) } + if err = d.Set("collect_failed_events", result.CollectFailedEvents); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting CollectFailedEvents: %s", err)) + } + if result.Config != nil { err = d.Set("config", enPagerDutyDestinationFlattenConfig(*result.Config)) if err != nil { diff --git a/ibm/service/eventnotification/data_source_ibm_en_destination_safari.go b/ibm/service/eventnotification/data_source_ibm_en_destination_safari.go index 28eb4e3409..a65b6fed58 100644 --- a/ibm/service/eventnotification/data_source_ibm_en_destination_safari.go +++ b/ibm/service/eventnotification/data_source_ibm_en_destination_safari.go @@ -45,6 +45,11 @@ func DataSourceIBMEnSafariDestination() *schema.Resource { Computed: true, Description: "Destination type push_ios.", }, + "collect_failed_events": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether to collect the failed event in Cloud Object Storage bucket", + }, "config": { Type: schema.TypeList, Computed: true, @@ -151,6 +156,10 @@ func dataSourceIBMEnSafariDestinationRead(context context.Context, d *schema.Res return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) } + if err = d.Set("collect_failed_events", result.CollectFailedEvents); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting CollectFailedEvents: %s", err)) + } + if result.Config != nil { err = d.Set("config", enSafariDestinationFlattenConfig(*result.Config)) if err != nil { diff --git a/ibm/service/eventnotification/data_source_ibm_en_destination_servicenow.go b/ibm/service/eventnotification/data_source_ibm_en_destination_servicenow.go index ff4cd80860..12ecc6dc47 100644 --- a/ibm/service/eventnotification/data_source_ibm_en_destination_servicenow.go +++ b/ibm/service/eventnotification/data_source_ibm_en_destination_servicenow.go @@ -45,6 +45,11 @@ func DataSourceIBMEnServiceNowDestination() *schema.Resource { Computed: true, Description: "Destination type push_chrome.", }, + "collect_failed_events": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether to collect the failed event in Cloud Object Storage bucket", + }, "config": { Type: schema.TypeList, Computed: true, @@ -141,6 +146,10 @@ func dataSourceIBMEnServiceNowDestinationRead(context context.Context, d *schema return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) } + if err = d.Set("collect_failed_events", result.CollectFailedEvents); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting CollectFailedEvents: %s", err)) + } + if result.Config != nil { err = d.Set("config", enServiceNowDestinationFlattenConfig(*result.Config)) if err != nil { diff --git a/ibm/service/eventnotification/data_source_ibm_en_destination_slack.go b/ibm/service/eventnotification/data_source_ibm_en_destination_slack.go index 67ff7acda0..faaedcc8b2 100644 --- a/ibm/service/eventnotification/data_source_ibm_en_destination_slack.go +++ b/ibm/service/eventnotification/data_source_ibm_en_destination_slack.go @@ -45,6 +45,11 @@ func DataSourceIBMEnSlackDestination() *schema.Resource { Computed: true, Description: "Destination type slack.", }, + "collect_failed_events": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether to collect the failed event in Cloud Object Storage bucket", + }, "config": { Type: schema.TypeList, Computed: true, @@ -121,6 +126,10 @@ func dataSourceIBMEnSlackDestinationRead(context context.Context, d *schema.Reso return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) } + if err = d.Set("collect_failed_events", result.CollectFailedEvents); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting CollectFailedEvents: %s", err)) + } + if result.Config != nil { err = d.Set("config", enSlackDestinationFlattenConfig(*result.Config)) if err != nil { diff --git a/ibm/service/eventnotification/data_source_ibm_en_destination_webhook.go b/ibm/service/eventnotification/data_source_ibm_en_destination_webhook.go index 2b327b15e4..4d45428710 100644 --- a/ibm/service/eventnotification/data_source_ibm_en_destination_webhook.go +++ b/ibm/service/eventnotification/data_source_ibm_en_destination_webhook.go @@ -45,6 +45,11 @@ func DataSourceIBMEnWebhookDestination() *schema.Resource { Computed: true, Description: "Destination type Webhook.", }, + "collect_failed_events": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether to collect the failed event in Cloud Object Storage bucket", + }, "config": { Type: schema.TypeList, Computed: true, @@ -142,6 +147,10 @@ func dataSourceIBMEnWebhookDestinationRead(context context.Context, d *schema.Re return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) } + // if err = d.Set("collect_failed_events", result.CollectFailedEvents); err != nil { + // return diag.FromErr(fmt.Errorf("[ERROR] Error setting CollectFailedEvents: %s", err)) + // } + if result.Config != nil { err = d.Set("config", enWebhookDestinationFlattenConfig(*result.Config)) if err != nil { diff --git a/ibm/service/eventnotification/data_source_ibm_en_email_template.go b/ibm/service/eventnotification/data_source_ibm_en_email_template.go new file mode 100644 index 0000000000..f0b24c2542 --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_email_template.go @@ -0,0 +1,117 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMEnEmailTemplate() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMEnEmailTemplateRead, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "template_id": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for Template.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Template name.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Templaten description.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Template type smtp_custom.notification/smtp_custom.invitation.", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + "subscription_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Number of subscriptions.", + }, + "subscription_names": { + Type: schema.TypeList, + Computed: true, + Description: "List of subscriptions.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + } +} + +func dataSourceIBMEnEmailTemplateRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.GetTemplateOptions{} + + options.SetInstanceID(d.Get("instance_guid").(string)) + options.SetID(d.Get("template_id").(string)) + + result, response, err := enClient.GetTemplateWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("GetTemplate failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *options.InstanceID, *options.ID)) + + if err = d.Set("name", result.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if result.Description != nil { + if err = d.Set("description", result.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + } + + if err = d.Set("type", result.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) + } + + if result.SubscriptionNames != nil { + err = d.Set("subscription_names", result.SubscriptionNames) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_names %s", err)) + } + } + + if err = d.Set("updated_at", flex.DateTimeToString(result.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + if err = d.Set("subscription_count", flex.IntValue(result.SubscriptionCount)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_count: %s", err)) + } + + return nil +} diff --git a/ibm/service/eventnotification/data_source_ibm_en_email_templates.go b/ibm/service/eventnotification/data_source_ibm_en_email_templates.go new file mode 100644 index 0000000000..a87c2d3314 --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_email_templates.go @@ -0,0 +1,180 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func DataSourceIBMEnTemplates() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMEnEmailTemplatesRead, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "search_key": { + Type: schema.TypeString, + Optional: true, + Description: "Filter the template by name or type.", + }, + "total_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Total number of templates.", + }, + "templates": { + Type: schema.TypeList, + Computed: true, + Description: "List of templates.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Template ID.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Template name.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "description of the template.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "template type smtp_custom.notification/smtp_custom.invitation.", + }, + "subscription_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Subscription count.", + }, + "subscription_names": { + Type: schema.TypeList, + Computed: true, + Description: "List of subscriptions.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Updated at.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMEnEmailTemplatesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.ListTemplatesOptions{} + + options.SetInstanceID(d.Get("instance_guid").(string)) + + if _, ok := d.GetOk("search_key"); ok { + options.SetSearch(d.Get("search_key").(string)) + } + var templateList *en.TemplateList + + finalList := []en.Template{} + + var offset int64 = 0 + var limit int64 = 100 + + options.SetLimit(limit) + + for { + options.SetOffset(offset) + + result, response, err := enClient.ListTemplatesWithContext(context, options) + + templateList = result + + if err != nil { + return diag.FromErr(fmt.Errorf("ListTemplatesWithContext failed %s\n%s", err, response)) + } + + offset = offset + limit + + finalList = append(finalList, result.Templates...) + + if offset > *result.TotalCount { + break + } + } + + templateList.Templates = finalList + + d.SetId(fmt.Sprintf("Templates/%s", *options.InstanceID)) + + if err = d.Set("total_count", flex.IntValue(templateList.TotalCount)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting total_count: %s", err)) + } + + if templateList.Templates != nil { + if err = d.Set("templates", enFlattentemplatesList(templateList.Templates)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting Templates %s", err)) + } + } + + return nil +} + +func enFlattentemplatesList(result []en.Template) (templates []map[string]interface{}) { + for _, templateItem := range result { + templates = append(templates, enTemplateListToMap(templateItem)) + } + + return templates +} + +func enTemplateListToMap(templateItem en.Template) (template map[string]interface{}) { + template = map[string]interface{}{} + + if templateItem.ID != nil { + template["id"] = templateItem.ID + } + if templateItem.Name != nil { + template["name"] = templateItem.Name + } + if templateItem.Description != nil { + template["description"] = templateItem.Description + } + if templateItem.Type != nil { + template["type"] = templateItem.Type + } + if templateItem.SubscriptionCount != nil { + template["subscription_count"] = templateItem.SubscriptionCount + } + if templateItem.SubscriptionNames != nil { + template["subscription_names"] = templateItem.SubscriptionNames + } + if templateItem.UpdatedAt != nil { + template["updated_at"] = flex.DateTimeToString(templateItem.UpdatedAt) + } + + return template +} diff --git a/ibm/service/eventnotification/data_source_ibm_en_email_templates_test.go b/ibm/service/eventnotification/data_source_ibm_en_email_templates_test.go new file mode 100644 index 0000000000..f26361d286 --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_email_templates_test.go @@ -0,0 +1,66 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMEnTemplatesDataSourceBasic(t *testing.T) { + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + instanceName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMEnTemplatesDatasourceConfig(instanceName, name, description), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_en_email_templates.data_email_template_1", "id"), + resource.TestCheckResourceAttrSet("data.ibm_en_email_templates.data_email_template_1", "instance_guid"), + resource.TestCheckResourceAttrSet("data.ibm_en_email_templates.data_email_template_1", "total_count"), + resource.TestCheckResourceAttrSet("data.ibm_en_email_templates.data_email_template_1", "templates.#"), + resource.TestCheckResourceAttrSet("data.ibm_en_email_templates.data_email_template_1", "templates.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_en_email_templates.data_email_template_1", "templates.0.updated_at"), + resource.TestCheckResourceAttrSet("data.ibm_en_email_templates.data_email_template_1", "templates.0.type"), + resource.TestCheckResourceAttrSet("data.ibm_en_email_templates.data_email_template_1", "templates.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_en_email_templates.data_email_template_1", "templates.0.description"), + ), + }, + }, + }) +} + +func testAccCheckIBMEnTemplatesDatasourceConfig(instanceName, name, description string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "en_template_datasource" { + name = "%s" + location = "us-south" + plan = "standard" + service = "event-notifications" + } + + resource "ibm_en_email_template" "en_template_datasource_1" { + instance_guid = ibm_resource_instance.en_template_datasource.guid + name = "%s" + type = "smtp_custom.notification" + description = "%s" + params { + body = "Go To-Do list

To-Do list for user: {{ Data.issuer.p }}

{{#each Email}}{{/each}}
TaskDone
{{ this }}
" + subject = "HI This is the template test for the invitation" + } + } + + data "ibm_en_destinations" "data_email_template_1" { + instance_guid = ibm_resource_instance.en_template_datasource_1.guid + } + `, instanceName, name, description) +} diff --git a/ibm/service/eventnotification/data_source_ibm_en_integration.go b/ibm/service/eventnotification/data_source_ibm_en_integration.go index 814d199a49..33d1256509 100644 --- a/ibm/service/eventnotification/data_source_ibm_en_integration.go +++ b/ibm/service/eventnotification/data_source_ibm_en_integration.go @@ -28,7 +28,35 @@ func DataSourceIBMEnIntegration() *schema.Resource { "integration_id": { Type: schema.TypeString, Required: true, - Description: "Unique identifier for Source.", + Description: "Unique identifier for Integration.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of key integration kms/hs-crypto.", + }, + "metadata": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "endpoint": { + Type: schema.TypeString, + Computed: true, + Description: "The public or private endpoint for kms/hpcs", + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN of the kms/hpcs instance", + }, + "root_key_id": { + Type: schema.TypeString, + Computed: true, + Description: "The value of root key id", + }, + }, + }, }, "updated_at": { Type: schema.TypeString, @@ -57,9 +85,34 @@ func dataSourceIBMEnIntegrationRead(context context.Context, d *schema.ResourceD d.SetId(fmt.Sprintf("%s/%s", *options.InstanceID, *options.ID)) + if err = d.Set("type", result.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) + } + + if result.Metadata != nil { + d.Set("metadata", enKMSIntegrationFlattenMetadata(result.Metadata)) + } + if err = d.Set("updated_at", flex.DateTimeToString(result.UpdatedAt)); err != nil { return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) } return nil } + +func enKMSIntegrationFlattenMetadata(metadataItem *en.IntegrationMetadata) []interface{} { + + metadataMap := make(map[string]interface{}) + if metadataItem.Endpoint != nil { + metadataMap["endpoint"] = metadataItem.Endpoint + } + + if metadataItem.CRN != nil { + metadataMap["crn"] = metadataItem.CRN + } + + if metadataItem.RootKeyID != nil { + metadataMap["root_key_id"] = metadataItem.RootKeyID + } + return []interface{}{metadataMap} +} diff --git a/ibm/service/eventnotification/data_source_ibm_en_integration_cos.go b/ibm/service/eventnotification/data_source_ibm_en_integration_cos.go new file mode 100644 index 0000000000..7bcbef5d9e --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_integration_cos.go @@ -0,0 +1,118 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func DataSourceIBMEnCOSIntegration() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMEnIntegrationRead, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "integration_id": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for Integration.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of integration is collect_failed_events.", + }, + "metadata": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "endpoint": { + Type: schema.TypeString, + Computed: true, + Description: "The public or private endpoint for COS bucket", + }, + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN of the Cloud Object Storage instance", + }, + "bucket_name": { + Type: schema.TypeString, + Computed: true, + Description: "Cloud Object Storage bucket name", + }, + }, + }, + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + }, + } +} + +func dataSourceIBMEnCOSIntegrationRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.GetIntegrationOptions{} + + options.SetInstanceID(d.Get("instance_guid").(string)) + options.SetID(d.Get("integration_id").(string)) + + result, response, err := enClient.GetIntegrationWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("GetIntegration failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *options.InstanceID, *options.ID)) + + if err = d.Set("type", result.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) + } + + if result.Metadata != nil { + d.Set("metadata", enCOSIntegrationFlattenMetadata(result.Metadata)) + } + + if err = d.Set("updated_at", flex.DateTimeToString(result.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + return nil +} + +func enCOSIntegrationFlattenMetadata(metadataItem *en.IntegrationMetadata) []interface{} { + + metadataMap := make(map[string]interface{}) + if metadataItem.Endpoint != nil { + metadataMap["endpoint"] = metadataItem.Endpoint + } + + if metadataItem.CRN != nil { + metadataMap["crn"] = metadataItem.CRN + } + + if metadataItem.BucketName != nil { + metadataMap["bucket_name"] = metadataItem.BucketName + } + return []interface{}{metadataMap} +} diff --git a/ibm/service/eventnotification/data_source_ibm_en_integration_cos_test.go b/ibm/service/eventnotification/data_source_ibm_en_integration_cos_test.go new file mode 100644 index 0000000000..759365cadc --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_integration_cos_test.go @@ -0,0 +1,60 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMEnIntegrationCOSDataSourceBasic(t *testing.T) { + instanceName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + // integrationid := fmt.Sprintf("tf_integrationid_%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMEnIntegrationCOSDataSourceConfigBasic(instanceName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_en_integration_cos.en_integration_data_1", "id"), + resource.TestCheckResourceAttrSet("data.ibm_en_integration_cos.en_integration_data_1", "instance_guid"), + // resource.TestCheckResourceAttrSet("data.ibm_en_integration_cos.en_integration_data_1", "integrationid"), + resource.TestCheckResourceAttrSet("data.ibm_en_integration_cos.en_integration_data_1", "updated_at"), + ), + }, + }, + }) +} + +func testAccCheckIBMEnIntegrationCOSDataSourceConfigBasic(instanceName string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "en_integration_datasource2" { + name = "%s" + location = "us-south" + plan = "standard" + service = "event-notifications" + } + + resource "ibm_en_integration_cos" "en_integration_resource_1" { + instance_guid = ibm_resource_instance.en_integration_datasource2.guid + type = "collect_failed_events" + metadata { + endpoint = "https://s3.us-west.cloud-object-storage.test.appdomain.cloud", + crn = "crn:v1:bluemix:public:cloud-object-storage:global:a/xxxxxxx6db359a81a1dde8f44bxxxxxx:xxxxxxxx-1d48-xxxx-xxxx-xxxxxxxxxxxx:bucket:cloud-object-storage" + bucket_name = "cloud-object-storage" + } + } + + data "ibm_en_integration_cos" "en_integration_data_1" { + instance_guid = ibm_resource_instance.en_integration_datasource2.guid + integration_id = ibm_en_integration.en_integration_resource_1.integration_id + } + `, instanceName) +} diff --git a/ibm/service/eventnotification/data_source_ibm_en_subscription_custom_sms.go b/ibm/service/eventnotification/data_source_ibm_en_subscription_custom_sms.go new file mode 100644 index 0000000000..92c4cd8b39 --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_subscription_custom_sms.go @@ -0,0 +1,215 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func DataSourceIBMEnCustomSMSSubscription() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMEnCustomSMSSubscriptionRead, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "subscription_id": { + Type: schema.TypeString, + Required: true, + Description: "Unique identifier for result.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Subscription name.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Subscription description.", + }, + "destination_id": { + Type: schema.TypeString, + Computed: true, + Description: "The destination ID.", + }, + "topic_id": { + Type: schema.TypeString, + Computed: true, + Description: "Topic ID.", + }, + "attributes": { + Type: schema.TypeList, + Computed: true, + Description: "The additional attributes", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "invited": { + Type: schema.TypeList, + Computed: true, + Description: "The phone number to send the SMS to.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "phone_number": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The email address to reply to.", + }, + "updated_at": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The email address user name to reply to.", + }, + "expires_at": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The email address user name to reply to.", + }, + }, + }, + }, + "subscribed": { + Type: schema.TypeList, + Computed: true, + Description: "The phone number to send the SMS to.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "phone_number": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The email address to reply to.", + }, + "updated_at": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The email address user name to reply to.", + }, + }, + }, + }, + "unsubscribed": { + Type: schema.TypeList, + Computed: true, + Description: "The phone number to send the SMS to.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "phone_number": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The email address to reply to.", + }, + "updated_at": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The email address user name to reply to.", + }, + }, + }, + }, + }, + }, + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + }, + } +} + +func dataSourceIBMEnCustomSMSSubscriptionRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + getSubscriptionOptions := &en.GetSubscriptionOptions{} + + getSubscriptionOptions.SetInstanceID(d.Get("instance_guid").(string)) + getSubscriptionOptions.SetID(d.Get("subscription_id").(string)) + + result, response, err := enClient.GetSubscriptionWithContext(context, getSubscriptionOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("GetSubscriptionWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *getSubscriptionOptions.InstanceID, *getSubscriptionOptions.ID)) + + if err = d.Set("name", result.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if result.Description != nil { + if err = d.Set("description", result.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + } + if err = d.Set("updated_at", result.UpdatedAt); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + if err = d.Set("destination_id", result.DestinationID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_id: %s", err)) + } + + if err = d.Set("topic_id", result.TopicID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting topic_id: %s", err)) + } + + if result.Attributes != nil { + if err = d.Set("attributes", enSMSSubscriptionFlattenAttributes(result.Attributes)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting attributes %s", err)) + } + } + + return nil +} + +func enCustomSMSSubscriptionFlattenAttributes(result en.SubscriptionAttributesIntf) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + + attributes := result.(*en.SubscriptionAttributes) + + finalMap := enSMSSubscriptionToMap(attributes) + finalList = append(finalList, finalMap) + + return finalList +} + +func enCustomSMSSubscriptionToMap(attributeItem *en.SubscriptionAttributes) (attributeMap map[string]interface{}) { + attributeMap = map[string]interface{}{} + + invitedmap := make(map[string]interface{}) + if attributeItem.Invited != nil { + invitedmap["invited"] = attributeItem.Invited + } + subscribedmap := make(map[string]interface{}) + if attributeItem.Subscribed != nil { + subscribedmap["subscribed"] = attributeItem.Subscribed + } + unsubscribedmap := make(map[string]interface{}) + if attributeItem.Unsubscribed != nil { + unsubscribedmap["unsubscribed"] = attributeItem.Unsubscribed + } + + return attributeMap +} diff --git a/ibm/service/eventnotification/data_source_ibm_en_subscription_custom_sms_test.go b/ibm/service/eventnotification/data_source_ibm_en_subscription_custom_sms_test.go new file mode 100644 index 0000000000..d7560c34ae --- /dev/null +++ b/ibm/service/eventnotification/data_source_ibm_en_subscription_custom_sms_test.go @@ -0,0 +1,78 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMEnCustomSMSSubscriptionDataSourceAllArgs(t *testing.T) { + instanceName := fmt.Sprintf("tf_instance_%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMEnCustomSMSSubscriptionDataSourceConfig(instanceName, name, description), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_custom_sms.data_subscription_1", "id"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_custom_sms.data_subscription_1", "instance_guid"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_custom_sms.data_subscription_1", "subscription_id"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_custom_sms.data_subscription_1", "name"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_custom_sms.data_subscription_1", "description"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_custom_sms.data_subscription_1", "updated_at"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_custom_sms.data_subscription_1", "destination_type"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_custom_sms.data_subscription_1", "destination_id"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_custom_sms.data_subscription_1", "destination_name"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_custom_sms.data_subscription_1", "topic_id"), + resource.TestCheckResourceAttrSet("data.ibm_en_subscription_custom_sms.data_subscription_1", "topic_name"), + ), + }, + }, + }) +} + +func testAccCheckIBMEnCustomSMSSubscriptionDataSourceConfig(instanceName, name, description string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "en_subscription_datasource" { + name = "%s" + location = "us-south" + plan = "standard" + service = "event-notifications" + } + + resource "ibm_en_topic" "en_topic_resource_4" { + instance_guid = ibm_resource_instance.en_subscription_datasource.guid + name = "tf_topic_name_0664" + description = "tf_topic_description_0455" + } + + + resource "ibm_en_subscription_custom_sms" "en_subscription_resource_4" { + name = "%s" + description = "%s" + instance_guid = ibm_resource_instance.en_subscription_datasource.guid + topic_id = ibm_en_topic.en_topic_resource_4.topic_id + destination_id = "ibm_resource_instance.ibm_en_destination_custom_sms.destination_id" + attributes { + invited = ["+16382922821", "+18976569023"] + } + } + + data "ibm_en_subscription_custom_sms" "data_subscription_1" { + instance_guid = ibm_resource_instance.en_subscription_datasource.guid + subscription_id = ibm_en_subscription_custom_sms.en_subscription_resource_4.subscription_id + } + + `, instanceName, name, description) +} diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_apns.go b/ibm/service/eventnotification/resource_ibm_en_destination_apns.go index 04c8828b75..64eeb61788 100644 --- a/ibm/service/eventnotification/resource_ibm_en_destination_apns.go +++ b/ibm/service/eventnotification/resource_ibm_en_destination_apns.go @@ -48,6 +48,11 @@ func ResourceIBMEnAPNSDestination() *schema.Resource { Optional: true, Description: "The Destination description.", }, + "collect_failed_events": { + Type: schema.TypeBool, + Optional: true, + Description: "Whether to collect the failed event in Cloud Object Storage bucket", + }, "certificate_content_type": { Type: schema.TypeString, Required: true, @@ -151,6 +156,8 @@ func resourceIBMEnAPNSDestinationCreate(context context.Context, d *schema.Resou options.SetType(d.Get("type").(string)) + options.SetCollectFailedEvents(d.Get("collect_failed_events").(bool)) + options.SetCertificateContentType(d.Get("certificate_content_type").(string)) certificatetype := d.Get("certificate_content_type").(string) @@ -231,6 +238,10 @@ func resourceIBMEnAPNSDestinationRead(context context.Context, d *schema.Resourc return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) } + if err = d.Set("collect_failed_events", result.CollectFailedEvents); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting CollectFailedEvents: %s", err)) + } + if err = d.Set("description", result.Description); err != nil { return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) } @@ -273,13 +284,17 @@ func resourceIBMEnAPNSDestinationUpdate(context context.Context, d *schema.Resou options.SetInstanceID(parts[0]) options.SetID(parts[1]) - if ok := d.HasChanges("name", "description", "certificate", "config"); ok { + if ok := d.HasChanges("name", "description", "collect_failed_events", "certificate", "config"); ok { options.SetName(d.Get("name").(string)) if _, ok := d.GetOk("description"); ok { options.SetDescription(d.Get("description").(string)) } + if _, ok := d.GetOk("collect_failed_events"); ok { + options.SetCollectFailedEvents(d.Get("collect_failed_events").(bool)) + } + certificatetype := d.Get("certificate_content_type").(string) if c, ok := d.GetOk("certificate"); ok { diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_apns_test.go b/ibm/service/eventnotification/resource_ibm_en_destination_apns_test.go index 47acc33aac..1a21cf3455 100644 --- a/ibm/service/eventnotification/resource_ibm_en_destination_apns_test.go +++ b/ibm/service/eventnotification/resource_ibm_en_destination_apns_test.go @@ -37,6 +37,7 @@ func TestAccIBMEnAPNSDestinationAllArgs(t *testing.T) { testAccCheckIBMEnAPNSDestinationExists("ibm_en_apns_destination.en_destination_resource_apns", config), resource.TestCheckResourceAttr("ibm_en_destination_ios.en_destination_resource_apns", "name", name), resource.TestCheckResourceAttr("ibm_en_destination_ios.en_destination_resource_apns", "type", "push_ios"), + resource.TestCheckResourceAttr("ibm_en_destination_ios.en_destination_resource_apns", "collect_failed_events", "false"), resource.TestCheckResourceAttr("ibm_en_destination_ios.en_destination_resource_apns", "description", description), ), }, @@ -45,6 +46,7 @@ func TestAccIBMEnAPNSDestinationAllArgs(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_en_destination_ios.en_destination_resource_apns", "name", newName), resource.TestCheckResourceAttr("ibm_en_destination_ios.en_destination_resource_apns", "type", "push_ios"), + resource.TestCheckResourceAttr("ibm_en_destination_ios.en_destination_resource_apns", "collect_failed_events", "false"), resource.TestCheckResourceAttr("ibm_en_destination_ios.en_destination_resource_apns", "description", newDescription), ), }, @@ -70,6 +72,7 @@ func testAccCheckIBMEnAPNSDestinationConfig(instanceName, name, description stri instance_guid = ibm_resource_instance.en_destination_resource.guid name = "%s" type = "push_ios" + collect_failed_events = false certificate_content_type = "p12" certificate = "${path.module}/cert.p12" description = "%s" diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_ce.go b/ibm/service/eventnotification/resource_ibm_en_destination_ce.go index f17b773758..478b281974 100644 --- a/ibm/service/eventnotification/resource_ibm_en_destination_ce.go +++ b/ibm/service/eventnotification/resource_ibm_en_destination_ce.go @@ -46,6 +46,11 @@ func ResourceIBMEnCodeEngineDestination() *schema.Resource { Optional: true, Description: "The Destination description.", }, + "collect_failed_events": { + Type: schema.TypeBool, + Optional: true, + Description: "Whether to collect the failed event in Cloud Object Storage bucket", + }, "config": { Type: schema.TypeList, MaxItems: 1, @@ -123,6 +128,7 @@ func resourceIBMEnCodeEngineDestinationCreate(context context.Context, d *schema options.SetInstanceID(d.Get("instance_guid").(string)) options.SetName(d.Get("name").(string)) options.SetType(d.Get("type").(string)) + options.SetCollectFailedEvents(d.Get("collect_failed_events").(bool)) destinationtype := d.Get("type").(string) if _, ok := d.GetOk("description"); ok { @@ -184,6 +190,10 @@ func resourceIBMEnCodeEngineDestinationRead(context context.Context, d *schema.R return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) } + if err = d.Set("collect_failed_events", result.CollectFailedEvents); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting CollectFailedEvents: %s", err)) + } + if err = d.Set("description", result.Description); err != nil { return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) } @@ -227,12 +237,17 @@ func resourceIBMEnCodeEngineDestinationUpdate(context context.Context, d *schema options.SetInstanceID(parts[0]) options.SetID(parts[1]) - if ok := d.HasChanges("name", "description", "config"); ok { + if ok := d.HasChanges("name", "description", "collect_failed_events", "config"); ok { options.SetName(d.Get("name").(string)) if _, ok := d.GetOk("description"); ok { options.SetDescription(d.Get("description").(string)) } + + if _, ok := d.GetOk("collect_failed_events"); ok { + options.SetCollectFailedEvents(d.Get("collect_failed_events").(bool)) + } + destinationtype := d.Get("type").(string) if _, ok := d.GetOk("config"); ok { config := CodeEnginedestinationConfigMapToDestinationConfig(d.Get("config.0.params.0").(map[string]interface{}), destinationtype) @@ -289,6 +304,10 @@ func CodeEnginedestinationConfigMapToDestinationConfig(configParams map[string]i params.Verb = core.StringPtr(configParams["verb"].(string)) } + // if configParams["collect_failed_events"] != nil { + // params.CollectFailedEvents = core.BoolPtr(configParams["collect_failed_events"].(bool)) + // } + if configParams["custom_headers"] != nil { var customHeaders = make(map[string]string) for k, v := range configParams["custom_headers"].(map[string]interface{}) { diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_ce_test.go b/ibm/service/eventnotification/resource_ibm_en_destination_ce_test.go index c707a2d7b8..df0780b2a3 100644 --- a/ibm/service/eventnotification/resource_ibm_en_destination_ce_test.go +++ b/ibm/service/eventnotification/resource_ibm_en_destination_ce_test.go @@ -37,6 +37,7 @@ func TestAccIBMEnCodeEngineAllArgs(t *testing.T) { testAccCheckIBMEnCodeEngineDestinationExists("ibm_en_destination_ce.en_destination_resource_1", config), resource.TestCheckResourceAttr("ibm_en_destination_ce.en_destination_resource_1", "name", name), resource.TestCheckResourceAttr("ibm_en_destination_ce.en_destination_resource_1", "type", "ibmce"), + resource.TestCheckResourceAttr("ibm_en_destination_ce.en_destination_resource_1", "collect_failed_events", "false"), resource.TestCheckResourceAttr("ibm_en_destination_ce.en_destination_resource_1", "description", description), ), }, @@ -45,6 +46,7 @@ func TestAccIBMEnCodeEngineAllArgs(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_en_destination_ce.en_destination_resource_1", "name", newName), resource.TestCheckResourceAttr("ibm_en_destination_ce.en_destination_resource_1", "type", "ibmce"), + resource.TestCheckResourceAttr("ibm_en_destination_ce.en_destination_resource_1", "collect_failed_events", "false"), resource.TestCheckResourceAttr("ibm_en_destination_ce.en_destination_resource_1", "description", newDescription), ), }, diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_cf.go b/ibm/service/eventnotification/resource_ibm_en_destination_cf.go index 8033bc2914..bf674f84b1 100644 --- a/ibm/service/eventnotification/resource_ibm_en_destination_cf.go +++ b/ibm/service/eventnotification/resource_ibm_en_destination_cf.go @@ -46,6 +46,11 @@ func ResourceIBMEnCFDestination() *schema.Resource { Optional: true, Description: "The Destination description.", }, + "collect_failed_events": { + Type: schema.TypeBool, + Optional: true, + Description: "Whether to collect the failed event in Cloud Object Storage bucket", + }, "config": { Type: schema.TypeList, MaxItems: 1, @@ -111,6 +116,7 @@ func resourceIBMEnCFDestinationCreate(context context.Context, d *schema.Resourc options.SetInstanceID(d.Get("instance_guid").(string)) options.SetName(d.Get("name").(string)) options.SetType(d.Get("type").(string)) + options.SetCollectFailedEvents(d.Get("collect_failed_events").(bool)) destinationtype := d.Get("type").(string) if _, ok := d.GetOk("description"); ok { @@ -172,6 +178,10 @@ func resourceIBMEnCFDestinationRead(context context.Context, d *schema.ResourceD return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) } + if err = d.Set("collect_failed_events", result.CollectFailedEvents); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting CollectFailedEvents: %s", err)) + } + if err = d.Set("description", result.Description); err != nil { return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) } @@ -215,12 +225,16 @@ func resourceIBMEnCFDestinationUpdate(context context.Context, d *schema.Resourc options.SetInstanceID(parts[0]) options.SetID(parts[1]) - if ok := d.HasChanges("name", "description", "config"); ok { + if ok := d.HasChanges("name", "description", "collect_failed_events", "config"); ok { options.SetName(d.Get("name").(string)) if _, ok := d.GetOk("description"); ok { options.SetDescription(d.Get("description").(string)) } + + if _, ok := d.GetOk("collect_failed_events"); ok { + options.SetCollectFailedEvents(d.Get("collect_failed_events").(bool)) + } destinationtype := d.Get("type").(string) if _, ok := d.GetOk("config"); ok { config := CFdestinationConfigMapToDestinationConfig(d.Get("config.0.params.0").(map[string]interface{}), destinationtype) diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_cf_test.go b/ibm/service/eventnotification/resource_ibm_en_destination_cf_test.go index c770490987..dcd98d3d8a 100644 --- a/ibm/service/eventnotification/resource_ibm_en_destination_cf_test.go +++ b/ibm/service/eventnotification/resource_ibm_en_destination_cf_test.go @@ -37,6 +37,7 @@ func TestAccIBMEnCFDestinationAllArgs(t *testing.T) { testAccCheckIBMEnCFDestinationExists("ibm_en_destination_cf.en_destination_resource_1", config), resource.TestCheckResourceAttr("ibm_en_destination_cf.en_destination_resource_1", "name", name), resource.TestCheckResourceAttr("ibm_en_destination_cf.en_destination_resource_1", "type", "ibmcf"), + resource.TestCheckResourceAttr("ibm_en_destination_cf.en_destination_resource_1", "collect_failed_events", "false"), resource.TestCheckResourceAttr("ibm_en_destination_cf.en_destination_resource_1", "description", description), ), }, @@ -45,6 +46,7 @@ func TestAccIBMEnCFDestinationAllArgs(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_en_destination_cf.en_destination_resource_1", "name", newName), resource.TestCheckResourceAttr("ibm_en_destination_cf.en_destination_resource_1", "type", "ibmcf"), + resource.TestCheckResourceAttr("ibm_en_destination_cf.en_destination_resource_1", "collect_failed_events", "false"), resource.TestCheckResourceAttr("ibm_en_destination_cf.en_destination_resource_1", "description", newDescription), ), }, diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_chrome.go b/ibm/service/eventnotification/resource_ibm_en_destination_chrome.go index b88e182bd0..745d7e2022 100644 --- a/ibm/service/eventnotification/resource_ibm_en_destination_chrome.go +++ b/ibm/service/eventnotification/resource_ibm_en_destination_chrome.go @@ -46,6 +46,11 @@ func ResourceIBMEnChromeDestination() *schema.Resource { Optional: true, Description: "The Destination description.", }, + "collect_failed_events": { + Type: schema.TypeBool, + Optional: true, + Description: "Whether to collect the failed event in Cloud Object Storage bucket", + }, "config": { Type: schema.TypeList, MaxItems: 1, @@ -119,6 +124,8 @@ func resourceIBMEnChromeDestinationCreate(context context.Context, d *schema.Res options.SetType(d.Get("type").(string)) + options.SetCollectFailedEvents(d.Get("collect_failed_events").(bool)) + if _, ok := d.GetOk("description"); ok { options.SetDescription(d.Get("description").(string)) } @@ -178,6 +185,10 @@ func resourceIBMEnChromeDestinationRead(context context.Context, d *schema.Resou return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) } + if err = d.Set("collect_failed_events", result.CollectFailedEvents); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting CollectFailedEvents: %s", err)) + } + if err = d.Set("description", result.Description); err != nil { return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) } @@ -220,13 +231,17 @@ func resourceIBMEnChromeDestinationUpdate(context context.Context, d *schema.Res options.SetInstanceID(parts[0]) options.SetID(parts[1]) - if ok := d.HasChanges("name", "description", "config"); ok { + if ok := d.HasChanges("name", "description", "collect_failed_events", "config"); ok { options.SetName(d.Get("name").(string)) if _, ok := d.GetOk("description"); ok { options.SetDescription(d.Get("description").(string)) } + if _, ok := d.GetOk("collect_failed_events"); ok { + options.SetCollectFailedEvents(d.Get("collect_failed_events").(bool)) + } + if _, ok := d.GetOk("config"); ok { config := ChromedestinationConfigMapToDestinationConfig(d.Get("config.0.params.0").(map[string]interface{})) options.SetConfig(&config) diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_chrome_test.go b/ibm/service/eventnotification/resource_ibm_en_destination_chrome_test.go index 5deec8283c..c0f2d18cb1 100644 --- a/ibm/service/eventnotification/resource_ibm_en_destination_chrome_test.go +++ b/ibm/service/eventnotification/resource_ibm_en_destination_chrome_test.go @@ -37,6 +37,7 @@ func TestAccIBMEnChromeDestinationAllArgs(t *testing.T) { testAccCheckIBMEnChromeDestinationExists("ibm_en_destination_chrome.en_destination_resource_1", config), resource.TestCheckResourceAttr("ibm_en_destination_chrome.en_destination_resource_1", "name", name), resource.TestCheckResourceAttr("ibm_en_destination_chrome.en_destination_resource_1", "type", "push_chrome"), + resource.TestCheckResourceAttr("ibm_en_destination_chrome.en_destination_resource_1", "collect_failed_events", "false"), resource.TestCheckResourceAttr("ibm_en_destination_chrome.en_destination_resource_1", "description", description), ), }, @@ -45,6 +46,7 @@ func TestAccIBMEnChromeDestinationAllArgs(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_en_destination_chrome.en_destination_resource_1", "name", newName), resource.TestCheckResourceAttr("ibm_en_destination_chrome.en_destination_resource_1", "type", "push_chrome"), + resource.TestCheckResourceAttr("ibm_en_destination_chrome.en_destination_resource_1", "collect_failed_events", "false"), resource.TestCheckResourceAttr("ibm_en_destination_chrome.en_destination_resource_1", "description", newDescription), ), }, diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_cos.go b/ibm/service/eventnotification/resource_ibm_en_destination_cos.go index 1551798664..f1aeb1d909 100644 --- a/ibm/service/eventnotification/resource_ibm_en_destination_cos.go +++ b/ibm/service/eventnotification/resource_ibm_en_destination_cos.go @@ -46,6 +46,11 @@ func ResourceIBMEnCOSDestination() *schema.Resource { Optional: true, Description: "The Destination description.", }, + "collect_failed_events": { + Type: schema.TypeBool, + Optional: true, + Description: "Whether to collect the failed event in Cloud Object Storage bucket", + }, "config": { Type: schema.TypeList, MaxItems: 1, @@ -116,6 +121,7 @@ func resourceIBMEnCOSDestinationCreate(context context.Context, d *schema.Resour options.SetInstanceID(d.Get("instance_guid").(string)) options.SetName(d.Get("name").(string)) options.SetType(d.Get("type").(string)) + options.SetCollectFailedEvents(d.Get("collect_failed_events").(bool)) destinationtype := d.Get("type").(string) if _, ok := d.GetOk("description"); ok { @@ -177,6 +183,10 @@ func resourceIBMEnCOSDestinationRead(context context.Context, d *schema.Resource return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) } + if err = d.Set("collect_failed_events", result.CollectFailedEvents); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting CollectFailedEvents: %s", err)) + } + if err = d.Set("description", result.Description); err != nil { return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) } @@ -220,12 +230,16 @@ func resourceIBMEnCOSDestinationUpdate(context context.Context, d *schema.Resour options.SetInstanceID(parts[0]) options.SetID(parts[1]) - if ok := d.HasChanges("name", "description", "config"); ok { + if ok := d.HasChanges("name", "description", "collect_failed_events", "config"); ok { options.SetName(d.Get("name").(string)) if _, ok := d.GetOk("description"); ok { options.SetDescription(d.Get("description").(string)) } + + if _, ok := d.GetOk("collect_failed_events"); ok { + options.SetCollectFailedEvents(d.Get("collect_failed_events").(bool)) + } destinationtype := d.Get("type").(string) if _, ok := d.GetOk("config"); ok { config := COSdestinationConfigMapToDestinationConfig(d.Get("config.0.params.0").(map[string]interface{}), destinationtype) diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_cos_test.go b/ibm/service/eventnotification/resource_ibm_en_destination_cos_test.go index 17295683f6..327a38f7ba 100644 --- a/ibm/service/eventnotification/resource_ibm_en_destination_cos_test.go +++ b/ibm/service/eventnotification/resource_ibm_en_destination_cos_test.go @@ -37,6 +37,7 @@ func TestAccIBMEnCOSDestinationAllArgs(t *testing.T) { testAccCheckIBMEnCOSDestinationExists("ibm_en_destination_cos.en_destination_resource_1", config), resource.TestCheckResourceAttr("ibm_en_destination_cos.en_destination_resource_1", "name", name), resource.TestCheckResourceAttr("ibm_en_destination_cos.en_destination_resource_1", "type", "ibmcos"), + resource.TestCheckResourceAttr("ibm_en_destination_cos.en_destination_resource_1", "collect_failed_events", "false"), resource.TestCheckResourceAttr("ibm_en_destination_cos.en_destination_resource_1", "description", description), ), }, @@ -45,6 +46,7 @@ func TestAccIBMEnCOSDestinationAllArgs(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_en_destination_cos.en_destination_resource_1", "name", newName), resource.TestCheckResourceAttr("ibm_en_destination_cos.en_destination_resource_1", "type", "ibmcos"), + resource.TestCheckResourceAttr("ibm_en_destination_cos.en_destination_resource_1", "collect_failed_events", "false"), resource.TestCheckResourceAttr("ibm_en_destination_cos.en_destination_resource_1", "description", newDescription), ), }, diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_custom_email.go b/ibm/service/eventnotification/resource_ibm_en_destination_custom_email.go index 2392065817..029e4459d1 100644 --- a/ibm/service/eventnotification/resource_ibm_en_destination_custom_email.go +++ b/ibm/service/eventnotification/resource_ibm_en_destination_custom_email.go @@ -46,6 +46,11 @@ func ResourceIBMEnCustomEmailDestination() *schema.Resource { Optional: true, Description: "The Destination description.", }, + "collect_failed_events": { + Type: schema.TypeBool, + Optional: true, + Description: "Whether to collect the failed event in Cloud Object Storage bucket", + }, "config": { Type: schema.TypeList, MaxItems: 1, @@ -107,6 +112,7 @@ func resourceIBMEnCustomEmailDestinationCreate(context context.Context, d *schem options.SetName(d.Get("name").(string)) options.SetType(d.Get("type").(string)) + options.SetCollectFailedEvents(d.Get("collect_failed_events").(bool)) destinationtype := d.Get("type").(string) if _, ok := d.GetOk("description"); ok { options.SetDescription(d.Get("description").(string)) @@ -167,6 +173,10 @@ func resourceIBMEnCustomEmailDestinationRead(context context.Context, d *schema. return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) } + if err = d.Set("collect_failed_events", result.CollectFailedEvents); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting CollectFailedEvents: %s", err)) + } + if err = d.Set("description", result.Description); err != nil { return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) } @@ -209,13 +219,17 @@ func resourceIBMEnCustomEmailDestinationUpdate(context context.Context, d *schem options.SetInstanceID(parts[0]) options.SetID(parts[1]) - if ok := d.HasChanges("name", "description", "config"); ok { + if ok := d.HasChanges("name", "description", "collect_failed_events", "config"); ok { options.SetName(d.Get("name").(string)) if _, ok := d.GetOk("description"); ok { options.SetDescription(d.Get("description").(string)) } + if _, ok := d.GetOk("collect_failed_events"); ok { + options.SetCollectFailedEvents(d.Get("collect_failed_events").(bool)) + } + destinationtype := d.Get("type").(string) if _, ok := d.GetOk("config"); ok { config := CustomEmaildestinationConfigMapToDestinationConfig(d.Get("config.0.params.0").(map[string]interface{}), destinationtype) diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_custom_email_test.go b/ibm/service/eventnotification/resource_ibm_en_destination_custom_email_test.go index c57a0c93da..0363bbfabe 100644 --- a/ibm/service/eventnotification/resource_ibm_en_destination_custom_email_test.go +++ b/ibm/service/eventnotification/resource_ibm_en_destination_custom_email_test.go @@ -37,6 +37,7 @@ func TestAccIBMEnCustomEmailDestinationAllArgs(t *testing.T) { testAccCheckIBMEnCustomEmailDestinationExists("ibm_en_destination_custom_email.en_destination_resource_1", config), resource.TestCheckResourceAttr("ibm_en_destination_custom_email.en_destination_resource_1", "name", name), resource.TestCheckResourceAttr("ibm_en_destination_custom_email.en_destination_resource_1", "type", "smtp_custom"), + resource.TestCheckResourceAttr("ibm_en_destination_custom_email.en_destination_resource_1", "collect_failed_events", "false"), resource.TestCheckResourceAttr("ibm_en_destination_custom_email.en_destination_resource_1", "description", description), ), }, @@ -45,6 +46,7 @@ func TestAccIBMEnCustomEmailDestinationAllArgs(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_en_destination_custom_email.en_destination_resource_1", "name", newName), resource.TestCheckResourceAttr("ibm_en_destination_custom_email.en_destination_resource_1", "type", "smtp_custom"), + resource.TestCheckResourceAttr("ibm_en_destination_custom_email.en_destination_resource_1", "collect_failed_events", "false"), resource.TestCheckResourceAttr("ibm_en_destination_custom_email.en_destination_resource_1", "description", newDescription), ), }, diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_custom_sms.go b/ibm/service/eventnotification/resource_ibm_en_destination_custom_sms.go new file mode 100644 index 0000000000..43fd471208 --- /dev/null +++ b/ibm/service/eventnotification/resource_ibm_en_destination_custom_sms.go @@ -0,0 +1,260 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func ResourceIBMEnCustomSMSDestination() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMEnCustomSMSDestinationCreate, + ReadContext: resourceIBMEnCustomSMSDestinationRead, + UpdateContext: resourceIBMEnCustomSMSDestinationUpdate, + DeleteContext: resourceIBMEnCustomSMSDestinationDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "name": { + Type: schema.TypeString, + Required: true, + Description: "The Destintion name.", + }, + "type": { + Type: schema.TypeString, + Required: true, + Description: "The type of Destination sms_custom.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "The Destination description.", + }, + "collect_failed_events": { + Type: schema.TypeBool, + Optional: true, + Description: "Whether to collect the failed event in Cloud Object Storage bucket", + }, + "destination_id": { + Type: schema.TypeString, + Computed: true, + Description: "Destination ID", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + "subscription_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Number of subscriptions.", + }, + "subscription_names": { + Type: schema.TypeList, + Computed: true, + Description: "List of subscriptions.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + } +} + +func resourceIBMEnCustomSMSDestinationCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.CreateDestinationOptions{} + + options.SetInstanceID(d.Get("instance_guid").(string)) + options.SetName(d.Get("name").(string)) + options.SetType(d.Get("type").(string)) + options.SetCollectFailedEvents(d.Get("collect_failed_events").(bool)) + + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + // if _, ok := d.GetOk("config"); ok { + // config := SlackdestinationConfigMapToDestinationConfig(d.Get("config.0.params.0").(map[string]interface{}), destinationtype) + // options.SetConfig(&config) + // } + + result, response, err := enClient.CreateDestinationWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("CreateDestinationWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *options.InstanceID, *result.ID)) + + return resourceIBMEnSlackDestinationRead(context, d, meta) +} + +func resourceIBMEnCustomSMSDestinationRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.GetDestinationOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + result, response, err := enClient.GetDestinationWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("GetDestinationWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("instance_guid", options.InstanceID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting instance_guid: %s", err)) + } + + if err = d.Set("destination_id", options.ID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_id: %s", err)) + } + + if err = d.Set("name", result.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if err = d.Set("type", result.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) + } + + if err = d.Set("description", result.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + + if err = d.Set("collect_failed_events", result.CollectFailedEvents); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting CollectFailedEvents: %s", err)) + } + + // if result.Config != nil { + // err = d.Set("config", enWebhookDestinationFlattenConfig(*result.Config)) + // if err != nil { + // return diag.FromErr(fmt.Errorf("[ERROR] Error setting config %s", err)) + // } + // } + + if err = d.Set("updated_at", flex.DateTimeToString(result.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + if err = d.Set("subscription_count", flex.IntValue(result.SubscriptionCount)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_count: %s", err)) + } + + if err = d.Set("subscription_names", result.SubscriptionNames); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_names: %s", err)) + + } + + return nil +} + +func resourceIBMEnCustomSMSDestinationUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.UpdateDestinationOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + if ok := d.HasChanges("name", "description", "collect_failed_events"); ok { + options.SetName(d.Get("name").(string)) + + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + if _, ok := d.GetOk("collect_failed_events"); ok { + options.SetCollectFailedEvents(d.Get("collect_failed_events").(bool)) + } + _, response, err := enClient.UpdateDestinationWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("UpdateDestinationWithContext failed %s\n%s", err, response)) + } + + return resourceIBMEnSlackDestinationRead(context, d, meta) + } + + return nil +} + +func resourceIBMEnCustomSMSDestinationDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.DeleteDestinationOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + response, err := enClient.DeleteDestinationWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("DeleteDestinationWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +// func SlackdestinationConfigMapToDestinationConfig(configParams map[string]interface{}, destinationtype string) en.DestinationConfig { +// params := new(en.DestinationConfigOneOf) +// if configParams["url"] != nil { +// params.URL = core.StringPtr(configParams["url"].(string)) +// } + +// if configParams["collect_failed_events"] != nil { +// params.CollectFailedEvents = core.BoolPtr(configParams["collect_failed_events"].(bool)) +// } + +// destinationConfig := new(en.DestinationConfig) +// destinationConfig.Params = params +// return *destinationConfig +// } diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_test.go b/ibm/service/eventnotification/resource_ibm_en_destination_custom_sms_test.go similarity index 62% rename from ibm/service/eventnotification/resource_ibm_en_destination_test.go rename to ibm/service/eventnotification/resource_ibm_en_destination_custom_sms_test.go index 95b5e511b0..28635dd68b 100644 --- a/ibm/service/eventnotification/resource_ibm_en_destination_test.go +++ b/ibm/service/eventnotification/resource_ibm_en_destination_custom_sms_test.go @@ -18,7 +18,7 @@ import ( en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" ) -func TestAccIBMEnDestinationAllArgs(t *testing.T) { +func TestAccIBMEnCustomSMSDestinationAllArgs(t *testing.T) { var config en.Destination name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) instanceName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) @@ -29,27 +29,29 @@ func TestAccIBMEnDestinationAllArgs(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { acc.TestAccPreCheck(t) }, Providers: acc.TestAccProviders, - CheckDestroy: testAccCheckIBMEnDestinationDestroy, + CheckDestroy: testAccCheckIBMEnServiceNowDestinationDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIBMEnDestinationConfig(instanceName, name, description), + Config: testAccCheckIBMEnCustomSMSDestinationConfig(instanceName, name, description), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMEnDestinationExists("ibm_en_destination.en_destination_resource_1", config), - resource.TestCheckResourceAttr("ibm_en_destination.en_destination_resource_1", "name", name), - resource.TestCheckResourceAttr("ibm_en_destination.en_destination_resource_1", "type", "webhook"), - resource.TestCheckResourceAttr("ibm_en_destination.en_destination_resource_1", "description", description), + testAccCheckIBMEnCustomSMSDestinationExists("ibm_en_destination_custom_sms.en_destination_resource_1", config), + resource.TestCheckResourceAttr("ibm_en_destination_custom_sms.en_destination_resource_1", "name", name), + resource.TestCheckResourceAttr("ibm_en_destination_custom_sms.en_destination_resource_1", "type", "smtp_custom"), + resource.TestCheckResourceAttr("ibm_en_destination_custom_sms.en_destination_resource_1", "collect_failed_events", "false"), + resource.TestCheckResourceAttr("ibm_en_destination_custom_sms.en_destination_resource_1", "description", description), ), }, { - Config: testAccCheckIBMEnDestinationConfig(instanceName, newName, newDescription), + Config: testAccCheckIBMEnCustomEmailDestinationConfig(instanceName, newName, newDescription), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("ibm_en_destination.en_destination_resource_1", "name", newName), - resource.TestCheckResourceAttr("ibm_en_destination.en_destination_resource_1", "type", "webhook"), - resource.TestCheckResourceAttr("ibm_en_destination.en_destination_resource_1", "description", newDescription), + resource.TestCheckResourceAttr("ibm_en_destination_custom_sms.en_destination_resource_1", "name", newName), + resource.TestCheckResourceAttr("ibm_en_destination_custom_sms.en_destination_resource_1", "type", "sms_custom"), + resource.TestCheckResourceAttr("ibm_en_destination_custom_sms.en_destination_resource_1", "collect_failed_events", "false"), + resource.TestCheckResourceAttr("ibm_en_destination_custom_sms.en_destination_resource_1", "description", newDescription), ), }, { - ResourceName: "ibm_en_destination.en_destination_resource_1", + ResourceName: "ibm_en_destination_custom_sms.en_destination_resource_1", ImportState: true, ImportStateVerify: true, }, @@ -57,7 +59,7 @@ func TestAccIBMEnDestinationAllArgs(t *testing.T) { }) } -func testAccCheckIBMEnDestinationConfig(instanceName, name, description string) string { +func testAccCheckIBMEnCustomSMSDestinationConfig(instanceName, name, description string) string { return fmt.Sprintf(` resource "ibm_resource_instance" "en_destination_resource" { name = "%s" @@ -66,22 +68,16 @@ func testAccCheckIBMEnDestinationConfig(instanceName, name, description string) service = "event-notifications" } - resource "ibm_en_destination" "en_destination_resource_1" { + resource "ibm_en_destination_custom_sms" "en_destination_resource_1" { instance_guid = ibm_resource_instance.en_destination_resource.guid name = "%s" - type = "webhook" + type = "sms_custom" description = "%s" - config { - params { - verb = "POST" - url = "https://demo.webhook.com" - } - } } `, instanceName, name, description) } -func testAccCheckIBMEnDestinationExists(n string, obj en.Destination) resource.TestCheckFunc { +func testAccCheckIBMEnCustomSMSDestinationExists(n string, obj en.Destination) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -114,7 +110,7 @@ func testAccCheckIBMEnDestinationExists(n string, obj en.Destination) resource.T } } -func testAccCheckIBMEnDestinationDestroy(s *terraform.State) error { +func testAccCheckIBMEnCustomSMSDestinationDestroy(s *terraform.State) error { enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() if err != nil { return err diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_fcm.go b/ibm/service/eventnotification/resource_ibm_en_destination_fcm.go index 00ae26b8cc..577a909dbf 100644 --- a/ibm/service/eventnotification/resource_ibm_en_destination_fcm.go +++ b/ibm/service/eventnotification/resource_ibm_en_destination_fcm.go @@ -46,6 +46,11 @@ func ResourceIBMEnFCMDestination() *schema.Resource { Optional: true, Description: "The Destination description.", }, + "collect_failed_events": { + Type: schema.TypeBool, + Optional: true, + Description: "Whether to collect the failed event in Cloud Object Storage bucket", + }, "config": { Type: schema.TypeList, MaxItems: 1, @@ -121,6 +126,7 @@ func resourceIBMEnFCMDestinationCreate(context context.Context, d *schema.Resour options.SetInstanceID(d.Get("instance_guid").(string)) options.SetName(d.Get("name").(string)) options.SetType(d.Get("type").(string)) + options.SetCollectFailedEvents(d.Get("collect_failed_events").(bool)) destinationtype := d.Get("type").(string) if _, ok := d.GetOk("description"); ok { @@ -182,6 +188,10 @@ func resourceIBMEnFCMDestinationRead(context context.Context, d *schema.Resource return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) } + if err = d.Set("collect_failed_events", result.CollectFailedEvents); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting CollectFailedEvents: %s", err)) + } + if err = d.Set("description", result.Description); err != nil { return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) } @@ -225,12 +235,16 @@ func resourceIBMEnFCMDestinationUpdate(context context.Context, d *schema.Resour options.SetInstanceID(parts[0]) options.SetID(parts[1]) - if ok := d.HasChanges("name", "description", "config"); ok { + if ok := d.HasChanges("name", "description", "collect_failed_events", "config"); ok { options.SetName(d.Get("name").(string)) if _, ok := d.GetOk("description"); ok { options.SetDescription(d.Get("description").(string)) } + + if _, ok := d.GetOk("collect_failed_events"); ok { + options.SetCollectFailedEvents(d.Get("collect_failed_events").(bool)) + } destinationtype := d.Get("type").(string) if _, ok := d.GetOk("config"); ok { config := FCMdestinationConfigMapToDestinationConfig(d.Get("config.0.params.0").(map[string]interface{}), destinationtype) diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_fcm_test.go b/ibm/service/eventnotification/resource_ibm_en_destination_fcm_test.go index a33dd0fba3..25c105eda4 100644 --- a/ibm/service/eventnotification/resource_ibm_en_destination_fcm_test.go +++ b/ibm/service/eventnotification/resource_ibm_en_destination_fcm_test.go @@ -36,7 +36,8 @@ func TestAccIBMEnFCMDestinationAllArgs(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMEnFCMDestinationExists("ibm_en_destination_android.en_destination_resource_fcm", config), resource.TestCheckResourceAttr("ibm_en_destination_android.en_destination_resource_fcm", "name", name), - resource.TestCheckResourceAttr("ibm_en_destination_android.en_destination_resource_fcm", "type", "webhook"), + resource.TestCheckResourceAttr("ibm_en_destination_android.en_destination_resource_fcm", "type", "push_android"), + resource.TestCheckResourceAttr("ibm_en_destination_android.en_destination_resource_fcm", "collect_failed_events", "false"), resource.TestCheckResourceAttr("ibm_en_destination_android.en_destination_resource_fcm", "description", description), ), }, @@ -45,6 +46,7 @@ func TestAccIBMEnFCMDestinationAllArgs(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_en_destination_android.en_destination_resource_fcm", "name", newName), resource.TestCheckResourceAttr("ibm_en_destination_android.en_destination_resource_fcm", "type", "push_android"), + resource.TestCheckResourceAttr("ibm_en_destination_android.en_destination_resource_fcm", "collect_failed_events", "false"), resource.TestCheckResourceAttr("ibm_en_destination_android.en_destination_resource_fcm", "description", newDescription), ), }, diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_firefox.go b/ibm/service/eventnotification/resource_ibm_en_destination_firefox.go index a4bfd9bca4..04f04952d5 100644 --- a/ibm/service/eventnotification/resource_ibm_en_destination_firefox.go +++ b/ibm/service/eventnotification/resource_ibm_en_destination_firefox.go @@ -46,6 +46,11 @@ func ResourceIBMEnFirefoxDestination() *schema.Resource { Optional: true, Description: "The Destination description.", }, + "collect_failed_events": { + Type: schema.TypeBool, + Optional: true, + Description: "Whether to collect the failed event in Cloud Object Storage bucket", + }, "config": { Type: schema.TypeList, MaxItems: 1, @@ -112,6 +117,7 @@ func resourceIBMEnFirefoxDestinationCreate(context context.Context, d *schema.Re options.SetName(d.Get("name").(string)) options.SetType(d.Get("type").(string)) + options.SetCollectFailedEvents(d.Get("collect_failed_events").(bool)) if _, ok := d.GetOk("description"); ok { options.SetDescription(d.Get("description").(string)) @@ -172,6 +178,10 @@ func resourceIBMEnFirefoxDestinationRead(context context.Context, d *schema.Reso return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) } + if err = d.Set("collect_failed_events", result.CollectFailedEvents); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting CollectFailedEvents: %s", err)) + } + if err = d.Set("description", result.Description); err != nil { return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) } @@ -214,13 +224,17 @@ func resourceIBMEnFirefoxDestinationUpdate(context context.Context, d *schema.Re options.SetInstanceID(parts[0]) options.SetID(parts[1]) - if ok := d.HasChanges("name", "description", "config"); ok { + if ok := d.HasChanges("name", "description", "collect_failed_events", "config"); ok { options.SetName(d.Get("name").(string)) if _, ok := d.GetOk("description"); ok { options.SetDescription(d.Get("description").(string)) } + if _, ok := d.GetOk("collect_failed_events"); ok { + options.SetCollectFailedEvents(d.Get("collect_failed_events").(bool)) + } + if _, ok := d.GetOk("config"); ok { config := firefoxdestinationConfigMapToDestinationConfig(d.Get("config.0.params.0").(map[string]interface{})) options.SetConfig(&config) diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_firefox_test.go b/ibm/service/eventnotification/resource_ibm_en_destination_firefox_test.go index c2f2d70118..5e5515960e 100644 --- a/ibm/service/eventnotification/resource_ibm_en_destination_firefox_test.go +++ b/ibm/service/eventnotification/resource_ibm_en_destination_firefox_test.go @@ -37,6 +37,7 @@ func TestAccIBMEnFirefoxDestinationAllArgs(t *testing.T) { testAccCheckIBMEnFirefoxDestinationExists("ibm_en_destination_firefox.en_destination_resource_1", config), resource.TestCheckResourceAttr("ibm_en_destination_firefox.en_destination_resource_1", "name", name), resource.TestCheckResourceAttr("ibm_en_destination_firefox.en_destination_resource_1", "type", "push_firefox"), + resource.TestCheckResourceAttr("ibm_en_destination_firefox.en_destination_resource_1", "collect_failed_events", "false"), resource.TestCheckResourceAttr("ibm_en_destination_firefox.en_destination_resource_1", "description", description), ), }, @@ -45,6 +46,7 @@ func TestAccIBMEnFirefoxDestinationAllArgs(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_en_destination_firefox.en_destination_resource_1", "name", newName), resource.TestCheckResourceAttr("ibm_en_destination_firefox.en_destination_resource_1", "type", "push_firefox"), + resource.TestCheckResourceAttr("ibm_en_destination_firefox.en_destination_resource_1", "collect_failed_events", "false"), resource.TestCheckResourceAttr("ibm_en_destination_firefox.en_destination_resource_1", "description", newDescription), ), }, diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_huawei.go b/ibm/service/eventnotification/resource_ibm_en_destination_huawei.go index d2872d467c..e72b24af29 100644 --- a/ibm/service/eventnotification/resource_ibm_en_destination_huawei.go +++ b/ibm/service/eventnotification/resource_ibm_en_destination_huawei.go @@ -46,6 +46,11 @@ func ResourceIBMEnHuaweiDestination() *schema.Resource { Optional: true, Description: "The Destination description.", }, + "collect_failed_events": { + Type: schema.TypeBool, + Optional: true, + Description: "Whether to collect the failed event in Cloud Object Storage bucket", + }, "config": { Type: schema.TypeList, MaxItems: 1, @@ -116,6 +121,7 @@ func resourceIBMEnHuaweiDestinationCreate(context context.Context, d *schema.Res options.SetInstanceID(d.Get("instance_guid").(string)) options.SetName(d.Get("name").(string)) options.SetType(d.Get("type").(string)) + options.SetCollectFailedEvents(d.Get("collect_failed_events").(bool)) destinationtype := d.Get("type").(string) if _, ok := d.GetOk("description"); ok { @@ -177,6 +183,10 @@ func resourceIBMEnHuaweiDestinationRead(context context.Context, d *schema.Resou return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) } + if err = d.Set("collect_failed_events", result.CollectFailedEvents); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting CollectFailedEvents: %s", err)) + } + if err = d.Set("description", result.Description); err != nil { return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) } @@ -220,12 +230,16 @@ func resourceIBMEnHuaweiDestinationUpdate(context context.Context, d *schema.Res options.SetInstanceID(parts[0]) options.SetID(parts[1]) - if ok := d.HasChanges("name", "description", "config"); ok { + if ok := d.HasChanges("name", "description", "collect_failed_events", "config"); ok { options.SetName(d.Get("name").(string)) if _, ok := d.GetOk("description"); ok { options.SetDescription(d.Get("description").(string)) } + + if _, ok := d.GetOk("collect_failed_events"); ok { + options.SetCollectFailedEvents(d.Get("collect_failed_events").(bool)) + } destinationtype := d.Get("type").(string) if _, ok := d.GetOk("config"); ok { config := HuaweidestinationConfigMapToDestinationConfig(d.Get("config.0.params.0").(map[string]interface{}), destinationtype) diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_huawei_test.go b/ibm/service/eventnotification/resource_ibm_en_destination_huawei_test.go index b790c2914d..15ef3e08a6 100644 --- a/ibm/service/eventnotification/resource_ibm_en_destination_huawei_test.go +++ b/ibm/service/eventnotification/resource_ibm_en_destination_huawei_test.go @@ -37,6 +37,7 @@ func TestAccIBMEnHuaweiDestinationAllArgs(t *testing.T) { testAccCheckIBMEnHuaweiDestinationExists("ibm_en_destination_huawei.en_destination_resource_huawei", config), resource.TestCheckResourceAttr("ibm_en_destination_huawei.en_destination_resource_huawei", "name", name), resource.TestCheckResourceAttr("ibm_en_destination_huawei.en_destination_resource_huawei", "type", "push_huawei"), + resource.TestCheckResourceAttr("ibm_en_destination_huawei.en_destination_resource_huawei", "collect_failed_events", "false"), resource.TestCheckResourceAttr("ibm_en_destination_huawei.en_destination_resource_huawei", "description", description), ), }, @@ -45,6 +46,7 @@ func TestAccIBMEnHuaweiDestinationAllArgs(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_en_destination_huawei.en_destination_resource_huawei", "name", newName), resource.TestCheckResourceAttr("ibm_en_destination_huawei.en_destination_resource_huawei", "type", "push_huawei"), + resource.TestCheckResourceAttr("ibm_en_destination_huawei.en_destination_resource_huawei", "collect_failed_events", "false"), resource.TestCheckResourceAttr("ibm_en_destination_huawei.en_destination_resource_huawei", "description", newDescription), ), }, diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_msteams.go b/ibm/service/eventnotification/resource_ibm_en_destination_msteams.go index f283e64006..eed4db5b64 100644 --- a/ibm/service/eventnotification/resource_ibm_en_destination_msteams.go +++ b/ibm/service/eventnotification/resource_ibm_en_destination_msteams.go @@ -46,6 +46,11 @@ func ResourceIBMEnMSTeamsDestination() *schema.Resource { Optional: true, Description: "The Destination description.", }, + "collect_failed_events": { + Type: schema.TypeBool, + Optional: true, + Description: "Whether to collect the failed event in Cloud Object Storage bucket", + }, "config": { Type: schema.TypeList, MaxItems: 1, @@ -106,6 +111,7 @@ func resourceIBMEnMSTeamsDestinationCreate(context context.Context, d *schema.Re options.SetInstanceID(d.Get("instance_guid").(string)) options.SetName(d.Get("name").(string)) options.SetType(d.Get("type").(string)) + options.SetCollectFailedEvents(d.Get("collect_failed_events").(bool)) destinationtype := d.Get("type").(string) if _, ok := d.GetOk("description"); ok { @@ -167,6 +173,10 @@ func resourceIBMEnMSTeamsDestinationRead(context context.Context, d *schema.Reso return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) } + if err = d.Set("collect_failed_events", result.CollectFailedEvents); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting CollectFailedEvents: %s", err)) + } + if err = d.Set("description", result.Description); err != nil { return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) } @@ -210,12 +220,17 @@ func resourceIBMEnMSTeamsDestinationUpdate(context context.Context, d *schema.Re options.SetInstanceID(parts[0]) options.SetID(parts[1]) - if ok := d.HasChanges("name", "description", "config"); ok { + if ok := d.HasChanges("name", "description", "collect_failed_events", "config"); ok { options.SetName(d.Get("name").(string)) if _, ok := d.GetOk("description"); ok { options.SetDescription(d.Get("description").(string)) } + + if _, ok := d.GetOk("collect_failed_events"); ok { + options.SetCollectFailedEvents(d.Get("collect_failed_events").(bool)) + } + destinationtype := d.Get("type").(string) if _, ok := d.GetOk("config"); ok { config := MSTeamsdestinationConfigMapToDestinationConfig(d.Get("config.0.params.0").(map[string]interface{}), destinationtype) diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_msteams_test.go b/ibm/service/eventnotification/resource_ibm_en_destination_msteams_test.go index 063082093d..c0784f2dfa 100644 --- a/ibm/service/eventnotification/resource_ibm_en_destination_msteams_test.go +++ b/ibm/service/eventnotification/resource_ibm_en_destination_msteams_test.go @@ -37,6 +37,7 @@ func TestAccIBMEnMSTeamsDestinationAllArgs(t *testing.T) { testAccCheckIBMEnMSTeamsDestinationExists("ibm_en_destination_msteams.en_destination_resource_1", config), resource.TestCheckResourceAttr("ibm_en_destination_msteams.en_destination_resource_1", "name", name), resource.TestCheckResourceAttr("ibm_en_destination_msteams.en_destination_resource_1", "type", "msteams"), + resource.TestCheckResourceAttr("ibm_en_destination_msteams.en_destination_resource_1", "collect_failed_events", "false"), resource.TestCheckResourceAttr("ibm_en_destination_msteams.en_destination_resource_1", "description", description), ), }, @@ -45,6 +46,7 @@ func TestAccIBMEnMSTeamsDestinationAllArgs(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_en_destination_msteams.en_destination_resource_1", "name", newName), resource.TestCheckResourceAttr("ibm_en_destination_msteams.en_destination_resource_1", "type", "msteams"), + resource.TestCheckResourceAttr("ibm_en_destination_msteams.en_destination_resource_1", "collect_failed_events", "false"), resource.TestCheckResourceAttr("ibm_en_destination_msteams.en_destination_resource_1", "description", newDescription), ), }, diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_pagerduty.go b/ibm/service/eventnotification/resource_ibm_en_destination_pagerduty.go index 8f03a84642..922088b30a 100644 --- a/ibm/service/eventnotification/resource_ibm_en_destination_pagerduty.go +++ b/ibm/service/eventnotification/resource_ibm_en_destination_pagerduty.go @@ -46,6 +46,11 @@ func ResourceIBMEnPagerDutyDestination() *schema.Resource { Optional: true, Description: "The Destination description.", }, + "collect_failed_events": { + Type: schema.TypeBool, + Optional: true, + Description: "Whether to collect the failed event in Cloud Object Storage bucket", + }, "config": { Type: schema.TypeList, MaxItems: 1, @@ -113,6 +118,7 @@ func resourceIBMEnPagerDutyDestinationCreate(context context.Context, d *schema. options.SetName(d.Get("name").(string)) options.SetType(d.Get("type").(string)) + options.SetCollectFailedEvents(d.Get("collect_failed_events").(bool)) destinationtype := d.Get("type").(string) if _, ok := d.GetOk("description"); ok { options.SetDescription(d.Get("description").(string)) @@ -173,6 +179,10 @@ func resourceIBMEnPagerDutyDestinationRead(context context.Context, d *schema.Re return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) } + if err = d.Set("collect_failed_events", result.CollectFailedEvents); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting CollectFailedEvents: %s", err)) + } + if err = d.Set("description", result.Description); err != nil { return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) } @@ -215,13 +225,17 @@ func resourceIBMEnPagerDutyDestinationUpdate(context context.Context, d *schema. options.SetInstanceID(parts[0]) options.SetID(parts[1]) - if ok := d.HasChanges("name", "description", "config"); ok { + if ok := d.HasChanges("name", "description", "collect_failed_events", "config"); ok { options.SetName(d.Get("name").(string)) if _, ok := d.GetOk("description"); ok { options.SetDescription(d.Get("description").(string)) } + if _, ok := d.GetOk("collect_failed_events"); ok { + options.SetCollectFailedEvents(d.Get("collect_failed_events").(bool)) + } + destinationtype := d.Get("type").(string) if _, ok := d.GetOk("config"); ok { config := PagerDutydestinationConfigMapToDestinationConfig(d.Get("config.0.params.0").(map[string]interface{}), destinationtype) diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_pagerduty_test.go b/ibm/service/eventnotification/resource_ibm_en_destination_pagerduty_test.go index c740ed7009..e585df69d5 100644 --- a/ibm/service/eventnotification/resource_ibm_en_destination_pagerduty_test.go +++ b/ibm/service/eventnotification/resource_ibm_en_destination_pagerduty_test.go @@ -37,6 +37,7 @@ func TestAccIBMEnPagerDutyDestinationAllArgs(t *testing.T) { testAccCheckIBMEnPagerDutyDestinationExists("ibm_en_destination_pagerduty.en_destination_resource_1", config), resource.TestCheckResourceAttr("ibm_en_destination_pagerduty.en_destination_resource_1", "name", name), resource.TestCheckResourceAttr("ibm_en_destination_pagerduty.en_destination_resource_1", "type", "pagerduty"), + resource.TestCheckResourceAttr("ibm_en_destination_pagerduty.en_destination_resource_1", "collect_failed_events", "false"), resource.TestCheckResourceAttr("ibm_en_destination_pagerduty.en_destination_resource_1", "description", description), ), }, @@ -45,6 +46,7 @@ func TestAccIBMEnPagerDutyDestinationAllArgs(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_en_destination_pagerduty.en_destination_resource_1", "name", newName), resource.TestCheckResourceAttr("ibm_en_destination_pagerduty.en_destination_resource_1", "type", "pagerduty"), + resource.TestCheckResourceAttr("ibm_en_destination_pagerduty.en_destination_resource_1", "collect_failed_events", "false"), resource.TestCheckResourceAttr("ibm_en_destination_pagerduty.en_destination_resource_1", "description", newDescription), ), }, diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_safari.go b/ibm/service/eventnotification/resource_ibm_en_destination_safari.go index aaafd957d9..058f7bc1cf 100644 --- a/ibm/service/eventnotification/resource_ibm_en_destination_safari.go +++ b/ibm/service/eventnotification/resource_ibm_en_destination_safari.go @@ -48,6 +48,11 @@ func ResourceIBMEnSafariDestination() *schema.Resource { Optional: true, Description: "The Destination description.", }, + "collect_failed_events": { + Type: schema.TypeBool, + Optional: true, + Description: "Whether to collect the failed event in Cloud Object Storage bucket", + }, "certificate": { Type: schema.TypeString, Required: true, @@ -205,6 +210,7 @@ func resourceIBMEnSafariDestinationCreate(context context.Context, d *schema.Res options.SetName(d.Get("name").(string)) options.SetType(d.Get("type").(string)) + options.SetCollectFailedEvents(d.Get("collect_failed_events").(bool)) // options.SetCertificateContentType(d.Get("certificate_content_type").(string)) if _, ok := d.GetOk("icon_16x16_content_type"); ok { @@ -406,6 +412,10 @@ func resourceIBMEnSafariDestinationRead(context context.Context, d *schema.Resou return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) } + if err = d.Set("collect_failed_events", result.CollectFailedEvents); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting CollectFailedEvents: %s", err)) + } + if err = d.Set("description", result.Description); err != nil { return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) } @@ -448,14 +458,16 @@ func resourceIBMEnSafariDestinationUpdate(context context.Context, d *schema.Res options.SetInstanceID(parts[0]) options.SetID(parts[1]) - if ok := d.HasChanges("name", "description", "certificate", "icon_16x16", "icon_16x16_2x", "icon_32x32", "icon_32x32_2x", "icon_128x128", "icon_128x128_2x", "config"); ok { + if ok := d.HasChanges("name", "description", "collect_failed_events", "certificate", "icon_16x16", "icon_16x16_2x", "icon_32x32", "icon_32x32_2x", "icon_128x128", "icon_128x128_2x", "config"); ok { options.SetName(d.Get("name").(string)) if _, ok := d.GetOk("description"); ok { options.SetDescription(d.Get("description").(string)) } - // certificatetype := d.Get("certificate_content_type").(string) + if _, ok := d.GetOk("collect_failed_events"); ok { + options.SetCollectFailedEvents(d.Get("collect_failed_events").(bool)) + } if c, ok := d.GetOk("certificate"); ok { path := c.(string) diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_safari_test.go b/ibm/service/eventnotification/resource_ibm_en_destination_safari_test.go index 14d4c9f269..de0d67b06f 100644 --- a/ibm/service/eventnotification/resource_ibm_en_destination_safari_test.go +++ b/ibm/service/eventnotification/resource_ibm_en_destination_safari_test.go @@ -37,6 +37,7 @@ func TestAccIBMEnSafariDestinationAllArgs(t *testing.T) { testAccCheckIBMEnSafariDestinationExists("ibm_en_destination_safari.en_destination_resource_safari", config), resource.TestCheckResourceAttr("ibm_en_destination_safari.en_destination_resource_safari", "name", name), resource.TestCheckResourceAttr("ibm_en_destination_safari.en_destination_resource_safari", "type", "push_safari"), + resource.TestCheckResourceAttr("ibm_en_destination_safari.en_destination_resource_safari", "collect_failed_events", "false"), resource.TestCheckResourceAttr("ibm_en_destination_safari.en_destination_resource_safari", "description", description), ), }, @@ -45,6 +46,7 @@ func TestAccIBMEnSafariDestinationAllArgs(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_en_destination_safari.en_destination_resource_safari", "name", newName), resource.TestCheckResourceAttr("ibm_en_destination_safari.en_destination_resource_safari", "type", "push_safari"), + resource.TestCheckResourceAttr("ibm_en_destination_safari.en_destination_resource_safari", "collect_failed_events", "false"), resource.TestCheckResourceAttr("ibm_en_destination_safari.en_destination_resource_safari", "description", newDescription), ), }, diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_servicenow.go b/ibm/service/eventnotification/resource_ibm_en_destination_servicenow.go index fa59b2c661..fcd0207dac 100644 --- a/ibm/service/eventnotification/resource_ibm_en_destination_servicenow.go +++ b/ibm/service/eventnotification/resource_ibm_en_destination_servicenow.go @@ -46,6 +46,11 @@ func ResourceIBMEnServiceNowDestination() *schema.Resource { Optional: true, Description: "The Destination description.", }, + "collect_failed_events": { + Type: schema.TypeBool, + Optional: true, + Description: "Whether to collect the failed event in Cloud Object Storage bucket", + }, "config": { Type: schema.TypeList, MaxItems: 1, @@ -131,6 +136,8 @@ func resourceIBMEnServiceNowDestinationCreate(context context.Context, d *schema options.SetName(d.Get("name").(string)) options.SetType(d.Get("type").(string)) + options.SetCollectFailedEvents(d.Get("collect_failed_events").(bool)) + destinationtype := d.Get("type").(string) if _, ok := d.GetOk("description"); ok { options.SetDescription(d.Get("description").(string)) @@ -195,6 +202,10 @@ func resourceIBMEnServiceNowDestinationRead(context context.Context, d *schema.R return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) } + if err = d.Set("collect_failed_events", result.CollectFailedEvents); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting CollectFailedEvents: %s", err)) + } + if result.Config != nil { err = d.Set("config", enServiceNowDestinationFlattenConfig(*result.Config)) if err != nil { @@ -233,13 +244,17 @@ func resourceIBMEnServiceNowDestinationUpdate(context context.Context, d *schema options.SetInstanceID(parts[0]) options.SetID(parts[1]) - if ok := d.HasChanges("name", "description", "config"); ok { + if ok := d.HasChanges("name", "description", "collect_failed_events", "config"); ok { options.SetName(d.Get("name").(string)) if _, ok := d.GetOk("description"); ok { options.SetDescription(d.Get("description").(string)) } + if _, ok := d.GetOk("collect_failed_events"); ok { + options.SetCollectFailedEvents(d.Get("collect_failed_events").(bool)) + } + destinationtype := d.Get("type").(string) if _, ok := d.GetOk("config"); ok { config := ServiceNowdestinationConfigMapToDestinationConfig(d.Get("config.0.params.0").(map[string]interface{}), destinationtype) diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_servicenow_test.go b/ibm/service/eventnotification/resource_ibm_en_destination_servicenow_test.go index 0a569905cb..b8c1e8e146 100644 --- a/ibm/service/eventnotification/resource_ibm_en_destination_servicenow_test.go +++ b/ibm/service/eventnotification/resource_ibm_en_destination_servicenow_test.go @@ -37,6 +37,7 @@ func TestAccIBMEnServiceNowDestinationAllArgs(t *testing.T) { testAccCheckIBMEnServiceNowDestinationExists("ibm_en_destination_sn.en_destination_resource_1", config), resource.TestCheckResourceAttr("ibm_en_destination_sn.en_destination_resource_1", "name", name), resource.TestCheckResourceAttr("ibm_en_destination_sn.en_destination_resource_1", "type", "pagerduty"), + resource.TestCheckResourceAttr("ibm_en_destination_sn.en_destination_resource_1", "collect_failed_events", "false"), resource.TestCheckResourceAttr("ibm_en_destination_sn.en_destination_resource_1", "description", description), ), }, @@ -45,6 +46,7 @@ func TestAccIBMEnServiceNowDestinationAllArgs(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_en_destination_sn.en_destination_resource_1", "name", newName), resource.TestCheckResourceAttr("ibm_en_destination_sn.en_destination_resource_1", "type", "pagerduty"), + resource.TestCheckResourceAttr("ibm_en_destination_sn.en_destination_resource_1", "collect_failed_events", "false"), resource.TestCheckResourceAttr("ibm_en_destination_sn.en_destination_resource_1", "description", newDescription), ), }, diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_slack.go b/ibm/service/eventnotification/resource_ibm_en_destination_slack.go index 84450a6fc8..49fb2ba4ef 100644 --- a/ibm/service/eventnotification/resource_ibm_en_destination_slack.go +++ b/ibm/service/eventnotification/resource_ibm_en_destination_slack.go @@ -46,6 +46,11 @@ func ResourceIBMEnSlackDestination() *schema.Resource { Optional: true, Description: "The Destination description.", }, + "collect_failed_events": { + Type: schema.TypeBool, + Optional: true, + Description: "Whether to collect the failed event in Cloud Object Storage bucket", + }, "config": { Type: schema.TypeList, MaxItems: 1, @@ -106,6 +111,7 @@ func resourceIBMEnSlackDestinationCreate(context context.Context, d *schema.Reso options.SetInstanceID(d.Get("instance_guid").(string)) options.SetName(d.Get("name").(string)) options.SetType(d.Get("type").(string)) + options.SetCollectFailedEvents(d.Get("collect_failed_events").(bool)) destinationtype := d.Get("type").(string) if _, ok := d.GetOk("description"); ok { @@ -167,6 +173,10 @@ func resourceIBMEnSlackDestinationRead(context context.Context, d *schema.Resour return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) } + if err = d.Set("collect_failed_events", result.CollectFailedEvents); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting CollectFailedEvents: %s", err)) + } + if err = d.Set("description", result.Description); err != nil { return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) } @@ -210,12 +220,17 @@ func resourceIBMEnSlackDestinationUpdate(context context.Context, d *schema.Reso options.SetInstanceID(parts[0]) options.SetID(parts[1]) - if ok := d.HasChanges("name", "description", "config"); ok { + if ok := d.HasChanges("name", "description", "collect_failed_events", "config"); ok { options.SetName(d.Get("name").(string)) if _, ok := d.GetOk("description"); ok { options.SetDescription(d.Get("description").(string)) } + + if _, ok := d.GetOk("collect_failed_events"); ok { + options.SetCollectFailedEvents(d.Get("collect_failed_events").(bool)) + } + destinationtype := d.Get("type").(string) if _, ok := d.GetOk("config"); ok { config := SlackdestinationConfigMapToDestinationConfig(d.Get("config.0.params.0").(map[string]interface{}), destinationtype) diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_slack_test.go b/ibm/service/eventnotification/resource_ibm_en_destination_slack_test.go index e7dc235651..4ca12d7483 100644 --- a/ibm/service/eventnotification/resource_ibm_en_destination_slack_test.go +++ b/ibm/service/eventnotification/resource_ibm_en_destination_slack_test.go @@ -37,6 +37,7 @@ func TestAccIBMEnSlackDestinationAllArgs(t *testing.T) { testAccCheckIBMEnSlackDestinationExists("ibm_en_destination_slack.en_destination_resource_1", config), resource.TestCheckResourceAttr("ibm_en_destination_slack.en_destination_resource_1", "name", name), resource.TestCheckResourceAttr("ibm_en_destination_slack.en_destination_resource_1", "type", "slack"), + resource.TestCheckResourceAttr("ibm_en_destination_slack.en_destination_resource_1", "collect_failed_events", "false"), resource.TestCheckResourceAttr("ibm_en_destination_slack.en_destination_resource_1", "description", description), ), }, @@ -45,6 +46,7 @@ func TestAccIBMEnSlackDestinationAllArgs(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_en_destination_slack.en_destination_resource_1", "name", newName), resource.TestCheckResourceAttr("ibm_en_destination_slack.en_destination_resource_1", "type", "slack"), + resource.TestCheckResourceAttr("ibm_en_destination_slack.en_destination_resource_1", "collect_failed_events", "false"), resource.TestCheckResourceAttr("ibm_en_destination_slack.en_destination_resource_1", "description", newDescription), ), }, diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_webhook.go b/ibm/service/eventnotification/resource_ibm_en_destination_webhook.go index a43b3c542f..c1542a709b 100644 --- a/ibm/service/eventnotification/resource_ibm_en_destination_webhook.go +++ b/ibm/service/eventnotification/resource_ibm_en_destination_webhook.go @@ -46,6 +46,11 @@ func ResourceIBMEnWebhookDestination() *schema.Resource { Optional: true, Description: "The Destination description.", }, + "collect_failed_events": { + Type: schema.TypeBool, + Optional: true, + Description: "Whether to collect the failed event in Cloud Object Storage bucket", + }, "config": { Type: schema.TypeList, MaxItems: 1, @@ -123,6 +128,7 @@ func resourceIBMEnWebhookDestinationCreate(context context.Context, d *schema.Re options.SetInstanceID(d.Get("instance_guid").(string)) options.SetName(d.Get("name").(string)) options.SetType(d.Get("type").(string)) + options.SetCollectFailedEvents(d.Get("collect_failed_events").(bool)) destinationtype := d.Get("type").(string) if _, ok := d.GetOk("description"); ok { @@ -188,6 +194,12 @@ func resourceIBMEnWebhookDestinationRead(context context.Context, d *schema.Reso return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) } + if result.CollectFailedEvents != nil { + if err = d.Set("collect_failed_events", result.CollectFailedEvents); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting CollectFailedEvents: %s", err)) + } + } + if result.Config != nil { err = d.Set("config", enWebhookDestinationFlattenConfig(*result.Config)) if err != nil { @@ -227,12 +239,16 @@ func resourceIBMEnWebhookDestinationUpdate(context context.Context, d *schema.Re options.SetInstanceID(parts[0]) options.SetID(parts[1]) - if ok := d.HasChanges("name", "description", "config"); ok { + if ok := d.HasChanges("name", "description", "collect_failed_events", "config"); ok { options.SetName(d.Get("name").(string)) if _, ok := d.GetOk("description"); ok { options.SetDescription(d.Get("description").(string)) } + + if _, ok := d.GetOk("collect_failed_events"); ok { + options.SetCollectFailedEvents(d.Get("collect_failed_events").(bool)) + } destinationtype := d.Get("type").(string) if _, ok := d.GetOk("config"); ok { config := WebhookdestinationConfigMapToDestinationConfig(d.Get("config.0.params.0").(map[string]interface{}), destinationtype) diff --git a/ibm/service/eventnotification/resource_ibm_en_destination_webhook_test.go b/ibm/service/eventnotification/resource_ibm_en_destination_webhook_test.go index c9a25af9da..a91489bcda 100644 --- a/ibm/service/eventnotification/resource_ibm_en_destination_webhook_test.go +++ b/ibm/service/eventnotification/resource_ibm_en_destination_webhook_test.go @@ -37,6 +37,7 @@ func TestAccIBMEnWebhookDestinationAllArgs(t *testing.T) { testAccCheckIBMEnWebhookDestinationExists("ibm_en_destination_webhook.en_destination_resource_1", config), resource.TestCheckResourceAttr("ibm_en_destination_webhook.en_destination_resource_1", "name", name), resource.TestCheckResourceAttr("ibm_en_destination_webhook.en_destination_resource_1", "type", "webhook"), + resource.TestCheckResourceAttr("ibm_en_destination_webhook.en_destination_resource_1", "collect_failed_events", "false"), resource.TestCheckResourceAttr("ibm_en_destination_webhook.en_destination_resource_1", "description", description), ), }, @@ -45,6 +46,7 @@ func TestAccIBMEnWebhookDestinationAllArgs(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ibm_en_destination_webhook.en_destination_resource_1", "name", newName), resource.TestCheckResourceAttr("ibm_en_destination_webhook.en_destination_resource_1", "type", "webhook"), + resource.TestCheckResourceAttr("ibm_en_destination_webhook.en_destination_resource_1", "collect_failed_events", "false"), resource.TestCheckResourceAttr("ibm_en_destination_webhook.en_destination_resource_1", "description", newDescription), ), }, diff --git a/ibm/service/eventnotification/resource_ibm_en_email_template.go b/ibm/service/eventnotification/resource_ibm_en_email_template.go new file mode 100644 index 0000000000..b23fe2d00b --- /dev/null +++ b/ibm/service/eventnotification/resource_ibm_en_email_template.go @@ -0,0 +1,262 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" + "github.com/IBM/go-sdk-core/v5/core" +) + +func ResourceIBMEnEmailTemplate() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMEnEmailTemplateCreate, + ReadContext: resourceIBMEnEmailTemplateRead, + UpdateContext: resourceIBMEnEmailTemplateUpdate, + DeleteContext: resourceIBMEnEmailTemplateDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "name": { + Type: schema.TypeString, + Required: true, + Description: "Subscription name.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Subscription description.", + }, + "type": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The type of template", + }, + "params": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "body": { + Type: schema.TypeString, + Optional: true, + Description: "The email address to reply to.", + }, + "subject": { + Type: schema.TypeString, + Optional: true, + Description: "The name of the email address user to reply to.", + }, + }, + }, + }, + "template_id": { + Type: schema.TypeString, + Computed: true, + Description: "Subscription ID.", + }, + "subscription_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Number of subscriptions.", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + "subscription_names": { + Type: schema.TypeList, + Computed: true, + Description: "List of subscriptions.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + } +} + +func resourceIBMEnEmailTemplateCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.CreateTemplateOptions{} + + options.SetInstanceID(d.Get("instance_guid").(string)) + + options.SetName(d.Get("name").(string)) + options.SetType(d.Get("type").(string)) + + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + + params := EmailTemplateParamsMap(d.Get("params.0").(map[string]interface{})) + options.SetParams(¶ms) + + result, response, err := enClient.CreateTemplateWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("CreateTemplateWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *options.InstanceID, *result.ID)) + + return resourceIBMEnEmailTemplateRead(context, d, meta) +} + +func resourceIBMEnEmailTemplateRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.GetTemplateOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + result, response, err := enClient.GetTemplateWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("GetTemplateWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("instance_guid", options.InstanceID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting instance_guid: %s", err)) + } + + if err = d.Set("template_id", options.ID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting template_id: %s", err)) + } + + if err = d.Set("name", result.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if result.Description != nil { + if err = d.Set("description", result.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + } + + if err = d.Set("type", result.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting template type: %s", err)) + } + + if err = d.Set("subscription_count", flex.IntValue(result.SubscriptionCount)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_count: %s", err)) + } + + if err = d.Set("subscription_names", result.SubscriptionNames); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subscription_names: %s", err)) + } + + if err = d.Set("updated_at", flex.DateTimeToString(result.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + return nil +} + +func resourceIBMEnEmailTemplateUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.ReplaceTemplateOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + if ok := d.HasChanges("name", "description", "params"); ok { + options.SetName(d.Get("name").(string)) + + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + + params := EmailTemplateParamsMap(d.Get("params.0").(map[string]interface{})) + options.SetParams(¶ms) + + _, response, err := enClient.ReplaceTemplateWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("ReplaceTemplateWithContext failed %s\n%s", err, response)) + } + + return resourceIBMEnEmailTemplateRead(context, d, meta) + } + + return nil +} + +func resourceIBMEnEmailTemplateDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.DeleteTemplateOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + response, err := enClient.DeleteTemplateWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("DeleteTemplateWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func EmailTemplateParamsMap(configParams map[string]interface{}) en.TemplateConfig { + params := new(en.TemplateConfig) + if configParams["body"] != nil { + params.Body = core.StringPtr(configParams["body"].(string)) + } + + if configParams["subject"] != nil { + params.Subject = core.StringPtr(configParams["subject"].(string)) + } + return *params +} diff --git a/ibm/service/eventnotification/resource_ibm_en_email_template_test.go b/ibm/service/eventnotification/resource_ibm_en_email_template_test.go new file mode 100644 index 0000000000..2913b475ad --- /dev/null +++ b/ibm/service/eventnotification/resource_ibm_en_email_template_test.go @@ -0,0 +1,146 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification_test + +import ( + "fmt" + "testing" + + 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/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func TestAccIBMEnEmailTemplateAllArgs(t *testing.T) { + var params en.Template + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + instanceName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + newName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + newDescription := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMEnEmailTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMEnEmailTemplateConfig(instanceName, name, description), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMEnEmailTemplateExists("ibm_en_email_template.en_template_resource_1", params), + resource.TestCheckResourceAttr("ibm_en_email_template.en_template_resource_1", "name", name), + resource.TestCheckResourceAttr("ibm_en_email_template.en_template_resource_1", "type", "smtp_custom.notification"), + resource.TestCheckResourceAttr("ibm_en_email_template.en_template_resource_1", "description", description), + ), + }, + { + Config: testAccCheckIBMEnEmailTemplateConfig(instanceName, newName, newDescription), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_en_email_template.en_template_resource_1", "name", newName), + resource.TestCheckResourceAttr("ibm_en_email_template.en_template_resource_1", "type", "smtp_custom"), + resource.TestCheckResourceAttr("ibm_en_email_template.en_template_resource_1", "description", newDescription), + ), + }, + { + ResourceName: "ibm_en_email_template.en_template_resource_1", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMEnEmailTemplateConfig(instanceName, name, description string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "en_template_resource" { + name = "%s" + location = "us-south" + plan = "standard" + service = "event-notifications" + } + + resource "ibm_en_email_template" "en_template_resource_1" { + instance_guid = ibm_resource_instance.en_template_resource.guid + name = "%s" + type = "smtp_custom.notification" + description = "%s" + params { + body = "Go To-Do list

To-Do list for user: {{ Data.issuer.p }}

{{#each Email}}{{/each}}
TaskDone
{{ this }}
" + subject = "HI This is the template test for the invitation" + } + } + `, instanceName, name, description) +} + +func testAccCheckIBMEnEmailTemplateExists(n string, obj en.Template) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return err + } + + options := &en.GetTemplateOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + result, _, err := enClient.GetTemplate(options) + if err != nil { + return err + } + + obj = *result + return nil + } +} + +func testAccCheckIBMEnEmailTemplateDestroy(s *terraform.State) error { + enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "en_destination_resource_1" { + continue + } + + options := &en.GetTemplateOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + // Try to find the key + _, response, err := enClient.GetTemplate(options) + + if err == nil { + return fmt.Errorf("en_destination still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("[ERROR] Error checking for en_destination (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/eventnotification/resource_ibm_en_integration_cos.go b/ibm/service/eventnotification/resource_ibm_en_integration_cos.go new file mode 100644 index 0000000000..662df4ad27 --- /dev/null +++ b/ibm/service/eventnotification/resource_ibm_en_integration_cos.go @@ -0,0 +1,217 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceIBMEnCOSIntegration() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMEnCOSIntegrationCreate, + ReadContext: resourceIBMEnCOSIntegrationRead, + UpdateContext: resourceIBMEnCOSIntegrationUpdate, + DeleteContext: resourceIBMEnCOSIntegrationDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "type": { + Type: schema.TypeString, + Required: true, + Description: "The type of integration is collect_failed_events.", + }, + "metadata": { + Type: schema.TypeList, + MaxItems: 1, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "endpoint": { + Type: schema.TypeString, + Required: true, + Description: "The public or private endpoint for COS bucket", + }, + "crn": { + Type: schema.TypeString, + Required: true, + Description: "The CRN of the Cloud Object Storage instance", + }, + "bucket_name": { + Type: schema.TypeString, + Required: true, + Description: "Cloud Object Storage bucket name", + }, + }, + }, + }, + "integration_id": { + Type: schema.TypeString, + Computed: true, + Description: "Unique identifier for Integration.", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + }, + } +} + +func resourceIBMEnCOSIntegrationCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.CreateIntegrationOptions{} + + options.SetInstanceID(d.Get("instance_guid").(string)) + options.SetType(d.Get("type").(string)) + + if _, ok := d.GetOk("metadata"); ok { + metadata := ReplaceCOSIntegrationMapMetadata(d.Get("metadata.0").(map[string]interface{})) + options.SetMetadata(&metadata) + } + + result, response, err := enClient.CreateIntegrationWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("CreateIntegrationWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *options.InstanceID, *result.ID)) + + return resourceIBMEnCOSIntegrationRead(context, d, meta) +} + +func resourceIBMEnCOSIntegrationRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.GetIntegrationOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + result, response, err := enClient.GetIntegrationWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId(d.Get("integration_id").(string)) + return nil + } + return diag.FromErr(fmt.Errorf("GetIntegrationWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("instance_guid", options.InstanceID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting instance_guid: %s", err)) + } + + if err = d.Set("integration_id", options.ID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error integration_id: %s", err)) + } + if err = d.Set("type", result.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) + } + + if err = d.Set("updated_at", flex.DateTimeToString(result.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + return nil +} + +func resourceIBMEnCOSIntegrationUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.ReplaceIntegrationOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + options.SetType(d.Get("type").(string)) + + if ok := d.HasChanges("metadata"); ok { + + if _, ok := d.GetOk("metadata"); ok { + metadata := ReplaceCOSIntegrationMapMetadataUpdate(d.Get("metadata.0").(map[string]interface{})) + options.SetMetadata(&metadata) + } + + _, response, err := enClient.ReplaceIntegrationWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("ReplaceIntegrationWithContext failed %s\n%s", err, response)) + } + + return resourceIBMEnIntegrationRead(context, d, meta) + } + + return nil +} + +func ReplaceCOSIntegrationMapMetadata(metadataParams map[string]interface{}) en.IntegrationCreateMetadata { + metadataconfigParams := new(en.IntegrationCreateMetadata) + if metadataParams["endpoint"] != nil { + metadataconfigParams.Endpoint = core.StringPtr(metadataParams["endpoint"].(string)) + } + + if metadataParams["crn"] != nil { + metadataconfigParams.CRN = core.StringPtr(metadataParams["crn"].(string)) + } + + if metadataParams["bucket_name"] != nil { + metadataconfigParams.BucketName = core.StringPtr(metadataParams["bucket_name"].(string)) + } + + return *metadataconfigParams +} + +func ReplaceCOSIntegrationMapMetadataUpdate(metadataParams map[string]interface{}) en.IntegrationMetadata { + metadataconfigParams := new(en.IntegrationMetadata) + if metadataParams["endpoint"] != nil { + metadataconfigParams.Endpoint = core.StringPtr(metadataParams["endpoint"].(string)) + } + + if metadataParams["crn"] != nil { + metadataconfigParams.CRN = core.StringPtr(metadataParams["crn"].(string)) + } + + if metadataParams["bucket_name"] != nil { + metadataconfigParams.BucketName = core.StringPtr(metadataParams["bucket_name"].(string)) + } + + return *metadataconfigParams +} + +func resourceIBMEnCOSIntegrationDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + return nil +} diff --git a/ibm/service/eventnotification/resource_ibm_en_integration_cos_test.go b/ibm/service/eventnotification/resource_ibm_en_integration_cos_test.go new file mode 100644 index 0000000000..750da952e7 --- /dev/null +++ b/ibm/service/eventnotification/resource_ibm_en_integration_cos_test.go @@ -0,0 +1,109 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification_test + +import ( + "fmt" + "testing" + + 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" + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" + "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 TestAccIBMEnIntegrationCOSAllArgs(t *testing.T) { + var metadata en.IntegrationGetResponse + instanceName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + // integrationid := fmt.Sprintf("tf_integrationid_%d", acctest.RandIntRange(10, 100)) + // newintegrationid := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMEnSourceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMEnIntegrationCOSConfig(instanceName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMEnIntegrationCOSExists("ibm_en_destination_webhook.en_destination_resource_1", metadata), + resource.TestCheckResourceAttr("ibm_en_integration_cos.en_integration_resource_1", "type", "collect_failed_events"), + ), + }, + { + Config: testAccCheckIBMEnIntegrationCOSConfig(instanceName), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_en_integration_cos.en_integration_resource_1", "type", "collect_failed_events"), + ), + }, + { + ResourceName: "ibm_en_integration.en_integration_resource_1", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMEnIntegrationCOSConfig(instanceName string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "en_integration_resource" { + name = "%s" + location = "us-south" + plan = "standard" + service = "event-notifications" + } + + resource "ibm_en_integration" "en_integration_resource_1" { + instance_guid = ibm_resource_instance.en_destination_resource.guid + type = "collect_failed_events" + metadata { + endpoint = "https://s3.us-west.cloud-object-storage.test.appdomain.cloud", + crn = "crn:v1:bluemix:public:cloud-object-storage:global:a/xxxxxxx6db359a81a1dde8f44bxxxxxx:xxxxxxxx-1d48-xxxx-xxxx-xxxxxxxxxxxx:bucket:cloud-object-storage" + bucket_name = "cloud-object-storage" + } + + } + `, instanceName) +} + +func testAccCheckIBMEnIntegrationCOSExists(n string, obj en.IntegrationGetResponse) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return err + } + + options := &en.GetIntegrationOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + result, _, err := enClient.GetIntegration(options) + if err != nil { + return err + } + + obj = *result + return nil + } +} + +func testAccCheckIBMEnIntegrationCOSDestroy(s *terraform.State) error { + + return nil +} diff --git a/ibm/service/eventnotification/resource_ibm_en_subscription_custom_sms.go b/ibm/service/eventnotification/resource_ibm_en_subscription_custom_sms.go new file mode 100644 index 0000000000..6f86c8ed9e --- /dev/null +++ b/ibm/service/eventnotification/resource_ibm_en_subscription_custom_sms.go @@ -0,0 +1,320 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification + +import ( + "context" + "fmt" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceIBMEnCustomSMSSubscription() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMEnCustomSMSSubscriptionCreate, + ReadContext: resourceIBMEnCustomSMSSubscriptionRead, + UpdateContext: resourceIBMEnCustomSMSSubscriptionUpdate, + DeleteContext: resourceIBMEnCustomSMSSubscriptionDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "instance_guid": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Unique identifier for IBM Cloud Event Notifications instance.", + }, + "name": { + Type: schema.TypeString, + Required: true, + Description: "Subscription name.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Subscription description.", + }, + "destination_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Destination ID.", + }, + "topic_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Topic ID.", + }, + "attributes": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "invited": { + Type: schema.TypeList, + Optional: true, + Description: "The phone number to send the SMS to in case of sms_ibm. The email id in case of smtp_ibm destination type.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "add": { + Type: schema.TypeList, + Optional: true, + Description: "The phone number to add in case of update to send the SMS to in case of sms_ibm.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "remove": { + Type: schema.TypeList, + Optional: true, + Description: "The phone number to remove in case of update to send the SMS to in case of sms_ibm. The email id in case of smtp_ibm destination type.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "subscription_id": { + Type: schema.TypeString, + Computed: true, + Description: "Subscription ID.", + }, + "destination_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of Destination.", + }, + "destination_name": { + Type: schema.TypeString, + Computed: true, + Description: "The Destination name.", + }, + "topic_name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the topic.", + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + Description: "Last updated time.", + }, + }, + } +} + +func resourceIBMEnCustomSMSSubscriptionCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.CreateSubscriptionOptions{} + + options.SetInstanceID(d.Get("instance_guid").(string)) + + options.SetName(d.Get("name").(string)) + options.SetTopicID(d.Get("topic_id").(string)) + options.SetDestinationID(d.Get("destination_id").(string)) + + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + + attributes, _ := CustomSMSattributesMapToAttributes(d.Get("attributes.0").(map[string]interface{})) + options.SetAttributes(&attributes) + + result, response, err := enClient.CreateSubscriptionWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("CreateSubscriptionWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *options.InstanceID, *result.ID)) + + return resourceIBMEnCustomSMSSubscriptionRead(context, d, meta) +} + +func resourceIBMEnCustomSMSSubscriptionRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.GetSubscriptionOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + result, response, err := enClient.GetSubscriptionWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("GetSubscriptionWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("instance_guid", options.InstanceID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting instance_guid: %s", err)) + } + + if err = d.Set("subscription_id", result.ID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting instance_guid: %s", err)) + } + + if err = d.Set("name", result.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if result.Description != nil { + if err = d.Set("description", result.Description); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting description: %s", err)) + } + } + + if result.From != nil { + if err = d.Set("from", result.From); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting from: %s", err)) + } + } + + if err = d.Set("destination_id", result.DestinationID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_id: %s", err)) + } + + // if err = d.Set("destination_type", result.DestinationType); err != nil { + // return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_type: %s", err)) + // } + + if result.DestinationName != nil { + if err = d.Set("destination_name", result.DestinationName); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting destination_name: %s", err)) + } + } + + if err = d.Set("topic_id", result.TopicID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting topic_id: %s", err)) + } + + if result.TopicName != nil { + if err = d.Set("topic_name", result.TopicName); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting topic_name: %s", err)) + } + } + + if err = d.Set("updated_at", result.UpdatedAt); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting updated_at: %s", err)) + } + + return nil +} + +func resourceIBMEnCustomSMSSubscriptionUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.UpdateSubscriptionOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + if ok := d.HasChanges("name", "description", "attributes"); ok { + options.SetName(d.Get("name").(string)) + + if _, ok := d.GetOk("description"); ok { + options.SetDescription(d.Get("description").(string)) + } + + _, attributes := SMSattributesMapToAttributes(d.Get("attributes.0").(map[string]interface{})) + options.SetAttributes(&attributes) + + _, response, err := enClient.UpdateSubscriptionWithContext(context, options) + if err != nil { + return diag.FromErr(fmt.Errorf("UpdateSubscriptionWithContext failed %s\n%s", err, response)) + } + + return resourceIBMEnSMSSubscriptionRead(context, d, meta) + } + + return nil +} + +func resourceIBMEnCustomSMSSubscriptionDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + enClient, err := meta.(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return diag.FromErr(err) + } + + options := &en.DeleteSubscriptionOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + response, err := enClient.DeleteSubscriptionWithContext(context, options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("DeleteSubscriptionWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func CustomSMSattributesMapToAttributes(attributeMap map[string]interface{}) (en.SubscriptionCreateAttributes, en.SubscriptionUpdateAttributesCustomSmsUpdateAttributes) { + attributesCreate := en.SubscriptionCreateAttributes{} + attributesUpdate := en.SubscriptionUpdateAttributesCustomSmsUpdateAttributes{} + + if attributeMap["invited"] != nil { + to := []string{} + for _, toItem := range attributeMap["invited"].([]interface{}) { + to = append(to, toItem.(string)) + } + attributesCreate.Invited = to + + updateTo := new(en.UpdateAttributesInvited) + if attributeMap["add"] != nil { + To := []string{} + for _, updateToitem := range attributeMap["add"].([]interface{}) { + To = append(To, updateToitem.(string)) + } + + updateTo.Add = To + } + if attributeMap["remove"] != nil { + rmsms := []string{} + for _, removeitem := range attributeMap["remove"].([]interface{}) { + rmsms = append(rmsms, removeitem.(string)) + } + + updateTo.Remove = rmsms + } + attributesUpdate.Invited = updateTo + } + + return attributesCreate, attributesUpdate +} diff --git a/ibm/service/eventnotification/resource_ibm_en_subscription_custom_sms_test.go b/ibm/service/eventnotification/resource_ibm_en_subscription_custom_sms_test.go new file mode 100644 index 0000000000..64d4c976f7 --- /dev/null +++ b/ibm/service/eventnotification/resource_ibm_en_subscription_custom_sms_test.go @@ -0,0 +1,160 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package eventnotification_test + +import ( + "fmt" + "testing" + + 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/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + en "github.com/IBM/event-notifications-go-admin-sdk/eventnotificationsv1" +) + +func TestAccIBMEnCustomSMSSubscriptionAllArgs(t *testing.T) { + var conf en.Subscription + instanceName := fmt.Sprintf("tf_instance_%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + description := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + newName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + newDescription := fmt.Sprintf("tf_description_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMEnSMSSubscriptionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMEnCustomSMSSubscriptionConfig(instanceName, name, description), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMEnCustomSMSSubscriptionExists("ibm_en_subscription_custom_sms.en_subscription_resource_1", conf), + resource.TestCheckResourceAttrSet("ibm_en_subscription_custom_sms.en_subscription_resource_1", "name"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_custom_sms.en_subscription_resource_1", "description"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_custom_sms.en_subscription_resource_1", "topic_id"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_custom_sms.en_subscription_resource_1", "updated_at"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_custom_sms.en_subscription_resource_1", "instance_guid"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_custom_sms.en_subscription_resource_1", "destination_id"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_custom_sms.en_subscription_resource_1", "destination_type"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_custom_sms.en_subscription_resource_1", "subscription_id"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_custom_sms.en_subscription_resource_1", "attributes.#"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_custom_sms.en_subscription_resource_1", "attributes.0.invited"), + ), + }, + { + Config: testAccCheckIBMEnCustomSMSSubscriptionConfig(instanceName, newName, newDescription), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_en_subscription_custom_sms.en_subscription_resource_1", "name", newName), + resource.TestCheckResourceAttr("ibm_en_subscription_custom_sms.en_subscription_resource_1", "description", newDescription), + ), + }, + { + ResourceName: "ibm_en_subscription_custom_sms.en_subscription_resource_1", + ImportState: true, + ImportStateVerify: false, + }, + }, + }) +} + +func testAccCheckIBMEnCustomSMSSubscriptionConfig(instanceName, name, description string) string { + return fmt.Sprintf(` + resource "ibm_resource_instance" "en_subscription_resource" { + name = "%s" + location = "us-south" + plan = "standard" + service = "event-notifications" + } + + resource "ibm_en_topic" "en_topic_resource_2" { + instance_guid = ibm_resource_instance.en_subscription_resource.guid + name = "tf_topic_name_0234" + description = "tf_topic_description_0235" + } + + + resource "ibm_en_subscription_custom_sms" "en_subscription_resource_1" { + name = "%s" + description = "%s" + instance_guid = ibm_resource_instance.en_subscription_resource.guid + topic_id = ibm_en_topic.en_topic_resource_2.topic_id + destination_id = "set sms destination id" + attributes { + invited = ["+16382922821", "+18976569023"] + } + } + `, instanceName, name, description) +} + +func testAccCheckIBMEnCustomSMSSubscriptionExists(n string, obj en.Subscription) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return err + } + + options := &en.GetSubscriptionOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + subscription, _, err := enClient.GetSubscription(options) + if err != nil { + return err + } + + obj = *subscription + return nil + } +} + +func testAccCheckIBMEnCustomSMSSubscriptionDestroy(s *terraform.State) error { + enClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).EventNotificationsApiV1() + if err != nil { + return err + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "en_subscription_resource_1" { + continue + } + + options := &en.GetSubscriptionOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + options.SetInstanceID(parts[0]) + options.SetID(parts[1]) + + // Try to find the key + _, response, err := enClient.GetSubscription(options) + + if err == nil { + return fmt.Errorf("en_subscription still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("[ERROR] Error checking for en_subscription (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/eventnotification/resource_ibm_en_subscription_sms_test.go b/ibm/service/eventnotification/resource_ibm_en_subscription_sms_test.go index f0fba2bae0..4bb0c28e37 100644 --- a/ibm/service/eventnotification/resource_ibm_en_subscription_sms_test.go +++ b/ibm/service/eventnotification/resource_ibm_en_subscription_sms_test.go @@ -44,7 +44,7 @@ func TestAccIBMEnSMSSubscriptionAllArgs(t *testing.T) { resource.TestCheckResourceAttrSet("ibm_en_subscription_sms.en_subscription_resource_1", "destination_type"), resource.TestCheckResourceAttrSet("ibm_en_subscription_sms.en_subscription_resource_1", "subscription_id"), resource.TestCheckResourceAttrSet("ibm_en_subscription_sms.en_subscription_resource_1", "attributes.#"), - resource.TestCheckResourceAttrSet("ibm_en_subscription_sms.en_subscription_resource_1", "attributes.0.to"), + resource.TestCheckResourceAttrSet("ibm_en_subscription_sms.en_subscription_resource_1", "attributes.0.invited"), ), }, { @@ -86,7 +86,7 @@ func testAccCheckIBMEnSMSSubscriptionConfig(instanceName, name, description stri topic_id = ibm_en_topic.en_topic_resource_2.topic_id destination_id = "set sms destination id" attributes { - to = ["+16382922821", "+18976569023"] + invited = ["+16382922821", "+18976569023"] } } `, instanceName, name, description) diff --git a/ibm/service/iampolicy/data_source_ibm_iam_authorization_policies_test.go b/ibm/service/iampolicy/data_source_ibm_iam_authorization_policies_test.go index 213b185ac1..b33893b921 100644 --- a/ibm/service/iampolicy/data_source_ibm_iam_authorization_policies_test.go +++ b/ibm/service/iampolicy/data_source_ibm_iam_authorization_policies_test.go @@ -73,8 +73,8 @@ func testAccCheckIBMIAMAuthorizationPoliciesDataSourceMultiplePolicies() string resource "ibm_iam_authorization_policy" "policy1" { source_service_name = "is" source_resource_type = "load-balancer" - target_service_name = "cloudcerts" - roles = ["Reader"] + target_service_name = "secrets-manager" + roles = ["SecretsReader"] } ` } diff --git a/ibm/service/iampolicy/resource_ibm_iam_access_group_policy.go b/ibm/service/iampolicy/resource_ibm_iam_access_group_policy.go index 5bfcaf2be9..5dda95b0ab 100644 --- a/ibm/service/iampolicy/resource_ibm_iam_access_group_policy.go +++ b/ibm/service/iampolicy/resource_ibm_iam_access_group_policy.go @@ -481,9 +481,9 @@ func resourceIBMIAMAccessGroupPolicyRead(d *schema.ResourceData, meta interface{ return fmt.Errorf("[ERROR] Error retrieving access group policy: %s\n%s", err, res) } - retrievedAttribute := flex.GetV2PolicySubjectAttribute("access_group_id", *accessGroupPolicy.Subject) - if accessGroupId != *retrievedAttribute { - return fmt.Errorf("[ERROR] Policy %s does not belong to access group %s, retrievedAttr: %s", accessGroupPolicyId, accessGroupId, *retrievedAttribute) + retrievedAttribute := flex.GetV2PolicySubjectAttribute("access_group_id", *accessGroupPolicy.Subject).(string) + if accessGroupId != retrievedAttribute { + return fmt.Errorf("[ERROR] Policy %s does not belong to access group %s, retrievedAttr: %s", accessGroupPolicyId, accessGroupId, retrievedAttribute) } d.Set("access_group_id", accessGroupId) @@ -770,7 +770,7 @@ func resourceIBMIAMAccessGroupPolicyExists(d *schema.ResourceData, meta interfac return false, nil } - tempID := fmt.Sprintf("%s/%s", *flex.GetV2PolicySubjectAttribute("access_group_id", *accessGroupPolicy.Subject), *accessGroupPolicy.ID) + tempID := fmt.Sprintf("%s/%s", flex.GetV2PolicySubjectAttribute("access_group_id", *accessGroupPolicy.Subject), *accessGroupPolicy.ID) return tempID == d.Id(), nil } diff --git a/ibm/service/iampolicy/resource_ibm_iam_access_group_policy_test.go b/ibm/service/iampolicy/resource_ibm_iam_access_group_policy_test.go index 2e3d5e70e9..1a5fd21c76 100644 --- a/ibm/service/iampolicy/resource_ibm_iam_access_group_policy_test.go +++ b/ibm/service/iampolicy/resource_ibm_iam_access_group_policy_test.go @@ -544,6 +544,27 @@ func TestAccIBMIAMAccessGroupPolicy_With_Attribute_Based_Condition(t *testing.T) }) } +func TestAccIBMIAMAccessGroupPolicy_StringMatch_Without_Wildcard(t *testing.T) { + var conf iampolicymanagementv1.V2PolicyTemplateMetaData + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMAccessGroupPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMAccessGroupStringMatchWithoutWildcard(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMAccessGroupPolicyExists("ibm_iam_access_group_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_access_group.accgrp", "name", name), + resource.TestCheckResourceAttr("ibm_iam_access_group_policy.policy", "resource_attributes.#", "2"), + ), + }, + }, + }) +} + func testAccCheckIBMIAMAccessGroupPolicyDestroy(s *terraform.State) error { iamPolicyManagementClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).IAMPolicyManagementV1API() if err != nil { @@ -1291,3 +1312,25 @@ func testAccCheckIBMIAMAccessGroupPolicyUpdateAttributeBasedCondition(name strin } `, name) } + +func testAccCheckIBMIAMAccessGroupStringMatchWithoutWildcard(name string) string { + return fmt.Sprintf(` + resource "ibm_iam_access_group" "accgrp" { + name = "%s" + } + + resource "ibm_iam_access_group_policy" "policy" { + access_group_id = ibm_iam_access_group.accgrp.id + roles = ["Viewer"] + resource_attributes { + name = "resource" + value = "test" + operator = "stringMatch" + } + resource_attributes { + name = "serviceName" + value = "messagehub" + } + } + `, name) +} diff --git a/ibm/service/iampolicy/resource_ibm_iam_authorization_policy.go b/ibm/service/iampolicy/resource_ibm_iam_authorization_policy.go index c1facb1f30..3a43380ff0 100644 --- a/ibm/service/iampolicy/resource_ibm_iam_authorization_policy.go +++ b/ibm/service/iampolicy/resource_ibm_iam_authorization_policy.go @@ -139,6 +139,11 @@ func ResourceIBMIAMAuthorizationPolicy() *schema.Resource { Required: true, Description: "Value of attribute.", }, + "operator": { + Type: schema.TypeString, + Optional: true, + Description: "Operator of attribute.", + }, }, }, }, @@ -219,8 +224,8 @@ func resourceIBMIAMAuthorizationPolicyCreate(d *schema.ResourceData, meta interf var sourceServiceName, targetServiceName string policyType := "authorization" - policySubject := &iampolicymanagementv1.PolicySubject{} - policyResource := &iampolicymanagementv1.PolicyResource{} + policySubject := &iampolicymanagementv1.V2PolicySubject{} + policyResource := &iampolicymanagementv1.V2PolicyResource{} userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() if err != nil { @@ -238,23 +243,54 @@ func resourceIBMIAMAuthorizationPolicyCreate(d *schema.ResourceData, meta interf a := attribute.(map[string]interface{}) name := a["name"].(string) value := a["value"].(string) + operator := a["operator"].(string) if name == "serviceName" { sourceServiceName = value } - at := iampolicymanagementv1.SubjectAttribute{ - Name: &name, - Value: &value, + + if operator == "" && value == "*" && name == "resourceGroupId" { + at := iampolicymanagementv1.V2PolicySubjectAttribute{ + Key: &name, + Value: true, + Operator: core.StringPtr("stringExists"), + } + policySubject.Attributes = append(policySubject.Attributes, at) + } else if operator == "stringExists" { + var resourceValue bool + if value == "true" { + resourceValue = true + } else if value == "false" { + resourceValue = false + } else { + return fmt.Errorf("[ERROR] Only values \"true\" and \"false\" are allowed when operator is \"stringExists\". Received %s.", value) + } + at := iampolicymanagementv1.V2PolicySubjectAttribute{ + Key: &name, + Value: &resourceValue, + Operator: &operator, + } + policySubject.Attributes = append(policySubject.Attributes, at) + } else { + if operator == "" { + operator = "stringEquals" + } + at := iampolicymanagementv1.V2PolicySubjectAttribute{ + Key: &name, + Value: &value, + Operator: &operator, + } + policySubject.Attributes = append(policySubject.Attributes, at) } - policySubject.Attributes = append(policySubject.Attributes, at) } } else { if name, ok := d.GetOk("source_service_name"); ok { sourceServiceName = name.(string) - serviceNameSubjectAttribute := &iampolicymanagementv1.SubjectAttribute{ - Name: core.StringPtr("serviceName"), - Value: &sourceServiceName, + serviceNameSubjectAttribute := &iampolicymanagementv1.V2PolicySubjectAttribute{ + Key: core.StringPtr("serviceName"), + Value: &sourceServiceName, + Operator: core.StringPtr("stringEquals"), } policySubject.Attributes = append(policySubject.Attributes, *serviceNameSubjectAttribute) } @@ -264,35 +300,48 @@ func resourceIBMIAMAuthorizationPolicyCreate(d *schema.ResourceData, meta interf sourceServiceAccount = account.(string) } - accountIdSubjectAttribute := &iampolicymanagementv1.SubjectAttribute{ - Name: core.StringPtr("accountId"), - Value: &sourceServiceAccount, + accountIdSubjectAttribute := &iampolicymanagementv1.V2PolicySubjectAttribute{ + Key: core.StringPtr("accountId"), + Value: &sourceServiceAccount, + Operator: core.StringPtr("stringEquals"), } policySubject.Attributes = append(policySubject.Attributes, *accountIdSubjectAttribute) if sID, ok := d.GetOk("source_resource_instance_id"); ok { - serviceInstanceSubjectAttribute := iampolicymanagementv1.SubjectAttribute{ - Name: core.StringPtr("serviceInstance"), - Value: core.StringPtr(sID.(string)), + serviceInstanceSubjectAttribute := iampolicymanagementv1.V2PolicySubjectAttribute{ + Key: core.StringPtr("serviceInstance"), + Value: core.StringPtr(sID.(string)), + Operator: core.StringPtr("stringEquals"), } policySubject.Attributes = append(policySubject.Attributes, serviceInstanceSubjectAttribute) } if sType, ok := d.GetOk("source_resource_type"); ok { - resourceTypeSubjectAttribute := iampolicymanagementv1.SubjectAttribute{ - Name: core.StringPtr("resourceType"), - Value: core.StringPtr(sType.(string)), + resourceTypeSubjectAttribute := iampolicymanagementv1.V2PolicySubjectAttribute{ + Key: core.StringPtr("resourceType"), + Value: core.StringPtr(sType.(string)), + Operator: core.StringPtr("stringEquals"), } policySubject.Attributes = append(policySubject.Attributes, resourceTypeSubjectAttribute) } if sResGrpID, ok := d.GetOk("source_resource_group_id"); ok { - resourceGroupSubjectAttribute := iampolicymanagementv1.SubjectAttribute{ - Name: core.StringPtr("resourceGroupId"), - Value: core.StringPtr(sResGrpID.(string)), + if sResGrpID == "*" { + resourceGroupSubjectAttribute := iampolicymanagementv1.V2PolicySubjectAttribute{ + Key: core.StringPtr("resourceGroupId"), + Value: true, + Operator: core.StringPtr("stringExists"), + } + policySubject.Attributes = append(policySubject.Attributes, resourceGroupSubjectAttribute) + } else { + resourceGroupSubjectAttribute := iampolicymanagementv1.V2PolicySubjectAttribute{ + Key: core.StringPtr("resourceGroupId"), + Value: core.StringPtr(sResGrpID.(string)), + Operator: core.StringPtr("stringEquals"), + } + policySubject.Attributes = append(policySubject.Attributes, resourceGroupSubjectAttribute) } - policySubject.Attributes = append(policySubject.Attributes, resourceGroupSubjectAttribute) } } @@ -309,26 +358,43 @@ func resourceIBMIAMAuthorizationPolicyCreate(d *schema.ResourceData, meta interf if name == "resourceType" && targetServiceName == "" { targetServiceName = "resource-controller" } - at := iampolicymanagementv1.ResourceAttribute{ - Name: &name, - Value: &value, - Operator: &operator, + if operator == "stringExists" { + var resourceValue bool + if value == "true" { + resourceValue = true + } else if value == "false" { + resourceValue = false + } else { + return fmt.Errorf("[ERROR] When operator equals stringExists, value should be either \"true\" or \"false\", instead of %s", value) + } + at := iampolicymanagementv1.V2PolicyResourceAttribute{ + Key: &name, + Value: &resourceValue, + Operator: &operator, + } + policyResource.Attributes = append(policyResource.Attributes, at) + } else { + at := iampolicymanagementv1.V2PolicyResourceAttribute{ + Key: &name, + Value: &value, + Operator: &operator, + } + policyResource.Attributes = append(policyResource.Attributes, at) } - policyResource.Attributes = append(policyResource.Attributes, at) } } else { if name, ok := d.GetOk("target_service_name"); ok { targetServiceName = name.(string) - serviceNameResourceAttribute := &iampolicymanagementv1.ResourceAttribute{ - Name: core.StringPtr("serviceName"), + serviceNameResourceAttribute := &iampolicymanagementv1.V2PolicyResourceAttribute{ + Key: core.StringPtr("serviceName"), Value: core.StringPtr(targetServiceName), Operator: core.StringPtr("stringEquals"), } policyResource.Attributes = append(policyResource.Attributes, *serviceNameResourceAttribute) } - accountIDResourceAttribute := &iampolicymanagementv1.ResourceAttribute{ - Name: core.StringPtr("accountId"), + accountIDResourceAttribute := &iampolicymanagementv1.V2PolicyResourceAttribute{ + Key: core.StringPtr("accountId"), Value: core.StringPtr(userDetails.UserAccount), Operator: core.StringPtr("stringEquals"), } @@ -336,17 +402,19 @@ func resourceIBMIAMAuthorizationPolicyCreate(d *schema.ResourceData, meta interf policyResource.Attributes = append(policyResource.Attributes, *accountIDResourceAttribute) if tID, ok := d.GetOk("target_resource_instance_id"); ok { - serviceInstanceResourceAttribute := iampolicymanagementv1.ResourceAttribute{ - Name: core.StringPtr("serviceInstance"), - Value: core.StringPtr(tID.(string)), + serviceInstanceResourceAttribute := iampolicymanagementv1.V2PolicyResourceAttribute{ + Key: core.StringPtr("serviceInstance"), + Value: core.StringPtr(tID.(string)), + Operator: core.StringPtr("stringEquals"), } policyResource.Attributes = append(policyResource.Attributes, serviceInstanceResourceAttribute) } if tType, ok := d.GetOk("target_resource_type"); ok { - resourceTypeResourceAttribute := iampolicymanagementv1.ResourceAttribute{ - Name: core.StringPtr("resourceType"), - Value: core.StringPtr(tType.(string)), + resourceTypeResourceAttribute := iampolicymanagementv1.V2PolicyResourceAttribute{ + Key: core.StringPtr("resourceType"), + Value: core.StringPtr(tType.(string)), + Operator: core.StringPtr("stringEquals"), } policyResource.Attributes = append(policyResource.Attributes, resourceTypeResourceAttribute) if targetServiceName == "" { @@ -355,9 +423,10 @@ func resourceIBMIAMAuthorizationPolicyCreate(d *schema.ResourceData, meta interf } if tResGrpID, ok := d.GetOk("target_resource_group_id"); ok { - resourceGroupResourceAttribute := iampolicymanagementv1.ResourceAttribute{ - Name: core.StringPtr("resourceGroupId"), - Value: core.StringPtr(tResGrpID.(string)), + resourceGroupResourceAttribute := iampolicymanagementv1.V2PolicyResourceAttribute{ + Key: core.StringPtr("resourceGroupId"), + Value: core.StringPtr(tResGrpID.(string)), + Operator: core.StringPtr("stringEquals"), } policyResource.Attributes = append(policyResource.Attributes, resourceGroupResourceAttribute) } @@ -381,13 +450,21 @@ func resourceIBMIAMAuthorizationPolicyCreate(d *schema.ResourceData, meta interf return err } - createPolicyOptions := iampapClient.NewCreatePolicyOptions( + policyGrant := &iampolicymanagementv1.Grant{ + Roles: flex.MapPolicyRolesToRoles(roles), + } + policyControl := &iampolicymanagementv1.Control{ + Grant: policyGrant, + } + + createPolicyOptions := iampapClient.NewCreateV2PolicyOptions( + policyControl, "authorization", - []iampolicymanagementv1.PolicySubject{*policySubject}, - roles, - []iampolicymanagementv1.PolicyResource{*policyResource}, ) + createPolicyOptions.SetSubject(policySubject) + createPolicyOptions.SetResource(policyResource) + if description, ok := d.GetOk("description"); ok { des := description.(string) createPolicyOptions.Description = &des @@ -397,7 +474,7 @@ func resourceIBMIAMAuthorizationPolicyCreate(d *schema.ResourceData, meta interf createPolicyOptions.SetHeaders(map[string]string{"Transaction-Id": transactionID.(string)}) } - authPolicy, resp, err := iampapClient.CreatePolicy(createPolicyOptions) + authPolicy, resp, err := iampapClient.CreateV2Policy(createPolicyOptions) if err != nil { return fmt.Errorf("[ERROR] Error creating authorization policy: %s %s", err, resp) } @@ -414,19 +491,19 @@ func resourceIBMIAMAuthorizationPolicyRead(d *schema.ResourceData, meta interfac return err } - getPolicyOptions := &iampolicymanagementv1.GetPolicyOptions{ - PolicyID: core.StringPtr(d.Id()), + getPolicyOptions := &iampolicymanagementv1.GetV2PolicyOptions{ + ID: core.StringPtr(d.Id()), } if transactionID, ok := d.GetOk("transaction_id"); ok { getPolicyOptions.SetHeaders(map[string]string{"Transaction-Id": transactionID.(string)}) } - authorizationPolicy, resp, err := iampapClient.GetPolicy(getPolicyOptions) + authorizationPolicy, resp, err := iampapClient.GetV2Policy(getPolicyOptions) err = resource.Retry(5*time.Minute, func() *resource.RetryError { var err error - authorizationPolicy, resp, err = iampapClient.GetPolicy(getPolicyOptions) + authorizationPolicy, resp, err = iampapClient.GetV2Policy(getPolicyOptions) if err != nil || authorizationPolicy == nil { if resp != nil && resp.StatusCode == 404 { return resource.RetryableError(err) @@ -437,15 +514,12 @@ func resourceIBMIAMAuthorizationPolicyRead(d *schema.ResourceData, meta interfac }) if conns.IsResourceTimeoutError(err) { - authorizationPolicy, resp, err = iampapClient.GetPolicy(getPolicyOptions) + authorizationPolicy, resp, err = iampapClient.GetV2Policy(getPolicyOptions) } if err != nil || resp == nil { return fmt.Errorf("[ERROR] Error retrieving authorizationPolicy: %s %s", err, resp) } - roles := make([]string, len(authorizationPolicy.Roles)) - for i, role := range authorizationPolicy.Roles { - roles[i] = *role.DisplayName - } + roles, err := flex.GetRoleNamesFromPolicyResponse(*authorizationPolicy, d, meta) if authorizationPolicy.Description != nil { d.Set("description", *authorizationPolicy.Description) } @@ -453,21 +527,22 @@ func resourceIBMIAMAuthorizationPolicyRead(d *schema.ResourceData, meta interfac d.Set("transaction_id", resp.Headers["Transaction-Id"][0]) } d.Set("roles", roles) - source := authorizationPolicy.Subjects[0] - target := authorizationPolicy.Resources[0] - - d.Set("resource_attributes", setAuthorizationResourceAttributes(target)) - d.Set("target_resource_instance_id", flex.GetResourceAttribute("serviceInstance", target)) - d.Set("target_resource_type", flex.GetResourceAttribute("resourceType", target)) - d.Set("target_resource_group_id", flex.GetResourceAttribute("resourceGroupId", target)) - d.Set("target_service_name", flex.GetResourceAttribute("serviceName", target)) - - d.Set("subject_attributes", setAuthorizationSubjectAttributes(source)) - d.Set("source_service_name", flex.GetSubjectAttribute("serviceName", source)) - d.Set("source_resource_instance_id", flex.GetSubjectAttribute("serviceInstance", source)) - d.Set("source_resource_type", flex.GetSubjectAttribute("resourceType", source)) - d.Set("source_service_account", flex.GetSubjectAttribute("accountId", source)) - d.Set("source_resource_group_id", flex.GetSubjectAttribute("resourceGroupId", source)) + source := authorizationPolicy.Subject + target := authorizationPolicy.Resource + + d.Set("resource_attributes", setAuthorizationResourceAttributes(*target)) + d.Set("target_resource_instance_id", flex.GetV2PolicyResourceAttribute("serviceInstance", *target)) + d.Set("target_resource_type", flex.GetV2PolicyResourceAttribute("resourceType", *target)) + d.Set("target_resource_group_id", flex.GetV2PolicyResourceAttribute("resourceGroupId", *target)) + d.Set("target_service_name", flex.GetV2PolicyResourceAttribute("serviceName", *target)) + if a, ok := d.GetOk("subject_attributes"); ok { + d.Set("subject_attributes", setAuthorizationSubjectAttributes(*source, a.(*schema.Set))) + } + d.Set("source_service_name", flex.GetV2PolicySubjectAttribute("serviceName", *source)) + d.Set("source_resource_instance_id", flex.GetV2PolicySubjectAttribute("serviceInstance", *source)) + d.Set("source_resource_type", flex.GetV2PolicySubjectAttribute("resourceType", *source)) + d.Set("source_service_account", flex.GetV2PolicySubjectAttribute("accountId", *source)) + d.Set("source_resource_group_id", flex.GetV2PolicySubjectAttribute("resourceGroupId", *source)) return nil } @@ -528,12 +603,12 @@ func resourceIBMIAMAuthorizationPolicyExists(d *schema.ResourceData, meta interf return *authorizationPolicy.ID == d.Id(), nil } -func setAuthorizationResourceAttributes(list iampolicymanagementv1.PolicyResource) []map[string]interface{} { +func setAuthorizationResourceAttributes(list iampolicymanagementv1.V2PolicyResource) []map[string]interface{} { result := make([]map[string]interface{}, 0) for _, attribute := range list.Attributes { l := map[string]interface{}{ - "name": attribute.Name, - "value": attribute.Value, + "name": attribute.Key, + "value": fmt.Sprintf("%v", attribute.Value), "operator": attribute.Operator, } result = append(result, l) @@ -541,12 +616,34 @@ func setAuthorizationResourceAttributes(list iampolicymanagementv1.PolicyResourc return result } -func setAuthorizationSubjectAttributes(list iampolicymanagementv1.PolicySubject) []map[string]interface{} { +func setAuthorizationSubjectAttributes(list iampolicymanagementv1.V2PolicySubject, a *schema.Set) []map[string]interface{} { + previousOperators := make([]string, 0) + + for _, item := range a.List() { + i := item.(map[string]interface{}) + + previousOperators = append(previousOperators, i["operator"].(string)) + } + result := make([]map[string]interface{}, 0) - for _, attribute := range list.Attributes { - l := map[string]interface{}{ - "name": attribute.Name, - "value": attribute.Value, + for i, attribute := range list.Attributes { + var l map[string]interface{} + if previousOperators[i] == "" && attribute.Value == true && *attribute.Operator == "stringExists" { + l = map[string]interface{}{ + "name": attribute.Key, + "value": "*", + } + } else if previousOperators[i] == "" { + l = map[string]interface{}{ + "name": attribute.Key, + "value": fmt.Sprintf("%v", attribute.Value), + } + } else { + l = map[string]interface{}{ + "name": attribute.Key, + "value": fmt.Sprintf("%v", attribute.Value), + "operator": attribute.Operator, + } } result = append(result, l) } diff --git a/ibm/service/iampolicy/resource_ibm_iam_authorization_policy_test.go b/ibm/service/iampolicy/resource_ibm_iam_authorization_policy_test.go index fe5b7436ca..d6a62efaa7 100644 --- a/ibm/service/iampolicy/resource_ibm_iam_authorization_policy_test.go +++ b/ibm/service/iampolicy/resource_ibm_iam_authorization_policy_test.go @@ -107,7 +107,7 @@ func TestAccIBMIAMAuthorizationPolicy_ResourceType(t *testing.T) { testAccCheckIBMIAMAuthorizationPolicyExists("ibm_iam_authorization_policy.policy", conf), resource.TestCheckResourceAttr("ibm_iam_authorization_policy.policy", "source_service_name", "is"), resource.TestCheckResourceAttr("ibm_iam_authorization_policy.policy", "source_resource_type", "load-balancer"), - resource.TestCheckResourceAttr("ibm_iam_authorization_policy.policy", "target_service_name", "hs-crypto"), + resource.TestCheckResourceAttr("ibm_iam_authorization_policy.policy", "target_service_name", "secrets-manager"), ), }, }, @@ -202,6 +202,27 @@ func TestAccIBMIAMAuthorizationPolicy_SourceResourceGroupId_ResourceAttributes(t }) } +func TestAccIBMIAMAuthorizationPolicy_SourceResourceGroupId_ResourceAttributes_WildCard(t *testing.T) { + var conf iampolicymanagementv1.PolicyTemplateMetaData + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMAuthorizationPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMAuthorizationPolicySourceResourceGroupIdResourceAttributesWildCard(acc.Tg_cross_network_account_id, acc.Tg_cross_network_account_id), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMAuthorizationPolicyExists("ibm_iam_authorization_policy.policy", conf), + resource.TestCheckResourceAttrSet("ibm_iam_authorization_policy.policy", "id"), + resource.TestCheckResourceAttr("ibm_iam_authorization_policy.policy", "source_service_name", ""), + resource.TestCheckResourceAttr("ibm_iam_authorization_policy.policy", "target_service_name", "cloud-object-storage"), + ), + }, + }, + }) +} + func TestAccIBMIAMAuthorizationPolicy_TargetResourceType(t *testing.T) { var conf iampolicymanagementv1.PolicyTemplateMetaData @@ -265,6 +286,25 @@ func TestAccIBMIAMAuthorizationPolicy_With_Transaction_id(t *testing.T) { }) } +func TestAccIBMIAMAuthorizationPolicy_SourceResourceGroupIdWithStringExistsInSubjectAttributes(t *testing.T) { + var conf iampolicymanagementv1.PolicyTemplateMetaData + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMAuthorizationPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMAuthorizationPolicySourceResourceGroupIdWithStringExistsInSubjectAttributes(acc.Tg_cross_network_account_id, acc.Tg_cross_network_account_id), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMAuthorizationPolicyExists("ibm_iam_authorization_policy.policy", conf), + resource.TestCheckResourceAttrSet("ibm_iam_authorization_policy.policy", "id"), + ), + }, + }, + }) +} + func testAccCheckIBMIAMAuthorizationPolicyDestroy(s *terraform.State) error { iamPolicyManagementClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).IAMPolicyManagementV1API() if err != nil { @@ -350,9 +390,9 @@ func testAccCheckIBMIAMAuthorizationPolicyResourceInstance(instanceName string) resource "ibm_iam_authorization_policy" "policy" { source_service_name = "cloud-object-storage" - source_resource_instance_id = ibm_resource_instance.instance1.id + source_resource_instance_id = ibm_resource_instance.instance1.guid target_service_name = "kms" - target_resource_instance_id = ibm_resource_instance.instance2.id + target_resource_instance_id = ibm_resource_instance.instance2.guid roles = ["Reader"] } @@ -364,8 +404,8 @@ func testAccCheckIBMIAMAuthorizationPolicyResourceType() string { resource "ibm_iam_authorization_policy" "policy" { source_service_name = "is" source_resource_type = "load-balancer" - target_service_name = "hs-crypto" - roles = ["Reader"] + target_service_name = "secrets-manager" + roles = ["SecretsReader"] } ` } @@ -426,7 +466,7 @@ func testAccCheckIBMIAMAuthorizationPolicyResourceAttributes(sServiceInstance, t } subject_attributes { name = "serviceInstance" - value = ibm_resource_instance.cos.id + value = ibm_resource_instance.cos.guid } subject_attributes { name = "serviceName" @@ -442,7 +482,7 @@ func testAccCheckIBMIAMAuthorizationPolicyResourceAttributes(sServiceInstance, t } resource_attributes { name = "serviceInstance" - value = ibm_resource_instance.kms.id + value = ibm_resource_instance.kms.guid } } `, sServiceInstance, tServiceInstance, sAccountID, tAccountID) @@ -497,6 +537,31 @@ func testAccCheckIBMIAMAuthorizationPolicySourceResourceGroupIdResourceAttribute `, sAccountID, tAccountID) } +func testAccCheckIBMIAMAuthorizationPolicySourceResourceGroupIdResourceAttributesWildCard(sAccountID, tAccountID string) string { + return fmt.Sprintf(` + resource "ibm_iam_authorization_policy" "policy" { + roles = ["Reader"] + subject_attributes { + name = "accountId" + value = "%s" + } + subject_attributes { + name = "resourceGroupId" + value = "*" + } + + resource_attributes { + name = "serviceName" + value = "cloud-object-storage" + } + resource_attributes { + name = "accountId" + value = "%s" + } + } + `, sAccountID, tAccountID) +} + func testAccCheckIBMIAMAuthorizationPolicyTargetResourceType() string { return ` resource "ibm_iam_authorization_policy" "policy" { @@ -534,3 +599,29 @@ func testAccCheckIBMIAMAuthorizationPolicyResourceTypeAndResourceAttributes(sAcc } `, sAccountID, tAccountID) } + +func testAccCheckIBMIAMAuthorizationPolicySourceResourceGroupIdWithStringExistsInSubjectAttributes(sAccountID, tAccountID string) string { + return fmt.Sprintf(` + resource "ibm_iam_authorization_policy" "policy" { + roles = ["Reader"] + subject_attributes { + name = "accountId" + value = "%s" + } + subject_attributes { + name = "resourceGroupId" + operator = "stringExists" + value = "true" + } + + resource_attributes { + name = "serviceName" + value = "cloud-object-storage" + } + resource_attributes { + name = "accountId" + value = "%s" + } + } + `, sAccountID, tAccountID) +} diff --git a/ibm/service/iampolicy/resource_ibm_iam_service_policy_test.go b/ibm/service/iampolicy/resource_ibm_iam_service_policy_test.go index 93bdf6ddb6..130677ad47 100644 --- a/ibm/service/iampolicy/resource_ibm_iam_service_policy_test.go +++ b/ibm/service/iampolicy/resource_ibm_iam_service_policy_test.go @@ -505,6 +505,27 @@ func TestAccIBMIAMServicePolicy_With_Attribute_Based_Condition(t *testing.T) { }) } +func TestAccIBMIAMServicePolicy_With_Resource_Attributes_Without_Wildcard(t *testing.T) { + var conf iampolicymanagementv1.V2PolicyTemplateMetaData + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMServicePolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMServicePolicyResourceAttributesWithoutWildcard(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMServicePolicyExists("ibm_iam_service_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_service_id.serviceID", "name", name), + resource.TestCheckResourceAttr("ibm_iam_service_policy.policy", "resource_attributes.#", "2"), + ), + }, + }, + }) +} + func testAccCheckIBMIAMServicePolicyDestroy(s *terraform.State) error { rsContClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).IAMPolicyManagementV1API() if err != nil { @@ -1238,3 +1259,25 @@ func testAccCheckIBMIAMServicePolicyUpdateAttributeBasedCondition(name string) s } `, name) } + +func testAccCheckIBMIAMServicePolicyResourceAttributesWithoutWildcard(name string) string { + return fmt.Sprintf(` + resource "ibm_iam_service_id" "serviceID" { + name = "%s" + } + + resource "ibm_iam_service_policy" "policy" { + iam_service_id = ibm_iam_service_id.serviceID.id + roles = ["Viewer"] + resource_attributes { + name = "resource" + value = "test" + operator = "stringMatch" + } + resource_attributes { + name = "serviceName" + value = "messagehub" + } + } + `, name) +} diff --git a/ibm/service/iampolicy/resource_ibm_iam_trusted_profile_policy_test.go b/ibm/service/iampolicy/resource_ibm_iam_trusted_profile_policy_test.go index ba0d80e5f7..d973a6df24 100644 --- a/ibm/service/iampolicy/resource_ibm_iam_trusted_profile_policy_test.go +++ b/ibm/service/iampolicy/resource_ibm_iam_trusted_profile_policy_test.go @@ -271,6 +271,27 @@ func TestAccIBMIAMTrustedProfilePolicy_With_Resource_Attributes(t *testing.T) { }) } +func TestAccIBMIAMTrustedProfilePolicy_With_Resource_Attributes_Without_Wildcard(t *testing.T) { + var conf iampolicymanagementv1.V2PolicyTemplateMetaData + name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMTrustedProfilePolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMTrustedProfilePolicyResourceAttributesWithoutWildcard(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMTrustedProfilePolicyExists("ibm_iam_trusted_profile_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile.profileID", "name", name), + resource.TestCheckResourceAttr("ibm_iam_trusted_profile_policy.policy", "resource_attributes.#", "2"), + ), + }, + }, + }) +} + func TestAccIBMIAMTrustedProfilePolicy_With_Resource_Tags(t *testing.T) { var conf iampolicymanagementv1.V2PolicyTemplateMetaData name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) @@ -807,6 +828,29 @@ func testAccCheckIBMIAMTrustedProfilePolicyResourceAttributes(name string) strin } `, name) } + +func testAccCheckIBMIAMTrustedProfilePolicyResourceAttributesWithoutWildcard(name string) string { + return fmt.Sprintf(` + resource "ibm_iam_trusted_profile" "profileID" { + name = "%s" + } + + resource "ibm_iam_trusted_profile_policy" "policy" { + profile_id = ibm_iam_trusted_profile.profileID.id + roles = ["Viewer"] + resource_attributes { + name = "resource" + value = "test" + operator = "stringMatch" + } + resource_attributes { + name = "serviceName" + value = "messagehub" + } + } + `, name) +} + func testAccCheckIBMIAMTrustedProfilePolicyResourceAttributesUpdate(name string) string { return fmt.Sprintf(` resource "ibm_iam_trusted_profile" "profileID" { diff --git a/ibm/service/iampolicy/resource_ibm_iam_user_policy_test.go b/ibm/service/iampolicy/resource_ibm_iam_user_policy_test.go index 46be011f8e..91b62395a5 100644 --- a/ibm/service/iampolicy/resource_ibm_iam_user_policy_test.go +++ b/ibm/service/iampolicy/resource_ibm_iam_user_policy_test.go @@ -180,6 +180,7 @@ func TestAccIBMIAMUserPolicy_import(t *testing.T) { }, }) } + func TestAccIBMIAMUserPolicy_With_Resource_Attributes(t *testing.T) { var conf iampolicymanagementv1.V2PolicyTemplateMetaData @@ -206,6 +207,26 @@ func TestAccIBMIAMUserPolicy_With_Resource_Attributes(t *testing.T) { }) } +func TestAccIBMIAMUserPolicy_With_Resource_Attributes_Without_Wildcard(t *testing.T) { + var conf iampolicymanagementv1.V2PolicyTemplateMetaData + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIAMServicePolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMIAMUserPolicyResourceAttributesWithoutWildcard(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIAMUserPolicyExists("ibm_iam_user_policy.policy", conf), + resource.TestCheckResourceAttr("ibm_iam_user_policy.policy", "resource_attributes.#", "2"), + ), + }, + }, + }) +} + + func TestAccIBMIAMUserPolicy_account_management(t *testing.T) { var conf iampolicymanagementv1.V2PolicyTemplateMetaData name := fmt.Sprintf("terraform_%d", acctest.RandIntRange(10, 100)) @@ -806,6 +827,28 @@ func testAccCheckIBMIAMUserPolicyResourceAttributes() string { `, acc.IAMUser) } + +func testAccCheckIBMIAMUserPolicyResourceAttributesWithoutWildcard() string { + return fmt.Sprintf(` + + resource "ibm_iam_user_policy" "policy" { + ibm_id = "%s" + roles = ["Viewer"] + resource_attributes { + name = "resource" + value = "test" + operator = "stringMatch" + } + resource_attributes { + name = "serviceName" + value = "messagehub" + } + } + +`, acc.IAMUser) +} + + func testAccCheckIBMIAMUserPolicyResourceAttributesUpdate() string { return fmt.Sprintf(` resource "ibm_iam_user_policy" "policy" { diff --git a/ibm/service/kubernetes/data_source_ibm_container_cluster.go b/ibm/service/kubernetes/data_source_ibm_container_cluster.go index a35f784d99..12f0e640de 100644 --- a/ibm/service/kubernetes/data_source_ibm_container_cluster.go +++ b/ibm/service/kubernetes/data_source_ibm_container_cluster.go @@ -426,7 +426,7 @@ func dataSourceIBMContainerClusterRead(d *schema.ResourceData, meta interface{}) } albs, err := albsAPI.ListClusterALBs(name, targetEnv) - if err != nil && !strings.Contains(err.Error(), "The specified cluster is a lite cluster.") && !strings.Contains(err.Error(), "This operation is not supported for your cluster's version.") && !strings.Contains(err.Error(), "The specified cluster is a free cluster.") { + if err != nil && !strings.Contains(err.Error(), "This operation is not supported for your cluster's version.") { return fmt.Errorf("[ERROR] Error retrieving alb's of the cluster %s: %s", name, err) } diff --git a/ibm/service/kubernetes/data_source_ibm_container_vpc_cluster.go b/ibm/service/kubernetes/data_source_ibm_container_vpc_cluster.go index fe7e3edff9..31a496730d 100644 --- a/ibm/service/kubernetes/data_source_ibm_container_vpc_cluster.go +++ b/ibm/service/kubernetes/data_source_ibm_container_vpc_cluster.go @@ -252,7 +252,10 @@ func DataSourceIBMContainerVPCCluster() *schema.Resource { Type: schema.TypeString, Computed: true, }, - + "vpe_service_endpoint_url": { + Type: schema.TypeString, + Computed: true, + }, "crn": { Type: schema.TypeString, Computed: true, @@ -395,6 +398,7 @@ func dataSourceIBMContainerClusterVPCRead(d *schema.ResourceData, meta interface d.Set("resource_group_id", cls.ResourceGroupID) d.Set("public_service_endpoint_url", cls.ServiceEndpoints.PublicServiceEndpointURL) d.Set("private_service_endpoint_url", cls.ServiceEndpoints.PrivateServiceEndpointURL) + d.Set("vpe_service_endpoint_url", cls.VirtualPrivateEndpointURL) d.Set("public_service_endpoint", cls.ServiceEndpoints.PublicServiceEndpointEnabled) d.Set("private_service_endpoint", cls.ServiceEndpoints.PrivateServiceEndpointEnabled) d.Set("ingress_hostname", cls.Ingress.HostName) @@ -421,7 +425,7 @@ func dataSourceIBMContainerClusterVPCRead(d *schema.ResourceData, meta interface if !strings.HasSuffix(cls.MasterKubeVersion, _OPENSHIFT) { albs, err := csClient.Albs().ListClusterAlbs(clusterID, targetEnv) - if err != nil && !strings.Contains(err.Error(), "The specified cluster is a lite cluster.") { + if err != nil { return fmt.Errorf("[ERROR] Error retrieving alb's of the cluster %s: %s", clusterID, err) } diff --git a/ibm/service/kubernetes/resource_ibm_container_cluster.go b/ibm/service/kubernetes/resource_ibm_container_cluster.go index a5ec55b331..d67e5c63f0 100644 --- a/ibm/service/kubernetes/resource_ibm_container_cluster.go +++ b/ibm/service/kubernetes/resource_ibm_container_cluster.go @@ -828,12 +828,10 @@ func resourceIBMContainerClusterRead(d *schema.ResourceData, meta interface{}) e d.Set("private_vlan_id", workersByPool[0].PrivateVlan) } d.Set("machine_type", strings.Split(workersByPool[0].MachineType, ".encrypted")[0]) - if workersByPool[0].MachineType != "free" { - if strings.HasSuffix(workersByPool[0].MachineType, ".encrypted") { - d.Set("disk_encryption", true) - } else { - d.Set("disk_encryption", false) - } + if strings.HasSuffix(workersByPool[0].MachineType, ".encrypted") { + d.Set("disk_encryption", true) + } else { + d.Set("disk_encryption", false) } if len(workersByPool) > 0 { @@ -866,7 +864,7 @@ func resourceIBMContainerClusterRead(d *schema.ResourceData, meta interface{}) e } albs, err := albsAPI.ListClusterALBs(clusterID, targetEnv) - if err != nil && !strings.Contains(err.Error(), "The specified cluster is a lite cluster.") && !strings.Contains(err.Error(), "This operation is not supported for your cluster's version.") && !strings.Contains(err.Error(), "The specified cluster is a free cluster.") { + if err != nil && !strings.Contains(err.Error(), "This operation is not supported for your cluster's version.") { return fmt.Errorf("[ERROR] Error retrieving alb's of the cluster %s: %s", clusterID, err) } diff --git a/ibm/service/kubernetes/resource_ibm_container_vpc_cluster.go b/ibm/service/kubernetes/resource_ibm_container_vpc_cluster.go index 3371e491ab..b1221f5572 100644 --- a/ibm/service/kubernetes/resource_ibm_container_vpc_cluster.go +++ b/ibm/service/kubernetes/resource_ibm_container_vpc_cluster.go @@ -415,6 +415,11 @@ func ResourceIBMContainerVpcCluster() *schema.Resource { Computed: true, }, + "vpe_service_endpoint_url": { + Type: schema.TypeString, + Computed: true, + }, + "crn": { Type: schema.TypeString, Computed: true, @@ -984,6 +989,7 @@ func resourceIBMContainerVpcClusterRead(d *schema.ResourceData, meta interface{} d.Set("resource_group_id", cls.ResourceGroupID) d.Set("public_service_endpoint_url", cls.ServiceEndpoints.PublicServiceEndpointURL) d.Set("private_service_endpoint_url", cls.ServiceEndpoints.PrivateServiceEndpointURL) + d.Set("vpe_service_endpoint_url", cls.VirtualPrivateEndpointURL) if cls.ServiceEndpoints.PublicServiceEndpointEnabled { d.Set("disable_public_service_endpoint", false) } else { diff --git a/ibm/service/metricsrouter/resource_ibm_metrics_router_route_test.go b/ibm/service/metricsrouter/resource_ibm_metrics_router_route_test.go index d84f2404bc..6c1e2e8fe7 100644 --- a/ibm/service/metricsrouter/resource_ibm_metrics_router_route_test.go +++ b/ibm/service/metricsrouter/resource_ibm_metrics_router_route_test.go @@ -139,7 +139,7 @@ func TestAccIBMMetricsRouterRouteSendNoTarget(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccCheckIBMMetricsRouterRouteNoTarget(name, action), - ExpectError: regexp.MustCompile("Send rule action requires non-empty targets"), + ExpectError: regexp.MustCompile("You have a rule with empty targets."), }, }, }) diff --git a/ibm/service/power/data_source_ibm_pi_catalog_images.go b/ibm/service/power/data_source_ibm_pi_catalog_images.go index 62adf75a8e..b2c5c392b2 100644 --- a/ibm/service/power/data_source_ibm_pi_catalog_images.go +++ b/ibm/service/power/data_source_ibm_pi_catalog_images.go @@ -7,108 +7,125 @@ import ( "context" "time" + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "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/helpers" - "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" ) -/* -Datasource to get the list of images that are available when a power instance is created -*/ +// Datasource to list images that are available when a power instance is created func DataSourceIBMPICatalogImages() *schema.Resource { - return &schema.Resource{ ReadContext: dataSourceIBMPICatalogImagesRead, Schema: map[string]*schema.Schema{ - - helpers.PICloudInstanceId: { - Type: schema.TypeString, + // Arguments + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", Required: true, + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, - "sap": { - Type: schema.TypeBool, - Optional: true, + Arg_SAP: { + Description: "Set true to include SAP images. The default value is false.", + Optional: true, + Type: schema.TypeBool, }, - "vtl": { - Type: schema.TypeBool, - Optional: true, + Arg_VTL: { + Description: "Set true to include VTL images. The default value is false.", + Optional: true, + Type: schema.TypeBool, }, - "images": { - Type: schema.TypeList, - Computed: true, + + // Attributes + Attr_Images: { + Computed: true, + Description: "Lists all the images in the IBM Power Virtual Server Cloud.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "image_id": { - Type: schema.TypeString, - Computed: true, - }, - "name": { - Type: schema.TypeString, - Computed: true, - }, - "state": { - Type: schema.TypeString, - Computed: true, - }, - "description": { - Type: schema.TypeString, - Computed: true, - }, - "storage_type": { - Type: schema.TypeString, - Computed: true, - }, - "storage_pool": { - Type: schema.TypeString, - Computed: true, - }, - "creation_date": { - Type: schema.TypeString, - Computed: true, - }, - "last_update_date": { - Type: schema.TypeString, - Computed: true, - }, - "image_type": { - Type: schema.TypeString, - Computed: true, - }, - "container_format": { - Type: schema.TypeString, - Computed: true, - }, - "disk_format": { - Type: schema.TypeString, - Computed: true, - }, - "operating_system": { - Type: schema.TypeString, - Computed: true, - }, - "hypervisor_type": { - Type: schema.TypeString, - Computed: true, - }, - "architecture": { - Type: schema.TypeString, - Computed: true, - }, - "endianness": { - Type: schema.TypeString, - Computed: true, - }, - "href": { - Type: schema.TypeString, - Computed: true, + Attr_Architecture: { + Computed: true, + Description: "The CPU architecture that the image is designed for.", + Type: schema.TypeString, + }, + Attr_ContainerFormat: { + Computed: true, + Description: "The container format.", + Type: schema.TypeString, + }, + Attr_CreationDate: { + Computed: true, + Description: "Date of image creation", + Type: schema.TypeString, + }, + Attr_Description: { + Computed: true, + Description: "The description of an image.", + Type: schema.TypeString, + }, + Attr_DiskFormat: { + Computed: true, + Description: "The disk format.", + Type: schema.TypeString, + }, + Attr_Endianness: { + Computed: true, + Description: "The Endianness order.", + Type: schema.TypeString, + }, + Attr_Href: { + Computed: true, + Description: "The href of an image.", + Type: schema.TypeString, + }, + Attr_HypervisorType: { + Computed: true, + Description: "Hypervisor type.", + Type: schema.TypeString, + }, + Attr_ImageID: { + Computed: true, + Description: "The unique identifier of an image.", + Type: schema.TypeString, + }, + Attr_ImageType: { + Computed: true, + Description: "The identifier of this image type.", + Type: schema.TypeString, + }, + Attr_LastUpdateDate: { + Computed: true, + Description: "The last updated date of an image.", + Type: schema.TypeString, + }, + Attr_Name: { + Computed: true, + Description: "The name of the image.", + Type: schema.TypeString, + }, + Attr_OperatingSystem: { + Computed: true, + Description: "Operating System.", + Type: schema.TypeString, + }, + Attr_State: { + Computed: true, + Description: "The state of an Operating System.", + Type: schema.TypeString, + }, + Attr_StoragePool: { + Computed: true, + Description: "Storage pool where image resides.", + Type: schema.TypeString, + }, + Attr_StorageType: { + Computed: true, + Description: "The storage type of an image.", + Type: schema.TypeString, }, }, }, + Type: schema.TypeList, }, }, } @@ -120,15 +137,9 @@ func dataSourceIBMPICatalogImagesRead(ctx context.Context, d *schema.ResourceDat return diag.FromErr(err) } - cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) - includeSAP := false - if s, ok := d.GetOk("sap"); ok { - includeSAP = s.(bool) - } - includeVTL := false - if v, ok := d.GetOk("vtl"); ok { - includeVTL = v.(bool) - } + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) + includeSAP := d.Get(Arg_SAP).(bool) + includeVTL := d.Get(Arg_VTL).(bool) imageC := instance.NewIBMPIImageClient(ctx, sess, cloudInstanceID) stockImages, err := imageC.GetAllStockImages(includeSAP, includeVTL) if err != nil { @@ -138,57 +149,58 @@ func dataSourceIBMPICatalogImagesRead(ctx context.Context, d *schema.ResourceDat images := make([]map[string]interface{}, 0) for _, i := range stockImages.Images { image := make(map[string]interface{}) - image["image_id"] = *i.ImageID - image["name"] = *i.Name - if i.State != nil { - image["state"] = *i.State - } + image[Attr_ImageID] = *i.ImageID + image[Attr_Name] = *i.Name + if i.Description != nil { - image["description"] = *i.Description - } - if i.StorageType != nil { - image["storage_type"] = *i.StorageType - } - if i.StoragePool != nil { - image["storage_pool"] = *i.StoragePool + image[Attr_Description] = *i.Description } if i.CreationDate != nil { - image["creation_date"] = i.CreationDate.String() - } - if i.LastUpdateDate != nil { - image["last_update_date"] = i.LastUpdateDate.String() + image[Attr_CreationDate] = i.CreationDate.String() } if i.Href != nil { - image["href"] = *i.Href + image[Attr_Href] = *i.Href + } + if i.LastUpdateDate != nil { + image[Attr_LastUpdateDate] = i.LastUpdateDate.String() } if i.Specifications != nil { s := i.Specifications - if s.ImageType != "" { - image["image_type"] = s.ImageType + if s.Architecture != "" { + image[Attr_Architecture] = s.Architecture } if s.ContainerFormat != "" { - image["container_format"] = s.ContainerFormat + image[Attr_ContainerFormat] = s.ContainerFormat } if s.DiskFormat != "" { - image["disk_format"] = s.DiskFormat + image[Attr_DiskFormat] = s.DiskFormat } - if s.OperatingSystem != "" { - image["operating_system"] = s.OperatingSystem + if s.Endianness != "" { + image[Attr_Endianness] = s.Endianness } if s.HypervisorType != "" { - image["hypervisor_type"] = s.HypervisorType + image[Attr_HypervisorType] = s.HypervisorType } - if s.Architecture != "" { - image["architecture"] = s.Architecture + if s.ImageType != "" { + image[Attr_ImageType] = s.ImageType } - if s.Endianness != "" { - image["endianness"] = s.Endianness + if s.OperatingSystem != "" { + image[Attr_OperatingSystem] = s.OperatingSystem } } + if i.State != nil { + image[Attr_State] = *i.State + } + if i.StoragePool != nil { + image[Attr_StoragePool] = *i.StoragePool + } + if i.StorageType != nil { + image[Attr_StorageType] = *i.StorageType + } images = append(images, image) } d.SetId(time.Now().UTC().String()) - d.Set("images", images) - return nil + d.Set(Attr_Images, images) + return nil } diff --git a/ibm/service/power/data_source_ibm_pi_catalog_images_test.go b/ibm/service/power/data_source_ibm_pi_catalog_images_test.go index a18020ff3d..f317397229 100644 --- a/ibm/service/power/data_source_ibm_pi_catalog_images_test.go +++ b/ibm/service/power/data_source_ibm_pi_catalog_images_test.go @@ -14,38 +14,34 @@ import ( func testAccCheckIBMPICatalogImagesDataSourceBasicConfig() string { return fmt.Sprintf(` - data "ibm_pi_catalog_images" "power_catalog_images_basic" { - pi_cloud_instance_id = "%s" - } - `, acc.Pi_cloud_instance_id) + data "ibm_pi_catalog_images" "power_catalog_images_basic" { + pi_cloud_instance_id = "%s" + }`, acc.Pi_cloud_instance_id) } func testAccCheckIBMPICatalogImagesDataSourceSAPConfig() string { return fmt.Sprintf(` - data "ibm_pi_catalog_images" "power_catalog_images_sap" { - pi_cloud_instance_id = "%s" - sap = "true" - } - `, acc.Pi_cloud_instance_id) + data "ibm_pi_catalog_images" "power_catalog_images_sap" { + pi_cloud_instance_id = "%s" + sap = "true" + }`, acc.Pi_cloud_instance_id) } func testAccCheckIBMPICatalogImagesDataSourceVTLConfig() string { return fmt.Sprintf(` - data "ibm_pi_catalog_images" "power_catalog_images_vtl" { - pi_cloud_instance_id = "%s" - vtl = "true" - } - `, acc.Pi_cloud_instance_id) + data "ibm_pi_catalog_images" "power_catalog_images_vtl" { + pi_cloud_instance_id = "%s" + vtl = "true" + }`, acc.Pi_cloud_instance_id) } func testAccCheckIBMPICatalogImagesDataSourceSAP_And_VTLConfig() string { return fmt.Sprintf(` - data "ibm_pi_catalog_images" "power_catalog_images_sap_and_vtl" { - pi_cloud_instance_id = "%s" - sap = "true" - vtl = "true" - } - `, acc.Pi_cloud_instance_id) + data "ibm_pi_catalog_images" "power_catalog_images_sap_and_vtl" { + pi_cloud_instance_id = "%s" + sap = "true" + vtl = "true" + }`, acc.Pi_cloud_instance_id) } func TestAccIBMPICatalogImagesDataSourceBasic(t *testing.T) { diff --git a/ibm/service/power/data_source_ibm_pi_cloud_connection.go b/ibm/service/power/data_source_ibm_pi_cloud_connection.go index 8e5bc59f83..f877aac73b 100644 --- a/ibm/service/power/data_source_ibm_pi_cloud_connection.go +++ b/ibm/service/power/data_source_ibm_pi_cloud_connection.go @@ -7,116 +7,104 @@ import ( "context" "log" - "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/helpers" "github.com/IBM-Cloud/power-go-client/power/models" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" -) - -const ( - PICloudConnectionId = "cloud_connection_id" - PICloudConnectionName = "name" - PICloudConnectionSpeed = "speed" - PICloudConnectionGlobalRouting = "global_routing" - PICloudConnectionMetered = "metered" - PICloudConnectionStatus = "status" - PICloudConnectionClassicEnabled = "classic_enabled" - PICloudConnectionUserIPAddress = "user_ip_address" - PICloudConnectionIBMIPAddress = "ibm_ip_address" - PICloudConnectionPort = "port" - PICloudConnectionNetworks = "networks" - PICloudConnectionClassicGreDest = "gre_destination_address" - PICloudConnectionClassicGreSource = "gre_source_address" - PICloudConnectionVPCEnabled = "vpc_enabled" - PICloudConnectionVPCCRNs = "vpc_crns" - PICloudConnectionConnectionMode = "connection_mode" + "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" ) func DataSourceIBMPICloudConnection() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMPICloudConnectionRead, Schema: map[string]*schema.Schema{ - helpers.PICloudInstanceId: { - Type: schema.TypeString, + // Arguments + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", Required: true, + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, - helpers.PICloudConnectionName: { - Type: schema.TypeString, + Arg_CloudConnectionName: { + Description: "The cloud connection name to be used.", Required: true, - Description: "Cloud Connection Name to be used", + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, - // Computed Attributes - PICloudConnectionSpeed: { - Type: schema.TypeInt, - Computed: true, + // Attributes + Attr_ClassicEnabled: { + Computed: true, + Description: "Enable classic endpoint destination.", + Type: schema.TypeBool, }, - PICloudConnectionGlobalRouting: { - Type: schema.TypeBool, - Computed: true, + Attr_ConnectionMode: { + Computed: true, + Description: "Type of service the gateway is attached to.", + Type: schema.TypeString, }, - PICloudConnectionMetered: { - Type: schema.TypeBool, - Computed: true, + Attr_GlobalRouting: { + Computed: true, + Description: "Enable global routing for this cloud connection.", + Type: schema.TypeBool, }, - PICloudConnectionStatus: { - Type: schema.TypeString, - Computed: true, + Attr_GreDestinationAddress: { + Computed: true, + Description: "GRE destination IP address.", + Type: schema.TypeString, }, - PICloudConnectionIBMIPAddress: { - Type: schema.TypeString, - Computed: true, + Attr_GreSourceAddress: { + Computed: true, + Description: "GRE auto-assigned source IP address.", + Type: schema.TypeString, }, - PICloudConnectionUserIPAddress: { - Type: schema.TypeString, - Computed: true, + Attr_IBMIPAddress: { + Computed: true, + Description: "The IBM IP address.", + Type: schema.TypeString, }, - PICloudConnectionPort: { - Type: schema.TypeString, - Computed: true, + Attr_Metered: { + Computed: true, + Description: "Enable metering for this cloud connection.", + Type: schema.TypeBool, }, - PICloudConnectionNetworks: { - Type: schema.TypeSet, + Attr_Networks: { Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, Description: "Set of Networks attached to this cloud connection", + Elem: &schema.Schema{Type: schema.TypeString}, + Type: schema.TypeSet, }, - PICloudConnectionClassicEnabled: { - Type: schema.TypeBool, + Attr_Port: { Computed: true, - Description: "Enable classic endpoint destination", - }, - PICloudConnectionClassicGreDest: { + Description: "Port.", Type: schema.TypeString, + }, + Attr_Speed: { Computed: true, - Description: "GRE destination IP address", + Description: "Speed of the cloud connection (speed in megabits per second)", + Type: schema.TypeInt, }, - PICloudConnectionClassicGreSource: { - Type: schema.TypeString, + Attr_Status: { Computed: true, - Description: "GRE auto-assigned source IP address", + Description: "Link status.", + Type: schema.TypeString, }, - PICloudConnectionVPCEnabled: { - Type: schema.TypeBool, + Attr_UserIPAddress: { Computed: true, - Description: "Enable VPC for this cloud connection", + Description: "User IP address.", + Type: schema.TypeString, }, - PICloudConnectionVPCCRNs: { - Type: schema.TypeSet, + Attr_VPCCRNs: { Computed: true, + Description: "Set of VPCs attached to this cloud connection.", Elem: &schema.Schema{Type: schema.TypeString}, - Description: "Set of VPCs attached to this cloud connection", + Type: schema.TypeSet, }, - PICloudConnectionConnectionMode: { - Type: schema.TypeString, + Attr_VPCEnabled: { Computed: true, - Description: "Type of service the gateway is attached to", + Description: "Enable VPC for this cloud connection.", + Type: schema.TypeBool, }, }, } @@ -128,8 +116,8 @@ func dataSourceIBMPICloudConnectionRead(ctx context.Context, d *schema.ResourceD return diag.FromErr(err) } - cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) - cloudConnectionName := d.Get(helpers.PICloudConnectionName).(string) + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) + cloudConnectionName := d.Get(Arg_CloudConnectionName).(string) client := instance.NewIBMPICloudConnectionClient(ctx, sess, cloudInstanceID) // Get API does not work with name for Cloud Connection hence using GetAll (max 2) @@ -165,16 +153,18 @@ func dataSourceIBMPICloudConnectionRead(ctx context.Context, d *schema.ResourceD } d.SetId(*cloudConnection.CloudConnectionID) - d.Set(helpers.PICloudConnectionName, cloudConnection.Name) - d.Set(PICloudConnectionGlobalRouting, cloudConnection.GlobalRouting) - d.Set(PICloudConnectionMetered, cloudConnection.Metered) - d.Set(PICloudConnectionIBMIPAddress, cloudConnection.IbmIPAddress) - d.Set(PICloudConnectionUserIPAddress, cloudConnection.UserIPAddress) - d.Set(PICloudConnectionStatus, cloudConnection.LinkStatus) - d.Set(PICloudConnectionPort, cloudConnection.Port) - d.Set(PICloudConnectionSpeed, cloudConnection.Speed) - d.Set(helpers.PICloudInstanceId, cloudInstanceID) - d.Set(PICloudConnectionConnectionMode, cloudConnection.ConnectionMode) + + d.Set(Arg_CloudInstanceID, cloudInstanceID) + d.Set(Arg_CloudConnectionName, cloudConnection.Name) + + d.Set(Attr_GlobalRouting, cloudConnection.GlobalRouting) + d.Set(Attr_Metered, cloudConnection.Metered) + d.Set(Attr_IBMIPAddress, cloudConnection.IbmIPAddress) + d.Set(Attr_UserIPAddress, cloudConnection.UserIPAddress) + d.Set(Attr_Status, cloudConnection.LinkStatus) + d.Set(Attr_Port, cloudConnection.Port) + d.Set(Attr_Speed, cloudConnection.Speed) + d.Set(Attr_ConnectionMode, cloudConnection.ConnectionMode) if cloudConnection.Networks != nil { networks := make([]string, len(cloudConnection.Networks)) for i, ccNetwork := range cloudConnection.Networks { @@ -182,24 +172,25 @@ func dataSourceIBMPICloudConnectionRead(ctx context.Context, d *schema.ResourceD networks[i] = *ccNetwork.NetworkID } } - d.Set(PICloudConnectionNetworks, networks) + d.Set(Attr_Networks, networks) } if cloudConnection.Classic != nil { - d.Set(PICloudConnectionClassicEnabled, cloudConnection.Classic.Enabled) + d.Set(Attr_ClassicEnabled, cloudConnection.Classic.Enabled) if cloudConnection.Classic.Gre != nil { - d.Set(PICloudConnectionClassicGreDest, cloudConnection.Classic.Gre.DestIPAddress) - d.Set(PICloudConnectionClassicGreSource, cloudConnection.Classic.Gre.SourceIPAddress) + d.Set(Attr_GreDestinationAddress, cloudConnection.Classic.Gre.DestIPAddress) + d.Set(Attr_GreSourceAddress, cloudConnection.Classic.Gre.SourceIPAddress) } } if cloudConnection.Vpc != nil { - d.Set(PICloudConnectionVPCEnabled, cloudConnection.Vpc.Enabled) + d.Set(Attr_VPCEnabled, cloudConnection.Vpc.Enabled) if cloudConnection.Vpc.Vpcs != nil && len(cloudConnection.Vpc.Vpcs) > 0 { vpcCRNs := make([]string, len(cloudConnection.Vpc.Vpcs)) for i, vpc := range cloudConnection.Vpc.Vpcs { vpcCRNs[i] = *vpc.VpcID } - d.Set(PICloudConnectionVPCCRNs, vpcCRNs) + d.Set(Attr_VPCCRNs, vpcCRNs) } } + return nil } diff --git a/ibm/service/power/data_source_ibm_pi_cloud_connection_test.go b/ibm/service/power/data_source_ibm_pi_cloud_connection_test.go index 732b10ad1f..60eda0cb08 100644 --- a/ibm/service/power/data_source_ibm_pi_cloud_connection_test.go +++ b/ibm/service/power/data_source_ibm_pi_cloud_connection_test.go @@ -30,9 +30,8 @@ func TestAccIBMPICloudConnectionDataSource_basic(t *testing.T) { func testAccCheckIBMPICloudConnectionDataSourceConfig() string { return fmt.Sprintf(` - data "ibm_pi_cloud_connection" "example" { - pi_cloud_connection_name = "%s" - pi_cloud_instance_id = "%s" - } - `, acc.PiCloudConnectionName, acc.Pi_cloud_instance_id) + data "ibm_pi_cloud_connection" "example" { + pi_cloud_connection_name = "%s" + pi_cloud_instance_id = "%s" + }`, acc.PiCloudConnectionName, acc.Pi_cloud_instance_id) } diff --git a/ibm/service/power/data_source_ibm_pi_cloud_connections.go b/ibm/service/power/data_source_ibm_pi_cloud_connections.go index ad5a35e434..2e99b1ea97 100644 --- a/ibm/service/power/data_source_ibm_pi_cloud_connections.go +++ b/ibm/service/power/data_source_ibm_pi_cloud_connections.go @@ -7,113 +7,118 @@ import ( "context" "log" - st "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/power-go-client/clients/instance" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "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" ) -/* -Datasource to get the list of Cloud Connections in a power instance -*/ - -const PICloudConnections = "connections" - +// Datasource to list Cloud Connections in a power instance func DataSourceIBMPICloudConnections() *schema.Resource { - return &schema.Resource{ ReadContext: dataSourceIBMPICloudConnectionsRead, Schema: map[string]*schema.Schema{ - helpers.PICloudInstanceId: { - Type: schema.TypeString, + // Arguments + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", Required: true, + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, - // Computed Attributes - PICloudConnections: { - Type: schema.TypeList, - Computed: true, + + // Attributes + Attr_Connections: { + Computed: true, + Description: "List of all the Cloud Connections.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - PICloudConnectionId: { - Type: schema.TypeString, - Computed: true, + Attr_ClassicEnabled: { + Computed: true, + Description: "Enable classic endpoint destination.", + Type: schema.TypeBool, }, - PICloudConnectionName: { - Type: schema.TypeString, - Computed: true, + Attr_CloudConnectionID: { + Computed: true, + Description: "The unique identifier of the cloud connection.", + Type: schema.TypeString, }, - PICloudConnectionSpeed: { - Type: schema.TypeInt, - Computed: true, + Attr_ConnectionMode: { + Computed: true, + Description: "Type of service the gateway is attached to.", + Type: schema.TypeString, }, - PICloudConnectionGlobalRouting: { - Type: schema.TypeBool, - Computed: true, + Attr_GlobalRouting: { + Computed: true, + Description: "Enable global routing for this cloud connection.", + Type: schema.TypeBool, }, - PICloudConnectionMetered: { - Type: schema.TypeBool, - Computed: true, + Attr_GreDestinationAddress: { + Computed: true, + Description: "GRE destination IP address.", + Type: schema.TypeString, }, - PICloudConnectionStatus: { - Type: schema.TypeString, - Computed: true, + Attr_GreSourceAddress: { + Computed: true, + Description: "GRE auto-assigned source IP address.", + Type: schema.TypeString, }, - PICloudConnectionIBMIPAddress: { - Type: schema.TypeString, - Computed: true, + Attr_IBMIPAddress: { + Computed: true, + Description: "IBM IP address.", + Type: schema.TypeString, }, - PICloudConnectionUserIPAddress: { - Type: schema.TypeString, - Computed: true, + Attr_Metered: { + Computed: true, + Description: "Enable metering for this cloud connection.", + Type: schema.TypeBool, }, - PICloudConnectionPort: { - Type: schema.TypeString, - Computed: true, + Attr_Name: { + Computed: true, + Description: "Name of the cloud connection.", + Type: schema.TypeString, }, - PICloudConnectionNetworks: { - Type: schema.TypeSet, + Attr_Networks: { Computed: true, + Description: "Set of Networks attached to this cloud connection.", Elem: &schema.Schema{Type: schema.TypeString}, - Description: "Set of Networks attached to this cloud connection", + Type: schema.TypeSet, }, - PICloudConnectionClassicEnabled: { - Type: schema.TypeBool, + Attr_Port: { Computed: true, - Description: "Enable classic endpoint destination", - }, - PICloudConnectionClassicGreDest: { + Description: "Port.", Type: schema.TypeString, + }, + Attr_Speed: { Computed: true, - Description: "GRE destination IP address", + Description: "Speed of the cloud connection (speed in megabits per second).", + Type: schema.TypeInt, }, - PICloudConnectionClassicGreSource: { - Type: schema.TypeString, + Attr_Status: { Computed: true, - Description: "GRE auto-assigned source IP address", + Description: "Link status.", + Type: schema.TypeString, }, - PICloudConnectionVPCEnabled: { - Type: schema.TypeBool, + Attr_UserIPAddress: { Computed: true, - Description: "Enable VPC for this cloud connection", + Description: "User IP address.", + Type: schema.TypeString, }, - PICloudConnectionVPCCRNs: { - Type: schema.TypeSet, + Attr_VPCCRNs: { Computed: true, + Description: "Set of VPCs attached to this cloud connection.", Elem: &schema.Schema{Type: schema.TypeString}, - Description: "Set of VPCs attached to this cloud connection", + Type: schema.TypeSet, }, - PICloudConnectionConnectionMode: { - Type: schema.TypeString, + Attr_VPCEnabled: { Computed: true, - Description: "Type of service the gateway is attached to", + Description: "Enable VPC for this cloud connection.", + Type: schema.TypeBool, }, }, }, + Type: schema.TypeList, }, }, } @@ -125,8 +130,8 @@ func dataSourceIBMPICloudConnectionsRead(ctx context.Context, d *schema.Resource return diag.FromErr(err) } - cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) - client := st.NewIBMPICloudConnectionClient(ctx, sess, cloudInstanceID) + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) + client := instance.NewIBMPICloudConnectionClient(ctx, sess, cloudInstanceID) cloudConnections, err := client.GetAll() if err != nil { @@ -137,16 +142,16 @@ func dataSourceIBMPICloudConnectionsRead(ctx context.Context, d *schema.Resource result := make([]map[string]interface{}, 0, len(cloudConnections.CloudConnections)) for _, cloudConnection := range cloudConnections.CloudConnections { cc := map[string]interface{}{ - PICloudConnectionId: *cloudConnection.CloudConnectionID, - PICloudConnectionName: *cloudConnection.Name, - PICloudConnectionGlobalRouting: *cloudConnection.GlobalRouting, - PICloudConnectionMetered: *cloudConnection.Metered, - PICloudConnectionIBMIPAddress: *cloudConnection.IbmIPAddress, - PICloudConnectionUserIPAddress: *cloudConnection.UserIPAddress, - PICloudConnectionStatus: *cloudConnection.LinkStatus, - PICloudConnectionPort: *cloudConnection.Port, - PICloudConnectionSpeed: *cloudConnection.Speed, - PICloudConnectionConnectionMode: cloudConnection.ConnectionMode, + Attr_CloudConnectionID: *cloudConnection.CloudConnectionID, + Attr_ConnectionMode: cloudConnection.ConnectionMode, + Attr_GlobalRouting: *cloudConnection.GlobalRouting, + Attr_IBMIPAddress: *cloudConnection.IbmIPAddress, + Attr_Metered: *cloudConnection.Metered, + Attr_Name: *cloudConnection.Name, + Attr_Port: *cloudConnection.Port, + Attr_Speed: *cloudConnection.Speed, + Attr_Status: *cloudConnection.LinkStatus, + Attr_UserIPAddress: *cloudConnection.UserIPAddress, } if cloudConnection.Networks != nil { @@ -156,23 +161,23 @@ func dataSourceIBMPICloudConnectionsRead(ctx context.Context, d *schema.Resource networks[i] = *ccNetwork.NetworkID } } - cc[PICloudConnectionNetworks] = networks + cc[Attr_Networks] = networks } if cloudConnection.Classic != nil { - cc[PICloudConnectionClassicEnabled] = cloudConnection.Classic.Enabled + cc[Attr_ClassicEnabled] = cloudConnection.Classic.Enabled if cloudConnection.Classic.Gre != nil { - cc[PICloudConnectionClassicGreDest] = cloudConnection.Classic.Gre.DestIPAddress - cc[PICloudConnectionClassicGreSource] = cloudConnection.Classic.Gre.SourceIPAddress + cc[Attr_GreDestinationAddress] = cloudConnection.Classic.Gre.DestIPAddress + cc[Attr_GreSourceAddress] = cloudConnection.Classic.Gre.SourceIPAddress } } if cloudConnection.Vpc != nil { - cc[PICloudConnectionVPCEnabled] = cloudConnection.Vpc.Enabled + cc[Attr_VPCEnabled] = cloudConnection.Vpc.Enabled if cloudConnection.Vpc.Vpcs != nil && len(cloudConnection.Vpc.Vpcs) > 0 { vpcCRNs := make([]string, len(cloudConnection.Vpc.Vpcs)) for i, vpc := range cloudConnection.Vpc.Vpcs { vpcCRNs[i] = *vpc.VpcID } - cc[PICloudConnectionVPCCRNs] = vpcCRNs + cc[Attr_VPCCRNs] = vpcCRNs } } @@ -181,7 +186,7 @@ func dataSourceIBMPICloudConnectionsRead(ctx context.Context, d *schema.Resource var genID, _ = uuid.GenerateUUID() d.SetId(genID) - d.Set(PICloudConnections, result) + d.Set(Attr_Connections, result) return nil } diff --git a/ibm/service/power/data_source_ibm_pi_cloud_instance.go b/ibm/service/power/data_source_ibm_pi_cloud_instance.go index f9fa86dcd5..4a09bf2768 100644 --- a/ibm/service/power/data_source_ibm_pi_cloud_instance.go +++ b/ibm/service/power/data_source_ibm_pi_cloud_instance.go @@ -6,96 +6,111 @@ package power import ( "context" - "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/helpers" "github.com/IBM-Cloud/power-go-client/power/models" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "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" ) func DataSourceIBMPICloudInstance() *schema.Resource { - return &schema.Resource{ ReadContext: dataSourceIBMPICloudInstanceRead, Schema: map[string]*schema.Schema{ - helpers.PICloudInstanceId: { - Type: schema.TypeString, + // Arguments + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", Required: true, + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, - // Start of Computed Attributes - "enabled": { - Type: schema.TypeBool, - Computed: true, - }, - "tenant_id": { - Type: schema.TypeString, - Computed: true, - }, - "region": { - Type: schema.TypeString, - Computed: true, - }, - "capabilities": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "total_processors_consumed": { - Type: schema.TypeFloat, - Computed: true, + // Attributes + Attr_Capabilities: { + Computed: true, + Description: "Lists the capabilities for this cloud instance.", + Elem: &schema.Schema{Type: schema.TypeString}, + Type: schema.TypeList, }, - "total_instances": { - Type: schema.TypeFloat, - Computed: true, + Attr_Enabled: { + Computed: true, + Description: "Indicates whether the tenant is enabled.", + Type: schema.TypeBool, }, - "total_memory_consumed": { - Type: schema.TypeFloat, - Computed: true, - }, - "total_ssd_storage_consumed": { - Type: schema.TypeFloat, - Computed: true, - }, - "total_standard_storage_consumed": { - Type: schema.TypeFloat, - Computed: true, - }, - "pvm_instances": { - Type: schema.TypeList, - Computed: true, + Attr_PVMInstances: { + Computed: true, + Description: "PVM instances owned by the Cloud Instance.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, + Attr_CreationDate: { + Computed: true, + Description: "Date of PVM instance creation.", + Type: schema.TypeString, }, - "name": { - Type: schema.TypeString, - Computed: true, + Attr_Href: { + Computed: true, + Description: "Link to Cloud Instance resource.", + Type: schema.TypeString, }, - "href": { - Type: schema.TypeString, - Computed: true, + Attr_ID: { + Computed: true, + Description: "PVM Instance ID.", + Type: schema.TypeString, }, - "status": { - Type: schema.TypeString, - Computed: true, + Attr_Name: { + Computed: true, + Description: "Name of the server.", + Type: schema.TypeString, }, - "systype": { - Type: schema.TypeString, - Computed: true, + Attr_Status: { + Computed: true, + Description: "The status of the instance.", + Type: schema.TypeString, }, - "creation_date": { - Type: schema.TypeString, - Computed: true, + Attr_SysType: { + Computed: true, + Description: "System type used to host the instance.", + Type: schema.TypeString, }, }, }, + Type: schema.TypeList, + }, + Attr_Region: { + Computed: true, + Description: "The region the cloud instance lives.", + Type: schema.TypeString, + }, + Attr_TenantID: { + Computed: true, + Description: "The tenant ID that owns this cloud instance.", + Type: schema.TypeString, + }, + Attr_TotalInstances: { + Computed: true, + Description: "The count of lpars that belong to this specific cloud instance.", + Type: schema.TypeFloat, + }, + Attr_TotalMemoryConsumed: { + Computed: true, + Description: "The total memory consumed by this service instance.", + Type: schema.TypeFloat, + }, + Attr_TotalProcessorsConsumed: { + Computed: true, + Description: "The total processors consumed by this service instance.", + Type: schema.TypeFloat, + }, + Attr_TotalSSDStorageConsumed: { + Computed: true, + Description: "The total SSD Storage consumed by this service instance.", + Type: schema.TypeFloat, + }, + Attr_TotalStandardStorageConsumed: { + Computed: true, + Description: "The total Standard Storage consumed by this service instance.", + Type: schema.TypeFloat, }, }, } @@ -107,7 +122,7 @@ func dataSourceIBMPICloudInstanceRead(ctx context.Context, d *schema.ResourceDat return diag.FromErr(err) } - cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) cloud_instance := instance.NewIBMPICloudInstanceClient(ctx, sess, cloudInstanceID) cloud_instance_data, err := cloud_instance.Get(cloudInstanceID) @@ -116,35 +131,33 @@ func dataSourceIBMPICloudInstanceRead(ctx context.Context, d *schema.ResourceDat } d.SetId(*cloud_instance_data.CloudInstanceID) - d.Set("tenant_id", (cloud_instance_data.TenantID)) - d.Set("enabled", cloud_instance_data.Enabled) - d.Set("region", cloud_instance_data.Region) - d.Set("capabilities", cloud_instance_data.Capabilities) - d.Set("pvm_instances", flattenpvminstances(cloud_instance_data.PvmInstances)) - d.Set("total_ssd_storage_consumed", cloud_instance_data.Usage.StorageSSD) - d.Set("total_instances", cloud_instance_data.Usage.Instances) - d.Set("total_standard_storage_consumed", cloud_instance_data.Usage.StorageStandard) - d.Set("total_processors_consumed", cloud_instance_data.Usage.Processors) - d.Set("total_memory_consumed", cloud_instance_data.Usage.Memory) - return nil + d.Set(Attr_Capabilities, cloud_instance_data.Capabilities) + d.Set(Attr_Enabled, cloud_instance_data.Enabled) + d.Set(Attr_PVMInstances, flattenpvminstances(cloud_instance_data.PvmInstances)) + d.Set(Attr_Region, cloud_instance_data.Region) + d.Set(Attr_TenantID, (cloud_instance_data.TenantID)) + d.Set(Attr_TotalInstances, cloud_instance_data.Usage.Instances) + d.Set(Attr_TotalMemoryConsumed, cloud_instance_data.Usage.Memory) + d.Set(Attr_TotalProcessorsConsumed, cloud_instance_data.Usage.Processors) + d.Set(Attr_TotalSSDStorageConsumed, cloud_instance_data.Usage.StorageSSD) + d.Set(Attr_TotalStandardStorageConsumed, cloud_instance_data.Usage.StorageStandard) + return nil } func flattenpvminstances(list []*models.PVMInstanceReference) []map[string]interface{} { pvms := make([]map[string]interface{}, 0) for _, lpars := range list { - l := map[string]interface{}{ - "id": *lpars.PvmInstanceID, - "name": *lpars.ServerName, - "href": *lpars.Href, - "status": *lpars.Status, - "systype": lpars.SysType, - "creation_date": lpars.CreationDate.String(), + Attr_CreationDate: lpars.CreationDate.String(), + Attr_ID: *lpars.PvmInstanceID, + Attr_Href: *lpars.Href, + Attr_Name: *lpars.ServerName, + Attr_Status: *lpars.Status, + Attr_SysType: lpars.SysType, } pvms = append(pvms, l) - } return pvms } diff --git a/ibm/service/power/data_source_ibm_pi_cloud_instance_test.go b/ibm/service/power/data_source_ibm_pi_cloud_instance_test.go index 1d80d59337..d2f0b69db9 100644 --- a/ibm/service/power/data_source_ibm_pi_cloud_instance_test.go +++ b/ibm/service/power/data_source_ibm_pi_cloud_instance_test.go @@ -13,7 +13,6 @@ import ( ) func TestAccIBMPICloudInstanceDataSource_basic(t *testing.T) { - resource.Test(t, resource.TestCase{ PreCheck: func() { acc.TestAccPreCheck(t) }, Providers: acc.TestAccProviders, @@ -29,10 +28,8 @@ func TestAccIBMPICloudInstanceDataSource_basic(t *testing.T) { } func testAccCheckIBMPICloudInstanceDataSourceConfig() string { - return fmt.Sprintf(` - -data "ibm_pi_cloud_instance" "testacc_ds_cloud_instance" { - pi_cloud_instance_id = "%s" -}`, acc.Pi_cloud_instance_id) - + return fmt.Sprintf(` + data "ibm_pi_cloud_instance" "testacc_ds_cloud_instance" { + pi_cloud_instance_id = "%s" + }`, acc.Pi_cloud_instance_id) } diff --git a/ibm/service/power/data_source_ibm_pi_datacenter.go b/ibm/service/power/data_source_ibm_pi_datacenter.go index 2404570273..1dd2643f27 100644 --- a/ibm/service/power/data_source_ibm_pi_datacenter.go +++ b/ibm/service/power/data_source_ibm_pi_datacenter.go @@ -15,54 +15,52 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) -const ( - DatacenterRegion = "region" - DatacenterType = "type" - DatacenterUrl = "url" -) - func DataSourceIBMPIDatacenter() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMPIDatacenterRead, Schema: map[string]*schema.Schema{ + // Arguments Arg_DatacenterZone: { - Type: schema.TypeString, + Description: "Datacenter zone you want to retrieve.", Optional: true, + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, + + // Attributes Attr_DatacenterCapabilities: { - Type: schema.TypeMap, Computed: true, - Description: "Datacenter Capabilities", + Description: "Datacenter Capabilities.", Elem: &schema.Schema{ Type: schema.TypeBool, }, + Type: schema.TypeMap, }, Attr_DatacenterHref: { - Type: schema.TypeString, Computed: true, - Description: "Datacenter href", + Description: "Datacenter href.", + Type: schema.TypeString, }, Attr_DatacenterLocation: { - Type: schema.TypeMap, Computed: true, - Description: "Datacenter location", + Description: "Datacenter location.", + Type: schema.TypeMap, }, Attr_DatacenterStatus: { - Type: schema.TypeString, Computed: true, - Description: "Datacenter status", + Description: "Datacenter status, active,maintenance or down.", + Type: schema.TypeString, }, Attr_DatacenterType: { - Type: schema.TypeString, Computed: true, - Description: "Datacenter type", + Description: "Datacenter type, off-premises or on-premises.", + Type: schema.TypeString, }, }, } } + func dataSourceIBMPIDatacenterRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - // session sess, err := meta.(conns.ClientSession).IBMPISession() if err != nil { return diag.FromErr(err) @@ -81,14 +79,14 @@ func dataSourceIBMPIDatacenterRead(ctx context.Context, d *schema.ResourceData, d.SetId(genID) d.Set(Attr_DatacenterCapabilities, dcData.Capabilities) dclocation := map[string]interface{}{ - DatacenterRegion: *dcData.Location.Region, - DatacenterType: *dcData.Location.Type, - DatacenterUrl: *dcData.Location.URL, + Attr_Region: *dcData.Location.Region, + Attr_Type: *dcData.Location.Type, + Attr_URL: *dcData.Location.URL, } + d.Set(Attr_DatacenterHref, dcData.Href) d.Set(Attr_DatacenterLocation, flex.Flatten(dclocation)) d.Set(Attr_DatacenterStatus, dcData.Status) d.Set(Attr_DatacenterType, dcData.Type) - d.Set(Attr_DatacenterHref, dcData.Href) return nil } 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 cc289ca32d..0a7490c750 100644 --- a/ibm/service/power/data_source_ibm_pi_datacenter_test.go +++ b/ibm/service/power/data_source_ibm_pi_datacenter_test.go @@ -4,7 +4,6 @@ package power_test import ( - "fmt" "testing" acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" @@ -27,9 +26,8 @@ func TestAccIBMPIDatacenterDataSourceBasic(t *testing.T) { } func testAccCheckIBMPIDatacenterDataSourceConfig() string { - return fmt.Sprintf(` + return ` data "ibm_pi_datacenter" "test" { pi_datacenter_zone = "dal12" - } - `) + }` } diff --git a/ibm/service/power/data_source_ibm_pi_datacenters.go b/ibm/service/power/data_source_ibm_pi_datacenters.go index 949ba4741a..08059004df 100644 --- a/ibm/service/power/data_source_ibm_pi_datacenters.go +++ b/ibm/service/power/data_source_ibm_pi_datacenters.go @@ -13,47 +13,44 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -const ( - Datacenters = "datacenters" -) - func DataSourceIBMPIDatacenters() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMPIDatacentersRead, Schema: map[string]*schema.Schema{ - Datacenters: { - Type: schema.TypeList, - Computed: true, + // Attributes + Attr_Datacenters: { + Type: schema.TypeList, + Computed: true, + Description: "List of Datacenters", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - Attr_DatacenterCapabilities: { - Type: schema.TypeMap, Computed: true, Description: "Datacenter Capabilities", Elem: &schema.Schema{ Type: schema.TypeBool, }, + Type: schema.TypeMap, }, Attr_DatacenterHref: { - Type: schema.TypeString, Computed: true, Description: "Datacenter href", + Type: schema.TypeString, }, Attr_DatacenterLocation: { - Type: schema.TypeMap, Computed: true, Description: "Datacenter location", + Type: schema.TypeMap, }, Attr_DatacenterStatus: { - Type: schema.TypeString, Computed: true, Description: "Datacenter status", + Type: schema.TypeString, }, Attr_DatacenterType: { - Type: schema.TypeString, Computed: true, Description: "Datacenter type", + Type: schema.TypeString, }, }, }, @@ -61,8 +58,8 @@ func DataSourceIBMPIDatacenters() *schema.Resource { }, } } + func dataSourceIBMPIDatacentersRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - // session sess, err := meta.(conns.ClientSession).IBMPISession() if err != nil { return diag.FromErr(err) @@ -77,21 +74,20 @@ func dataSourceIBMPIDatacentersRead(ctx context.Context, d *schema.ResourceData, if datacenter != nil { dc := map[string]interface{}{ Attr_DatacenterCapabilities: datacenter.Capabilities, + Attr_DatacenterHref: datacenter.Href, Attr_DatacenterLocation: map[string]interface{}{ - DatacenterRegion: datacenter.Location.Region, - DatacenterType: datacenter.Location.Type, - DatacenterUrl: datacenter.Location.URL, + Attr_Region: datacenter.Location.Region, + Attr_Type: datacenter.Location.Type, + Attr_URL: datacenter.Location.URL, }, Attr_DatacenterStatus: datacenter.Status, Attr_DatacenterType: datacenter.Type, - Attr_DatacenterHref: datacenter.Href, } datacenters = append(datacenters, dc) } - } var clientgenU, _ = uuid.GenerateUUID() d.SetId(clientgenU) - d.Set(Datacenters, datacenters) + d.Set(Attr_Datacenters, datacenters) return nil } 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 21271d7d54..83ba01a68e 100644 --- a/ibm/service/power/data_source_ibm_pi_datacenters_test.go +++ b/ibm/service/power/data_source_ibm_pi_datacenters_test.go @@ -4,7 +4,6 @@ package power_test import ( - "fmt" "testing" acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" @@ -27,5 +26,5 @@ func TestAccIBMPIDatacentersDataSourceBasic(t *testing.T) { } func testAccCheckIBMPIDatacentersDataSourceConfig() string { - return fmt.Sprintf(`data "ibm_pi_datacenters" "test" {}`) + return `data "ibm_pi_datacenters" "test" {}` } diff --git a/ibm/service/power/data_source_ibm_pi_dhcp.go b/ibm/service/power/data_source_ibm_pi_dhcp.go index c6e716c020..b42bbc98dc 100644 --- a/ibm/service/power/data_source_ibm_pi_dhcp.go +++ b/ibm/service/power/data_source_ibm_pi_dhcp.go @@ -60,11 +60,6 @@ func DataSourceIBMPIDhcp() *schema.Resource { }, }, }, - Attr_DhcpNetworkDeprecated: { - Type: schema.TypeString, - Computed: true, - Description: "The ID of the DHCP Server private network (deprecated - replaced by network_id)", - }, Attr_DhcpNetworkID: { Type: schema.TypeString, Computed: true, @@ -114,7 +109,6 @@ func dataSourceIBMPIDhcpRead(ctx context.Context, d *schema.ResourceData, meta i if dhcpServer.Network != nil { dhcpNetwork := dhcpServer.Network if dhcpNetwork.ID != nil { - d.Set(Attr_DhcpNetworkDeprecated, *dhcpNetwork.ID) d.Set(Attr_DhcpNetworkID, *dhcpNetwork.ID) } if dhcpNetwork.Name != nil { diff --git a/ibm/service/power/data_source_ibm_pi_dhcps.go b/ibm/service/power/data_source_ibm_pi_dhcps.go index a95f1935b5..79c2586dae 100644 --- a/ibm/service/power/data_source_ibm_pi_dhcps.go +++ b/ibm/service/power/data_source_ibm_pi_dhcps.go @@ -45,11 +45,6 @@ func DataSourceIBMPIDhcps() *schema.Resource { Computed: true, Description: "The ID of the DHCP Server", }, - Attr_DhcpNetworkDeprecated: { - Type: schema.TypeString, - Computed: true, - Description: "The ID of the DHCP Server private network (deprecated - replaced by network_id)", - }, Attr_DhcpNetworkID: { Type: schema.TypeString, Computed: true, @@ -103,7 +98,6 @@ func dataSourceIBMPIDhcpServersRead(ctx context.Context, d *schema.ResourceData, if dhcpServer.Network != nil { dhcpNetwork := dhcpServer.Network if dhcpNetwork.ID != nil { - d.Set(Attr_DhcpNetworkDeprecated, *dhcpNetwork.ID) d.Set(Attr_DhcpNetworkID, *dhcpNetwork.ID) } if dhcpNetwork.Name != nil { diff --git a/ibm/service/power/data_source_ibm_pi_disaster_recovery_location.go b/ibm/service/power/data_source_ibm_pi_disaster_recovery_location.go index f7f2f3e85c..4c839ab37f 100644 --- a/ibm/service/power/data_source_ibm_pi_disaster_recovery_location.go +++ b/ibm/service/power/data_source_ibm_pi_disaster_recovery_location.go @@ -6,47 +6,50 @@ package power import ( "context" + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "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/helpers" - "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" ) func DataSourceIBMPIDisasterRecoveryLocation() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMPIDisasterRecoveryLocation, Schema: map[string]*schema.Schema{ - helpers.PICloudInstanceId: { - Type: schema.TypeString, + // Arguments + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", Required: true, + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, - // Computed Attributes - PIDRLocation: { - Type: schema.TypeString, + // Attributes + Attr_Location: { Computed: true, - Description: "RegionZone of a site", + Description: "The region zone of a site.", + Type: schema.TypeString, }, - "replication_sites": { - Type: schema.TypeList, - Computed: true, + Attr_ReplicationSites: { + Computed: true, + Description: "List of replication sites.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "is_active": { - Type: schema.TypeBool, - Computed: true, + Attr_IsActive: { + Computed: true, + Description: "Indicates the location is active or not, true if location is active , otherwise it is false.", + Type: schema.TypeBool, }, - PIDRLocation: { - Type: schema.TypeString, - Computed: true, + Attr_Location: { + Computed: true, + Description: "The region zone of the location.", + Type: schema.TypeString, }, }, }, + Type: schema.TypeList, }, }, } @@ -58,7 +61,7 @@ func dataSourceIBMPIDisasterRecoveryLocation(ctx context.Context, d *schema.Reso return diag.FromErr(err) } - cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) drClient := instance.NewIBMPIDisasterRecoveryLocationClient(ctx, sess, cloudInstanceID) drLocationSite, err := drClient.Get() if err != nil { @@ -69,8 +72,8 @@ func dataSourceIBMPIDisasterRecoveryLocation(ctx context.Context, d *schema.Reso for _, i := range drLocationSite.ReplicationSites { if i != nil { l := map[string]interface{}{ - "is_active": i.IsActive, - PIDRLocation: i.Location, + Attr_IsActive: i.IsActive, + Attr_Location: i.Location, } result = append(result, l) } @@ -78,8 +81,8 @@ func dataSourceIBMPIDisasterRecoveryLocation(ctx context.Context, d *schema.Reso var clientgenU, _ = uuid.GenerateUUID() d.SetId(clientgenU) - d.Set(PIDRLocation, drLocationSite.Location) - d.Set("replication_sites", result) + d.Set(Attr_Location, drLocationSite.Location) + d.Set(Attr_ReplicationSites, result) return nil } diff --git a/ibm/service/power/data_source_ibm_pi_disaster_recovery_location_test.go b/ibm/service/power/data_source_ibm_pi_disaster_recovery_location_test.go index 561a451c2a..ef7f68307e 100644 --- a/ibm/service/power/data_source_ibm_pi_disaster_recovery_location_test.go +++ b/ibm/service/power/data_source_ibm_pi_disaster_recovery_location_test.go @@ -30,8 +30,7 @@ func TestAccIBMPIDisasterRecoveryLocationDataSourceBasic(t *testing.T) { func testAccCheckIBMPIDisasterRecoveryLocationDataSourceConfig() string { return fmt.Sprintf(` -data "ibm_pi_disaster_recovery_location" "testacc_disaster_recovery_location" { - pi_cloud_instance_id = "%s" -}`, acc.Pi_cloud_instance_id) - + data "ibm_pi_disaster_recovery_location" "testacc_disaster_recovery_location" { + pi_cloud_instance_id = "%s" + }`, acc.Pi_cloud_instance_id) } diff --git a/ibm/service/power/data_source_ibm_pi_disaster_recovery_locations.go b/ibm/service/power/data_source_ibm_pi_disaster_recovery_locations.go index 49d77fe170..c838348000 100644 --- a/ibm/service/power/data_source_ibm_pi_disaster_recovery_locations.go +++ b/ibm/service/power/data_source_ibm_pi_disaster_recovery_locations.go @@ -6,45 +6,46 @@ package power import ( "context" + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/go-uuid" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" ) func DataSourceIBMPIDisasterRecoveryLocations() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMPIDisasterRecoveryLocations, Schema: map[string]*schema.Schema{ - - // Computed Attributes - "disaster_recovery_locations": { + // Attributes + Attr_DisasterRecoveryLocations: { Type: schema.TypeList, Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - PIDRLocation: { - Type: schema.TypeString, + Attr_Location: { Computed: true, - Description: "RegionZone of a site", + Description: "The region zone of a site.", + Type: schema.TypeString, }, - "replication_sites": { - Type: schema.TypeList, - Computed: true, + Attr_ReplicationSites: { + Computed: true, + Description: "List of Replication Sites.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "is_active": { - Type: schema.TypeBool, - Computed: true, + Attr_IsActive: { + Computed: true, + Description: "Indicates the location is active or not, true if location is active, otherwise it is false.", + Type: schema.TypeBool, }, - PIDRLocation: { - Type: schema.TypeString, - Computed: true, + Attr_Location: { + Computed: true, + Description: "The region zone of the location.", + Type: schema.TypeString, }, }, }, + Type: schema.TypeList, }, }, }, @@ -72,15 +73,15 @@ func dataSourceIBMPIDisasterRecoveryLocations(ctx context.Context, d *schema.Res for _, j := range i.ReplicationSites { if j != nil { r := map[string]interface{}{ - "is_active": j.IsActive, - PIDRLocation: j.Location, + Attr_IsActive: j.IsActive, + Attr_Location: j.Location, } replicationSites = append(replicationSites, r) } } l := map[string]interface{}{ - "location": i.Location, - "replication_sites": replicationSites, + Attr_Location: i.Location, + Attr_ReplicationSites: replicationSites, } results = append(results, l) } @@ -88,7 +89,7 @@ func dataSourceIBMPIDisasterRecoveryLocations(ctx context.Context, d *schema.Res var clientgenU, _ = uuid.GenerateUUID() d.SetId(clientgenU) - d.Set("disaster_recovery_locations", results) + d.Set(Attr_DisasterRecoveryLocations, results) return nil } diff --git a/ibm/service/power/data_source_ibm_pi_disaster_recovery_locations_test.go b/ibm/service/power/data_source_ibm_pi_disaster_recovery_locations_test.go index 6320f451b3..49b3e3b47f 100644 --- a/ibm/service/power/data_source_ibm_pi_disaster_recovery_locations_test.go +++ b/ibm/service/power/data_source_ibm_pi_disaster_recovery_locations_test.go @@ -27,5 +27,5 @@ func TestAccIBMPIDisasterRecoveryLocationsDataSourceBasic(t *testing.T) { } func testAccCheckIBMPIDisasterRecoveryLocationsDataSourceConfig() string { - return "data \"ibm_pi_disaster_recovery_locations\" \"testacc_disaster_recovery_locations\" {}" + return `data "ibm_pi_disaster_recovery_locations" "testacc_disaster_recovery_locations" {}` } diff --git a/ibm/service/power/data_source_ibm_pi_image.go b/ibm/service/power/data_source_ibm_pi_image.go index c88a51a55e..7b72b1430b 100644 --- a/ibm/service/power/data_source_ibm_pi_image.go +++ b/ibm/service/power/data_source_ibm_pi_image.go @@ -6,65 +6,72 @@ package power import ( "context" - "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/power-go-client/clients/instance" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - //"fmt" - "github.com/IBM-Cloud/power-go-client/clients/instance" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) func DataSourceIBMPIImage() *schema.Resource { - return &schema.Resource{ ReadContext: dataSourceIBMPIImagesRead, Schema: map[string]*schema.Schema{ - - helpers.PIImageName: { - Type: schema.TypeString, + // Arguments + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", Required: true, - Description: "Imagename Name to be used for pvminstances", + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, - helpers.PICloudInstanceId: { - Type: schema.TypeString, + Arg_ImageName: { + Description: "The ID of the image.", Required: true, + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, - "state": { - Type: schema.TypeString, - Computed: true, + // Attributes + Attr_Architecture: { + Computed: true, + Description: "The CPU architecture that the image is designed for. ", + Type: schema.TypeString, }, - "size": { - Type: schema.TypeInt, - Computed: true, + Attr_Hypervisor: { + Computed: true, + Description: "Hypervision Type.", + Type: schema.TypeString, }, - "architecture": { - Type: schema.TypeString, - Computed: true, + Attr_ImageType: { + Computed: true, + Description: "The identifier of this image type.", + Type: schema.TypeString, }, - "operatingsystem": { - Type: schema.TypeString, - Computed: true, + // TODO: Relabel this one "operating_system" to match catalog images + Attr_OperatingSystem: { + Computed: true, + Description: "The operating system that is installed with the image.", + Type: schema.TypeString, }, - "hypervisor": { - Type: schema.TypeString, - Computed: true, + Attr_Size: { + Computed: true, + Description: "The size of the image in megabytes.", + Type: schema.TypeInt, }, - "storage_type": { - Type: schema.TypeString, - Computed: true, + Attr_State: { + Computed: true, + Description: "The state for this image. ", + Type: schema.TypeString, }, - "storage_pool": { - Type: schema.TypeString, - Computed: true, + Attr_StoragePool: { + Computed: true, + Description: "Storage pool where image resides.", + Type: schema.TypeString, }, - "image_type": { - Type: schema.TypeString, - Computed: true, + Attr_StorageType: { + Computed: true, + Description: "The storage type for this image.", + Type: schema.TypeString, }, }, } @@ -76,24 +83,23 @@ func dataSourceIBMPIImagesRead(ctx context.Context, d *schema.ResourceData, meta return diag.FromErr(err) } - cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) imageC := instance.NewIBMPIImageClient(ctx, sess, cloudInstanceID) - imagedata, err := imageC.Get(d.Get(helpers.PIImageName).(string)) + imagedata, err := imageC.Get(d.Get(Arg_ImageName).(string)) if err != nil { return diag.FromErr(err) } d.SetId(*imagedata.ImageID) - d.Set("state", imagedata.State) - d.Set("size", imagedata.Size) - d.Set("architecture", imagedata.Specifications.Architecture) - d.Set("hypervisor", imagedata.Specifications.HypervisorType) - d.Set("operatingsystem", imagedata.Specifications.OperatingSystem) - d.Set("storage_type", imagedata.StorageType) - d.Set("storage_pool", imagedata.StoragePool) - d.Set("image_type", imagedata.Specifications.ImageType) + d.Set(Attr_Architecture, imagedata.Specifications.Architecture) + d.Set(Attr_Hypervisor, imagedata.Specifications.HypervisorType) + d.Set(Attr_ImageType, imagedata.Specifications.ImageType) + d.Set(Attr_OperatingSystem, imagedata.Specifications.OperatingSystem) + d.Set(Attr_Size, imagedata.Size) + d.Set(Attr_State, imagedata.State) + d.Set(Attr_StoragePool, imagedata.StoragePool) + d.Set(Attr_StorageType, imagedata.StorageType) return nil - } diff --git a/ibm/service/power/data_source_ibm_pi_image_test.go b/ibm/service/power/data_source_ibm_pi_image_test.go index 539aa9950e..734d3b71b7 100644 --- a/ibm/service/power/data_source_ibm_pi_image_test.go +++ b/ibm/service/power/data_source_ibm_pi_image_test.go @@ -13,7 +13,6 @@ import ( ) func TestAccIBMPIImageDataSource_basic(t *testing.T) { - resource.Test(t, resource.TestCase{ PreCheck: func() { acc.TestAccPreCheck(t) }, Providers: acc.TestAccProviders, @@ -30,9 +29,8 @@ func TestAccIBMPIImageDataSource_basic(t *testing.T) { func testAccCheckIBMPIImageDataSourceConfig() string { return fmt.Sprintf(` - data "ibm_pi_image" "testacc_ds_image" { - pi_image_name = "%s" - pi_cloud_instance_id = "%s" - }`, acc.Pi_image, acc.Pi_cloud_instance_id) - + data "ibm_pi_image" "testacc_ds_image" { + pi_image_name = "%s" + pi_cloud_instance_id = "%s" + }`, acc.Pi_image, acc.Pi_cloud_instance_id) } diff --git a/ibm/service/power/data_source_ibm_pi_images.go b/ibm/service/power/data_source_ibm_pi_images.go index 9b6782aa9f..e3a8936325 100644 --- a/ibm/service/power/data_source_ibm_pi_images.go +++ b/ibm/service/power/data_source_ibm_pi_images.go @@ -6,70 +6,72 @@ package power import ( "context" - "github.com/IBM-Cloud/power-go-client/helpers" + "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" "github.com/hashicorp/go-uuid" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - //"fmt" - "github.com/IBM-Cloud/power-go-client/clients/instance" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) -/* -Datasource to get the list of images that are available when a power instance is created -*/ +// Datasource to list images that are available when a power instance is created func DataSourceIBMPIImages() *schema.Resource { - return &schema.Resource{ ReadContext: dataSourceIBMPIImagesAllRead, Schema: map[string]*schema.Schema{ - - helpers.PICloudInstanceId: { - Type: schema.TypeString, + // Arguments + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", Required: true, + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, - // Computed Attributes - - "image_info": { - Type: schema.TypeList, - Computed: true, + // Attributes + Attr_ImageInfo: { + Computed: true, + Description: "List of all supported images.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, + Attr_Href: { + Computed: true, + Description: "The hyper link of an image.", + Type: schema.TypeString, }, - "name": { - Type: schema.TypeString, - Computed: true, + Attr_ID: { + Computed: true, + Description: "The unique identifier of an image.", + Type: schema.TypeString, }, - "href": { - Type: schema.TypeString, - Computed: true, + Attr_ImageType: { + Computed: true, + Description: "The identifier of this image type.", + Type: schema.TypeString, }, - "state": { - Type: schema.TypeString, - Computed: true, + Attr_Name: { + Computed: true, + Description: "The name of an image.", + Type: schema.TypeString, }, - "storage_type": { - Type: schema.TypeString, - Computed: true, + Attr_State: { + Computed: true, + Description: "The state of an image.", + Type: schema.TypeString, }, - "storage_pool": { - Type: schema.TypeString, - Computed: true, + Attr_StoragePool: { + Computed: true, + Description: "Storage pool where image resides.", + Type: schema.TypeString, }, - "image_type": { - Type: schema.TypeString, - Computed: true, + Attr_StorageType: { + Computed: true, + Description: "The storage type of an image.", + Type: schema.TypeString, }, }, }, + Type: schema.TypeList, }, }, } @@ -81,7 +83,7 @@ func dataSourceIBMPIImagesAllRead(ctx context.Context, d *schema.ResourceData, m return diag.FromErr(err) } - cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) imageC := instance.NewIBMPIImageClient(ctx, sess, cloudInstanceID) imagedata, err := imageC.GetAll() @@ -91,28 +93,24 @@ func dataSourceIBMPIImagesAllRead(ctx context.Context, d *schema.ResourceData, m var clientgenU, _ = uuid.GenerateUUID() d.SetId(clientgenU) - d.Set("image_info", flattenStockImages(imagedata.Images)) + d.Set(Attr_ImageInfo, flattenStockImages(imagedata.Images)) return nil - } func flattenStockImages(list []*models.ImageReference) []map[string]interface{} { result := make([]map[string]interface{}, 0, len(list)) for _, i := range list { - l := map[string]interface{}{ - "id": *i.ImageID, - "state": *i.State, - "href": *i.Href, - "name": *i.Name, - "storage_type": *i.StorageType, - "storage_pool": *i.StoragePool, - "image_type": i.Specifications.ImageType, + Attr_Href: *i.Href, + Attr_ID: *i.ImageID, + Attr_ImageType: i.Specifications.ImageType, + Attr_Name: *i.Name, + Attr_State: *i.State, + Attr_StoragePool: *i.StoragePool, + Attr_StorageType: *i.StorageType, } - result = append(result, l) - } return result } diff --git a/ibm/service/power/data_source_ibm_pi_images_test.go b/ibm/service/power/data_source_ibm_pi_images_test.go index 083de54094..ee670de149 100644 --- a/ibm/service/power/data_source_ibm_pi_images_test.go +++ b/ibm/service/power/data_source_ibm_pi_images_test.go @@ -13,7 +13,6 @@ import ( ) func TestAccIBMPIImagesDataSource_basic(t *testing.T) { - resource.Test(t, resource.TestCase{ PreCheck: func() { acc.TestAccPreCheck(t) }, Providers: acc.TestAccProviders, @@ -30,8 +29,7 @@ func TestAccIBMPIImagesDataSource_basic(t *testing.T) { func testAccCheckIBMPIImagesDataSourceConfig() string { return fmt.Sprintf(` - data "ibm_pi_images" "testacc_ds_image" { - pi_cloud_instance_id = "%s" - }`, acc.Pi_cloud_instance_id) - + data "ibm_pi_images" "testacc_ds_image" { + pi_cloud_instance_id = "%s" + }`, acc.Pi_cloud_instance_id) } diff --git a/ibm/service/power/data_source_ibm_pi_instance.go b/ibm/service/power/data_source_ibm_pi_instance.go index 354cfe951b..0c77d7a78a 100644 --- a/ibm/service/power/data_source_ibm_pi_instance.go +++ b/ibm/service/power/data_source_ibm_pi_instance.go @@ -52,39 +52,6 @@ func DataSourceIBMPIInstance() *schema.Resource { Type: schema.TypeString, Computed: true, }, - "addresses": { - Type: schema.TypeList, - Computed: true, - Deprecated: "This field is deprecated, use networks instead", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "ip": { - Type: schema.TypeString, - Computed: true, - }, - "macaddress": { - Type: schema.TypeString, - Computed: true, - }, - "network_id": { - Type: schema.TypeString, - Computed: true, - }, - "network_name": { - Type: schema.TypeString, - Computed: true, - }, - "type": { - Type: schema.TypeString, - Computed: true, - }, - "external_ip": { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, "networks": { Type: schema.TypeList, Computed: true, @@ -195,6 +162,26 @@ func DataSourceIBMPIInstance() *schema.Resource { Type: schema.TypeString, Computed: true, }, + Attr_IBMiCSS: { + Type: schema.TypeBool, + Computed: true, + Description: "IBMi Cloud Storage Solution", + }, + Attr_IBMiPHA: { + Type: schema.TypeBool, + Computed: true, + Description: "IBMi Power High Availability", + }, + Attr_IBMiRDS: { + Type: schema.TypeBool, + Computed: true, + Description: "IBMi Rational Dev Studio", + }, + Attr_IBMiRDSUsers: { + Type: schema.TypeInt, + Computed: true, + Description: "IBMi Rational Dev Studio Number of User Licenses", + }, }, } } @@ -243,24 +230,20 @@ func dataSourceIBMPIInstancesRead(ctx context.Context, d *schema.ResourceData, m d.Set(Attr_PIInstanceSharedProcessorPool, powervmdata.SharedProcessorPool) d.Set(Attr_PIInstanceSharedProcessorPoolID, powervmdata.SharedProcessorPoolID) - if powervmdata.Addresses != nil { - pvmaddress := make([]map[string]interface{}, len(powervmdata.Addresses)) - for i, pvmip := range powervmdata.Addresses { - p := make(map[string]interface{}) - p["ip"] = pvmip.IPAddress - p["network_name"] = pvmip.NetworkName - p["network_id"] = pvmip.NetworkID - p["macaddress"] = pvmip.MacAddress - p["type"] = pvmip.Type - p["external_ip"] = pvmip.ExternalIP - pvmaddress[i] = p - } - d.Set("addresses", pvmaddress) - } - if powervmdata.Health != nil { d.Set("health_status", powervmdata.Health.Status) } + if powervmdata.SoftwareLicenses != nil { + d.Set(Attr_IBMiCSS, powervmdata.SoftwareLicenses.IbmiCSS) + d.Set(Attr_IBMiPHA, powervmdata.SoftwareLicenses.IbmiPHA) + d.Set(Attr_IBMiRDS, powervmdata.SoftwareLicenses.IbmiRDS) + if *powervmdata.SoftwareLicenses.IbmiRDS { + d.Set(Attr_IBMiRDSUsers, powervmdata.SoftwareLicenses.IbmiRDSUsers) + } else { + d.Set(Attr_IBMiRDSUsers, 0) + } + } + return nil } diff --git a/ibm/service/power/data_source_ibm_pi_instance_console_languages.go b/ibm/service/power/data_source_ibm_pi_instance_console_languages.go index e5cb5b344d..d34dad28fb 100644 --- a/ibm/service/power/data_source_ibm_pi_instance_console_languages.go +++ b/ibm/service/power/data_source_ibm_pi_instance_console_languages.go @@ -6,59 +6,52 @@ package power import ( "context" - "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/power-go-client/clients/instance" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/go-uuid" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM-Cloud/power-go-client/clients/instance" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) -const ( - ConsoleLanguages = "console_languages" - ConsoleLanguageCode = "code" - ConsoleLanguageDesc = "language" -) - -/* -Datasource to get the list of available console languages for an instance -*/ +// Datasource to list available console languages for an instance func DataSourceIBMPIInstanceConsoleLanguages() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMPIInstanceConsoleLanguagesRead, Schema: map[string]*schema.Schema{ - helpers.PICloudInstanceId: { - Type: schema.TypeString, + // Arguments + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", Required: true, + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, - helpers.PIInstanceName: { - Type: schema.TypeString, + Arg_InstanceName: { + Description: "The unique identifier or name of the instance.", Required: true, - Description: "The unique identifier or name of the instance", + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, - // Computed Attributes - ConsoleLanguages: { - Type: schema.TypeList, - Computed: true, + // Attributes + Attr_ConsoleLanguages: { + Computed: true, + Description: "List of all the Console Languages.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - ConsoleLanguageCode: { - Type: schema.TypeString, + Attr_Code: { Computed: true, - Description: "language code", - }, - ConsoleLanguageDesc: { + Description: "Language code.", Type: schema.TypeString, + }, + Attr_Language: { Computed: true, - Description: "language description", + Description: "Language description.", + Type: schema.TypeString, }, }, }, + Type: schema.TypeList, }, }, } @@ -70,8 +63,8 @@ func dataSourceIBMPIInstanceConsoleLanguagesRead(ctx context.Context, d *schema. return diag.FromErr(err) } - cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) - instanceName := d.Get(helpers.PIInstanceName).(string) + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) + instanceName := d.Get(Arg_InstanceName).(string) client := instance.NewIBMPIInstanceClient(ctx, sess, cloudInstanceID) languages, err := client.GetConsoleLanguages(instanceName) @@ -86,12 +79,12 @@ func dataSourceIBMPIInstanceConsoleLanguagesRead(ctx context.Context, d *schema. result := make([]map[string]interface{}, 0, len(languages.ConsoleLanguages)) for _, language := range languages.ConsoleLanguages { l := map[string]interface{}{ - ConsoleLanguageCode: *language.Code, - ConsoleLanguageDesc: language.Language, + Attr_Code: *language.Code, + Attr_Language: language.Language, } result = append(result, l) } - d.Set(ConsoleLanguages, result) + d.Set(Attr_ConsoleLanguages, result) } return nil diff --git a/ibm/service/power/data_source_ibm_pi_instance_console_languages_test.go b/ibm/service/power/data_source_ibm_pi_instance_console_languages_test.go index acadb056e0..9d52aa963f 100644 --- a/ibm/service/power/data_source_ibm_pi_instance_console_languages_test.go +++ b/ibm/service/power/data_source_ibm_pi_instance_console_languages_test.go @@ -30,8 +30,8 @@ func TestAccIBMPIInstanceConsoleLanguages(t *testing.T) { func testAccCheckIBMPIInstanceConsoleLanguagesConfig() string { return fmt.Sprintf(` - data "ibm_pi_console_languages" "example" { - pi_cloud_instance_id = "%s" - pi_instance_name = "%s" - }`, acc.Pi_cloud_instance_id, acc.Pi_instance_name) + data "ibm_pi_console_languages" "example" { + pi_cloud_instance_id = "%s" + pi_instance_name = "%s" + }`, acc.Pi_cloud_instance_id, acc.Pi_instance_name) } diff --git a/ibm/service/power/data_source_ibm_pi_instance_ip.go b/ibm/service/power/data_source_ibm_pi_instance_ip.go index 4d57021d36..60cac39d42 100644 --- a/ibm/service/power/data_source_ibm_pi_instance_ip.go +++ b/ibm/service/power/data_source_ibm_pi_instance_ip.go @@ -10,7 +10,6 @@ import ( "strconv" "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/IBM-Cloud/power-go-client/helpers" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -18,51 +17,59 @@ import ( ) func DataSourceIBMPIInstanceIP() *schema.Resource { - return &schema.Resource{ ReadContext: dataSourceIBMPIInstancesIPRead, Schema: map[string]*schema.Schema{ - helpers.PIInstanceName: { - Type: schema.TypeString, + // Arguments + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", Required: true, - Description: "Server Name to be used for pvminstances", + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, - helpers.PICloudInstanceId: { - Type: schema.TypeString, + Arg_InstanceName: { + Description: "The unique identifier or name of the instance.", Required: true, + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, - helpers.PINetworkName: { + Arg_NetworkName: { + Description: "The subnet that the instance belongs to.", Type: schema.TypeString, Required: true, ValidateFunc: validation.NoZeroValues, }, - // Computed attributes - "ip": { - Type: schema.TypeString, - Computed: true, + // Attributes + Attr_ExternalIP: { + Computed: true, + Description: "The external IP of the network that is attached to this instance.", + Type: schema.TypeString, }, - "ipoctet": { - Type: schema.TypeString, - Computed: true, + Attr_IP: { + Computed: true, + Description: "The IP address that is attached to this instance from the subnet.", + Type: schema.TypeString, }, - "macaddress": { - Type: schema.TypeString, - Computed: true, + Attr_IPOctet: { + Computed: true, + Description: "The IP octet of the network that is attached to this instance.", + Type: schema.TypeString, }, - "network_id": { - Type: schema.TypeString, - Computed: true, + Attr_MacAddress: { + Computed: true, + Description: "The MAC address of the network that is attached to this instance.", + Type: schema.TypeString, }, - "type": { - Type: schema.TypeString, - Computed: true, + Attr_NetworkID: { + Computed: true, + Description: "ID of the network.", + Type: schema.TypeString, }, - "external_ip": { - Type: schema.TypeString, - Computed: true, + Attr_Type: { + Computed: true, + Description: "The type of the network that is attached to this instance.", + Type: schema.TypeString, }, }, } @@ -74,11 +81,11 @@ func dataSourceIBMPIInstancesIPRead(ctx context.Context, d *schema.ResourceData, return diag.FromErr(err) } - cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) - networkName := d.Get(helpers.PINetworkName).(string) + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) + networkName := d.Get(Arg_NetworkName).(string) powerC := instance.NewIBMPIInstanceClient(ctx, sess, cloudInstanceID) - powervmdata, err := powerC.Get(d.Get(helpers.PIInstanceName).(string)) + powervmdata, err := powerC.Get(d.Get(Arg_InstanceName).(string)) if err != nil { return diag.FromErr(err) } @@ -87,17 +94,16 @@ func dataSourceIBMPIInstancesIPRead(ctx context.Context, d *schema.ResourceData, if network.NetworkName == networkName { log.Printf("Printing the ip %s", network.IPAddress) d.SetId(network.NetworkID) - d.Set("ip", network.IPAddress) - d.Set("network_id", network.NetworkID) - d.Set("macaddress", network.MacAddress) - d.Set("external_ip", network.ExternalIP) - d.Set("type", network.Type) + d.Set(Attr_ExternalIP, network.ExternalIP) + d.Set(Attr_IP, network.IPAddress) + d.Set(Attr_MacAddress, network.MacAddress) + d.Set(Attr_NetworkID, network.NetworkID) + d.Set(Attr_Type, network.Type) IPObject := net.ParseIP(network.IPAddress).To4() if len(IPObject) > 0 { - d.Set("ipoctet", strconv.Itoa(int(IPObject[3]))) + d.Set(Attr_IPOctet, strconv.Itoa(int(IPObject[3]))) } - return nil } } diff --git a/ibm/service/power/data_source_ibm_pi_instance_ip_test.go b/ibm/service/power/data_source_ibm_pi_instance_ip_test.go index 36362776a8..b8963ee639 100644 --- a/ibm/service/power/data_source_ibm_pi_instance_ip_test.go +++ b/ibm/service/power/data_source_ibm_pi_instance_ip_test.go @@ -29,10 +29,9 @@ func TestAccIBMPIInstanceIPDataSource_basic(t *testing.T) { func testAccCheckIBMPIInstanceIPDataSourceConfig() string { return fmt.Sprintf(` - data "ibm_pi_instance_ip" "testacc_ds_instance_ip" { - pi_network_name = "%[1]s" - pi_instance_name = "%[2]s" - pi_cloud_instance_id = "%[3]s" - } - `, acc.Pi_network_name, acc.Pi_instance_name, acc.Pi_cloud_instance_id) + data "ibm_pi_instance_ip" "testacc_ds_instance_ip" { + pi_network_name = "%[1]s" + pi_instance_name = "%[2]s" + pi_cloud_instance_id = "%[3]s" + }`, acc.Pi_network_name, acc.Pi_instance_name, acc.Pi_cloud_instance_id) } diff --git a/ibm/service/power/data_source_ibm_pi_instance_snapshot.go b/ibm/service/power/data_source_ibm_pi_instance_snapshot.go new file mode 100644 index 0000000000..d57f666b4b --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_instance_snapshot.go @@ -0,0 +1,102 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "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" +) + +func DataSourceIBMPIInstanceSnapshot() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMPIInstanceSnapshotRead, + Schema: map[string]*schema.Schema{ + // Arguments + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, + }, + Arg_SnapshotID: { + Description: "The unique identifier of the Power Systems Virtual Machine instance snapshot.", + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, + }, + + // Attributes + Attr_Action: { + Computed: true, + Description: "Action performed on the instance snapshot.", + Type: schema.TypeString, + }, + Attr_CreationDate: { + Computed: true, + Description: "Date of snapshot creation.", + Type: schema.TypeString, + }, + Attr_Description: { + Computed: true, + Description: "The description of the snapshot.", + Type: schema.TypeString, + }, + Attr_LastUpdatedDate: { + Computed: true, + Description: "Date of last update.", + Type: schema.TypeString, + }, + Attr_Name: { + Computed: true, + Description: "The name of the Power Systems Virtual Machine instance snapshot.", + Type: schema.TypeString, + }, + Attr_PercentComplete: { + Computed: true, + Description: "The snapshot completion percentage.", + Type: schema.TypeInt, + }, + Attr_Status: { + Computed: true, + Description: "The status of the Power Virtual Machine instance snapshot.", + Type: schema.TypeString, + }, + Attr_VolumeSnapshots: { + Computed: true, + Description: "A map of volume snapshots included in the Power Virtual Machine instance snapshot.", + Type: schema.TypeMap, + }, + }, + } +} + +func dataSourceIBMPIInstanceSnapshotRead(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) + snapshot := instance.NewIBMPISnapshotClient(ctx, sess, cloudInstanceID) + snapshotData, err := snapshot.Get(d.Get(Arg_SnapshotID).(string)) + if err != nil { + return diag.FromErr(err) + } + + d.SetId(*snapshotData.SnapshotID) + d.Set(Attr_Action, snapshotData.Action) + d.Set(Attr_CreationDate, snapshotData.CreationDate.String()) + d.Set(Attr_Description, snapshotData.Description) + d.Set(Attr_LastUpdatedDate, snapshotData.LastUpdateDate.String()) + d.Set(Attr_Name, snapshotData.Name) + d.Set(Attr_PercentComplete, snapshotData.PercentComplete) + d.Set(Attr_Status, snapshotData.Status) + d.Set(Attr_VolumeSnapshots, snapshotData.VolumeSnapshots) + return nil +} diff --git a/ibm/service/power/data_source_ibm_pi_instance_snapshot_test.go b/ibm/service/power/data_source_ibm_pi_instance_snapshot_test.go new file mode 100644 index 0000000000..0ef17d9344 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_instance_snapshot_test.go @@ -0,0 +1,36 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMPIInstanceSnapshotDataSource_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIInstanceSnapshotDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_pi_instance_snapshot.testacc_ds_snapshot", "id"), + ), + }, + }, + }) +} + +func testAccCheckIBMPIInstanceSnapshotDataSourceConfig() string { + return fmt.Sprintf(` + data "ibm_pi_instance_snapshot" "testacc_ds_snapshot" { + pi_cloud_instance_id = "%s" + pi_snapshot_id = "%s" + }`, acc.Pi_cloud_instance_id, acc.Pi_snapshot_id) +} diff --git a/ibm/service/power/data_source_ibm_pi_instance_snapshots.go b/ibm/service/power/data_source_ibm_pi_instance_snapshots.go new file mode 100644 index 0000000000..dad1bd7f61 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_instance_snapshots.go @@ -0,0 +1,128 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "log" + + "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" + "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" +) + +func DataSourceIBMPIInstanceSnapshots() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMPIInstanceSnapshotsRead, + 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_InstanceSnapshots: { + Computed: true, + Description: "List of Power Virtual Machine instance snapshots within the given cloud instance.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_Action: { + Computed: true, + Description: "Action performed on the instance snapshot.", + Type: schema.TypeString, + }, + Attr_CreationDate: { + Computed: true, + Description: "Date of snapshot creation.", + Type: schema.TypeString, + }, + Attr_Description: { + Computed: true, + Description: "The description of the snapshot.", + Type: schema.TypeString, + }, + Attr_ID: { + Computed: true, + Description: "The unique identifier of the Power Systems Virtual Machine instance snapshot.", + Type: schema.TypeString, + }, + Attr_LastUpdatedDate: { + Computed: true, + Description: "Date of last update.", + Type: schema.TypeString, + }, + Attr_Name: { + Computed: true, + Description: "The name of the Power Systems Virtual Machine instance snapshot.", + Type: schema.TypeString, + }, + Attr_PercentComplete: { + Computed: true, + Description: "The snapshot completion percentage.", + Type: schema.TypeInt, + }, + Attr_Status: { + Computed: true, + Description: "The status of the Power Virtual Machine instance snapshot.", + Type: schema.TypeString, + }, + Attr_VolumeSnapshots: { + Computed: true, + Description: "A map of volume snapshots included in the Power Virtual Machine instance snapshot.", + Type: schema.TypeMap, + }, + }, + }, + Type: schema.TypeList, + }, + }, + } +} + +func dataSourceIBMPIInstanceSnapshotsRead(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) + snapshot := instance.NewIBMPISnapshotClient(ctx, sess, cloudInstanceID) + snapshotData, err := snapshot.GetAll() + if err != nil { + return diag.FromErr(err) + } + + var clientgenU, _ = uuid.GenerateUUID() + d.SetId(clientgenU) + d.Set(Attr_InstanceSnapshots, flattenSnapshotsInstances(snapshotData.Snapshots)) + + return nil +} + +func flattenSnapshotsInstances(list []*models.Snapshot) []map[string]interface{} { + log.Printf("Calling the flattenSnapshotsInstances call with list %d", len(list)) + result := make([]map[string]interface{}, 0, len(list)) + for _, i := range list { + l := map[string]interface{}{ + Attr_Action: i.Action, + Attr_CreationDate: i.CreationDate.String(), + Attr_Description: i.Description, + Attr_ID: *i.SnapshotID, + Attr_LastUpdatedDate: i.LastUpdateDate.String(), + Attr_Name: *i.Name, + Attr_PercentComplete: i.PercentComplete, + Attr_Status: i.Status, + Attr_VolumeSnapshots: i.VolumeSnapshots, + } + result = append(result, l) + } + return result +} diff --git a/ibm/service/power/data_source_ibm_pi_snapshots_test.go b/ibm/service/power/data_source_ibm_pi_instance_snapshots_test.go similarity index 66% rename from ibm/service/power/data_source_ibm_pi_snapshots_test.go rename to ibm/service/power/data_source_ibm_pi_instance_snapshots_test.go index be8d385d8a..f508671d50 100644 --- a/ibm/service/power/data_source_ibm_pi_snapshots_test.go +++ b/ibm/service/power/data_source_ibm_pi_instance_snapshots_test.go @@ -12,14 +12,13 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) -func TestAccIBMPISnapshotsDataSource_basic(t *testing.T) { - +func TestAccIBMPIInstanceSnapshotsDataSource_basic(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { acc.TestAccPreCheck(t) }, Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { - Config: testAccCheckIBMPISnapshotsDataSourceConfig(), + Config: testAccCheckIBMPIInstanceSnapshotsDataSourceConfig(), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.ibm_pi_instance_snapshots.testacc_ds_snapshots", "id"), ), @@ -28,11 +27,9 @@ func TestAccIBMPISnapshotsDataSource_basic(t *testing.T) { }) } -func testAccCheckIBMPISnapshotsDataSourceConfig() string { +func testAccCheckIBMPIInstanceSnapshotsDataSourceConfig() string { return fmt.Sprintf(` - -data "ibm_pi_instance_snapshots" "testacc_ds_snapshots" { - pi_cloud_instance_id = "%s" -}`, acc.Pi_cloud_instance_id) - + data "ibm_pi_instance_snapshots" "testacc_ds_snapshots" { + pi_cloud_instance_id = "%s" + }`, acc.Pi_cloud_instance_id) } diff --git a/ibm/service/power/data_source_ibm_pi_instance_volumes.go b/ibm/service/power/data_source_ibm_pi_instance_volumes.go index 611ef5cf62..0bd9b2a09e 100644 --- a/ibm/service/power/data_source_ibm_pi_instance_volumes.go +++ b/ibm/service/power/data_source_ibm_pi_instance_volumes.go @@ -6,82 +6,92 @@ package power import ( "context" - "github.com/IBM-Cloud/power-go-client/helpers" + "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" "github.com/hashicorp/go-uuid" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM-Cloud/power-go-client/clients/instance" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) func DataSourceIBMPIInstanceVolumes() *schema.Resource { - return &schema.Resource{ ReadContext: dataSourceIBMPIInstanceVolumesRead, Schema: map[string]*schema.Schema{ - helpers.PIInstanceName: { - Type: schema.TypeString, + // Arguments + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", Required: true, - Description: "Instance Name to be used for pvminstances", + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, - helpers.PICloudInstanceId: { - Type: schema.TypeString, + Arg_InstanceName: { + Description: "The unique identifier or name of the instance.", Required: true, + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, - //Computed Attributes - "boot_volume_id": { - Type: schema.TypeString, - Computed: true, + // Attribute + Attr_BootVolumeID: { + Computed: true, + Description: "The unique identifier of the boot volume.", + Type: schema.TypeString, }, - "instance_volumes": { - Type: schema.TypeList, - Computed: true, + Attr_InstanceVolumes: { + Computed: true, + Description: "List of volumes attached to instance.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, + Attr_Bootable: { + Computed: true, + Description: "Indicates if the volume is boot capable.", + Type: schema.TypeBool, }, - "size": { - Type: schema.TypeFloat, - Computed: true, + Attr_Href: { + Computed: true, + Description: "The hyper link of the volume.", + Type: schema.TypeString, }, - "href": { - Type: schema.TypeString, - Computed: true, + Attr_ID: { + Computed: true, + Description: "The unique identifier of the volume.", + Type: schema.TypeString, }, - "name": { - Type: schema.TypeString, - Computed: true, + Attr_Name: { + Computed: true, + Description: "The name of the volume.", + Type: schema.TypeString, }, - "state": { - Type: schema.TypeString, - Computed: true, + Attr_Pool: { + Computed: true, + Description: "Volume pool, name of storage pool where the volume is located.", + Type: schema.TypeString, }, - "type": { - Type: schema.TypeString, - Computed: true, + Attr_Shareable: { + Computed: true, + Description: "Indicates if the volume is shareable between VMs.", + Type: schema.TypeBool, }, - "pool": { - Type: schema.TypeString, - Computed: true, + Attr_Size: { + Computed: true, + Description: "The size of this volume in gigabytes.", + Type: schema.TypeFloat, }, - "shareable": { - Type: schema.TypeBool, - Computed: true, + Attr_State: { + Computed: true, + Description: "The state of the volume.", + Type: schema.TypeString, }, - "bootable": { - Type: schema.TypeBool, - Computed: true, + Attr_Type: { + Computed: true, + Description: "The disk type that is used for this volume.", + Type: schema.TypeString, }, }, }, + Type: schema.TypeList, }, }, } @@ -93,38 +103,36 @@ func dataSourceIBMPIInstanceVolumesRead(ctx context.Context, d *schema.ResourceD return diag.FromErr(err) } - cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) volumeC := instance.NewIBMPIVolumeClient(ctx, sess, cloudInstanceID) - volumedata, err := volumeC.GetAllInstanceVolumes(d.Get(helpers.PIInstanceName).(string)) + volumedata, err := volumeC.GetAllInstanceVolumes(d.Get(Arg_InstanceName).(string)) if err != nil { return diag.FromErr(err) } var clientgenU, _ = uuid.GenerateUUID() d.SetId(clientgenU) - d.Set("boot_volume_id", *volumedata.Volumes[0].VolumeID) - d.Set("instance_volumes", flattenVolumesInstances(volumedata.Volumes)) + d.Set(Attr_BootVolumeID, *volumedata.Volumes[0].VolumeID) + d.Set(Attr_InstanceVolumes, flattenVolumesInstances(volumedata.Volumes)) return nil - } func flattenVolumesInstances(list []*models.VolumeReference) []map[string]interface{} { result := make([]map[string]interface{}, 0, len(list)) for _, i := range list { l := map[string]interface{}{ - "id": *i.VolumeID, - "state": *i.State, - "href": *i.Href, - "name": *i.Name, - "size": *i.Size, - "type": *i.DiskType, - "pool": i.VolumePool, - "shareable": *i.Shareable, - "bootable": *i.Bootable, + Attr_Bootable: *i.Bootable, + Attr_Href: *i.Href, + Attr_ID: *i.VolumeID, + Attr_Name: *i.Name, + Attr_Pool: i.VolumePool, + Attr_Shareable: *i.Shareable, + Attr_Size: *i.Size, + Attr_State: *i.State, + Attr_Type: *i.DiskType, } - result = append(result, l) } return result diff --git a/ibm/service/power/data_source_ibm_pi_instance_volumes_test.go b/ibm/service/power/data_source_ibm_pi_instance_volumes_test.go index 211c17b9e7..10543c5a66 100644 --- a/ibm/service/power/data_source_ibm_pi_instance_volumes_test.go +++ b/ibm/service/power/data_source_ibm_pi_instance_volumes_test.go @@ -31,9 +31,8 @@ func TestAccIBMPIVolumesDataSource_basic(t *testing.T) { func testAccCheckIBMPIVolumesDataSourceConfig(name string) string { return fmt.Sprintf(` -data "ibm_pi_instance_volumes" "testacc_ds_volumes" { - pi_instance_name = "%s" - pi_cloud_instance_id = "%s" -}`, acc.Pi_instance_name, acc.Pi_cloud_instance_id) - + data "ibm_pi_instance_volumes" "testacc_ds_volumes" { + pi_instance_name = "%s" + pi_cloud_instance_id = "%s" + }`, acc.Pi_instance_name, acc.Pi_cloud_instance_id) } diff --git a/ibm/service/power/data_source_ibm_pi_key.go b/ibm/service/power/data_source_ibm_pi_key.go index 70ab96ba7c..b7f928828f 100644 --- a/ibm/service/power/data_source_ibm_pi_key.go +++ b/ibm/service/power/data_source_ibm_pi_key.go @@ -6,79 +6,65 @@ package power import ( "context" - "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/helpers" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "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" ) func DataSourceIBMPIKey() *schema.Resource { - return &schema.Resource{ ReadContext: dataSourceIBMPIKeyRead, Schema: map[string]*schema.Schema{ - // Arguments - Arg_KeyName: { - Type: schema.TypeString, + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", Required: true, - Description: "SSH key name for a pcloud tenant", + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, - Arg_CloudInstanceID: { - Type: schema.TypeString, + Arg_KeyName: { Required: true, + Description: "User defined name for the SSH key.", ValidateFunc: validation.NoZeroValues, + Type: schema.TypeString, }, // Attributes - Attr_KeyCreationDate: { - Type: schema.TypeString, + Attr_CreationDate: { Computed: true, - Description: "Date of sshkey creation", - }, - Attr_Key: { + Description: "Date of SSH Key creation.", Type: schema.TypeString, - Sensitive: true, - Computed: true, - Description: "SSH RSA key", }, - "sshkey": { - Type: schema.TypeString, - Sensitive: true, - Computed: true, - Deprecated: "This field is deprecated, use ssh_key instead", + Attr_SSHKey: { + Computed: true, + Description: "SSH RSA key.", + Sensitive: true, + Type: schema.TypeString, }, }, } } func dataSourceIBMPIKeyRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - - // session sess, err := meta.(conns.ClientSession).IBMPISession() if err != nil { return diag.FromErr(err) } - // arguments - cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) - // get key sshkeyC := instance.NewIBMPIKeyClient(ctx, sess, cloudInstanceID) sshkeydata, err := sshkeyC.Get(d.Get(helpers.PIKeyName).(string)) if err != nil { return diag.FromErr(err) } - // set attributes d.SetId(*sshkeydata.Name) - d.Set(Attr_KeyCreationDate, sshkeydata.CreationDate.String()) - d.Set(Attr_Key, sshkeydata.SSHKey) - d.Set("sshkey", sshkeydata.SSHKey) // TODO: deprecated, to remove + d.Set(Attr_CreationDate, sshkeydata.CreationDate.String()) + d.Set(Attr_SSHKey, sshkeydata.SSHKey) return nil } diff --git a/ibm/service/power/data_source_ibm_pi_key_test.go b/ibm/service/power/data_source_ibm_pi_key_test.go index 184b74a0ec..a4fb373339 100644 --- a/ibm/service/power/data_source_ibm_pi_key_test.go +++ b/ibm/service/power/data_source_ibm_pi_key_test.go @@ -13,7 +13,6 @@ import ( ) func TestAccIBMPIKeyDataSource_basic(t *testing.T) { - resource.Test(t, resource.TestCase{ PreCheck: func() { acc.TestAccPreCheck(t) }, Providers: acc.TestAccProviders, @@ -30,9 +29,8 @@ func TestAccIBMPIKeyDataSource_basic(t *testing.T) { func testAccCheckIBMPIKeyDataSourceConfig() string { return fmt.Sprintf(` -data "ibm_pi_key" "testacc_ds_key" { - pi_key_name = "%s" - pi_cloud_instance_id = "%s" -}`, acc.Pi_key_name, acc.Pi_cloud_instance_id) - + data "ibm_pi_key" "testacc_ds_key" { + pi_key_name = "%s" + pi_cloud_instance_id = "%s" + }`, acc.Pi_key_name, acc.Pi_cloud_instance_id) } diff --git a/ibm/service/power/data_source_ibm_pi_keys.go b/ibm/service/power/data_source_ibm_pi_keys.go index 0f78a9ab4e..91bf669e1f 100644 --- a/ibm/service/power/data_source_ibm_pi_keys.go +++ b/ibm/service/power/data_source_ibm_pi_keys.go @@ -13,7 +13,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" st "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/IBM-Cloud/power-go-client/helpers" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" ) @@ -21,56 +20,51 @@ func DataSourceIBMPIKeys() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMPIKeysRead, Schema: map[string]*schema.Schema{ - // Arguments Arg_CloudInstanceID: { - Type: schema.TypeString, + Description: "The GUID of the service instance associated with an account.", Required: true, - Description: "PI cloud instance ID", + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, // Attributes Attr_Keys: { - Type: schema.TypeList, Computed: true, - Description: "SSH Keys", + Description: "List of all the SSH keys.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - Attr_KeyName: { - Type: schema.TypeString, + Attr_CreationDate: { Computed: true, - Description: "User defined name for the SSH key", - }, - Attr_Key: { + Description: "Date of SSH key creation.", Type: schema.TypeString, - Computed: true, - Description: "SSH RSA key", }, - Attr_KeyCreationDate: { + Attr_Name: { + Computed: true, + Description: "User defined name for the SSH key.", Type: schema.TypeString, + }, + Attr_SSHKey: { Computed: true, - Description: "Date of SSH key creation", + Description: "SSH RSA key.", + Type: schema.TypeString, }, }, }, + Type: schema.TypeList, }, }, } } func dataSourceIBMPIKeysRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - - // session sess, err := meta.(conns.ClientSession).IBMPISession() if err != nil { return diag.FromErr(err) } - // arguments - cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) - // get keys client := st.NewIBMPIKeyClient(ctx, sess, cloudInstanceID) sshKeys, err := client.GetAll() if err != nil { @@ -78,13 +72,12 @@ func dataSourceIBMPIKeysRead(ctx context.Context, d *schema.ResourceData, meta i return diag.FromErr(err) } - // set attributes result := make([]map[string]interface{}, 0, len(sshKeys.SSHKeys)) for _, sshKey := range sshKeys.SSHKeys { key := map[string]interface{}{ - Attr_KeyName: sshKey.Name, - Attr_Key: sshKey.SSHKey, - Attr_KeyCreationDate: sshKey.CreationDate.String(), + Attr_CreationDate: sshKey.CreationDate.String(), + Attr_Name: sshKey.Name, + Attr_SSHKey: sshKey.SSHKey, } result = append(result, key) } diff --git a/ibm/service/power/data_source_ibm_pi_keys_test.go b/ibm/service/power/data_source_ibm_pi_keys_test.go index f45dfc7fce..66bb6c4596 100644 --- a/ibm/service/power/data_source_ibm_pi_keys_test.go +++ b/ibm/service/power/data_source_ibm_pi_keys_test.go @@ -31,6 +31,5 @@ func testAccCheckIBMPIKeysDataSourceConfig() string { return fmt.Sprintf(` data "ibm_pi_keys" "test" { pi_cloud_instance_id = "%s" - } - `, acc.Pi_cloud_instance_id) + }`, 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 3a04453ca7..2835514f90 100644 --- a/ibm/service/power/data_source_ibm_pi_network.go +++ b/ibm/service/power/data_source_ibm_pi_network.go @@ -4,86 +4,97 @@ package power import ( - //"fmt" - "context" - "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/helpers" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "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" ) func DataSourceIBMPINetwork() *schema.Resource { - return &schema.Resource{ ReadContext: dataSourceIBMPINetworkRead, Schema: map[string]*schema.Schema{ - helpers.PINetworkName: { - Type: schema.TypeString, + // Arguments + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", Required: true, - Description: "Network Name to be used for pvminstances", + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, - helpers.PICloudInstanceId: { - Type: schema.TypeString, + Arg_NetworkName: { + Description: "The unique identifier or name of a network.", Required: true, + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, - // Computed Attributes - "cidr": { - Type: schema.TypeString, - Computed: true, + // Attributes + Attr_AccessConfig: { + Computed: true, + Description: "The network communication configuration option of the network (for satellite locations only).", + Type: schema.TypeString, }, - "type": { - Type: schema.TypeString, - Computed: true, + Attr_AvailableIPCount: { + Computed: true, + Description: "The total number of IP addresses that you have in your network.", + Type: schema.TypeFloat, }, - "vlan_id": { - Type: schema.TypeInt, - Computed: true, + Attr_CIDR: { + Computed: true, + Description: "The CIDR of the network.", + Type: schema.TypeString, }, - "gateway": { - Type: schema.TypeString, - Computed: true, + Attr_DNS: { + Computed: true, + Description: "The DNS Servers for the network.", + Elem: &schema.Schema{Type: schema.TypeString}, + Type: schema.TypeSet, }, - "available_ip_count": { - Type: schema.TypeFloat, - Computed: true, + Attr_Gateway: { + Computed: true, + Description: "The network gateway that is attached to your network.", + Type: schema.TypeString, }, - "used_ip_count": { - Type: schema.TypeFloat, - Computed: true, + Attr_Jumbo: { + Computed: true, + Deprecated: "This field is deprecated, use mtu instead.", + Description: "MTU Jumbo option of the network (for multi-zone locations only).", + Type: schema.TypeBool, }, - "used_ip_percent": { - Type: schema.TypeFloat, - Computed: true, + Attr_MTU: { + Computed: true, + Description: "Maximum Transmission Unit option of the network.", + Type: schema.TypeInt, }, - "name": { - Type: schema.TypeString, - Computed: true, - Deprecated: "This value is deprecated in favor of" + helpers.PINetworkName, + Attr_Name: { + Computed: true, + Deprecated: "This field is deprecated, use pi_network_name instead.", + Description: "The unique identifier or name of a network.", + Type: schema.TypeString, }, - "dns": { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, + Attr_Type: { + Computed: true, + Description: "The type of network.", + Type: schema.TypeString, }, - "jumbo": { - Type: schema.TypeBool, - Computed: true, + Attr_UsedIPCount: { + Computed: true, + Description: "The number of used IP addresses.", + Type: schema.TypeFloat, }, - "mtu": { - Type: schema.TypeInt, - Computed: true, + Attr_UsedIPPercent: { + Computed: true, + Description: "The percentage of IP addresses used.", + Type: schema.TypeFloat, }, - "access_config": { - Type: schema.TypeString, - Computed: true, + Attr_VLanID: { + Computed: true, + Description: "The VLAN ID that the network is connected to.", + Type: schema.TypeInt, }, }, } @@ -95,7 +106,7 @@ func dataSourceIBMPINetworkRead(ctx context.Context, d *schema.ResourceData, met return diag.FromErr(err) } - cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) networkC := instance.NewIBMPINetworkClient(ctx, sess, cloudInstanceID) networkdata, err := networkC.Get(d.Get(helpers.PINetworkName).(string)) @@ -104,35 +115,34 @@ func dataSourceIBMPINetworkRead(ctx context.Context, d *schema.ResourceData, met } d.SetId(*networkdata.NetworkID) + d.Set(Attr_AccessConfig, networkdata.AccessConfig) + if networkdata.IPAddressMetrics.Available != nil { + d.Set(Attr_AvailableIPCount, networkdata.IPAddressMetrics.Available) + } if networkdata.Cidr != nil { - d.Set("cidr", networkdata.Cidr) + d.Set(Attr_CIDR, networkdata.Cidr) } - if networkdata.Type != nil { - d.Set("type", networkdata.Type) + if len(networkdata.DNSServers) > 0 { + d.Set(Attr_DNS, networkdata.DNSServers) } - d.Set("gateway", networkdata.Gateway) - if networkdata.VlanID != nil { - d.Set("vlan_id", networkdata.VlanID) + d.Set(Attr_Gateway, networkdata.Gateway) + d.Set(Attr_Jumbo, networkdata.Jumbo) + d.Set(Attr_MTU, networkdata.Mtu) + if networkdata.Name != nil { + d.Set(Attr_Name, networkdata.Name) } - if networkdata.IPAddressMetrics.Available != nil { - d.Set("available_ip_count", networkdata.IPAddressMetrics.Available) + if networkdata.Type != nil { + d.Set(Attr_Type, networkdata.Type) } if networkdata.IPAddressMetrics.Used != nil { - d.Set("used_ip_count", networkdata.IPAddressMetrics.Used) + d.Set(Attr_UsedIPCount, networkdata.IPAddressMetrics.Used) } if networkdata.IPAddressMetrics.Utilization != nil { - d.Set("used_ip_percent", networkdata.IPAddressMetrics.Utilization) - } - if networkdata.Name != nil { - d.Set("name", networkdata.Name) + d.Set(Attr_UsedIPPercent, networkdata.IPAddressMetrics.Utilization) } - if len(networkdata.DNSServers) > 0 { - d.Set("dns", networkdata.DNSServers) + if networkdata.VlanID != nil { + d.Set(Attr_VLanID, networkdata.VlanID) } - d.Set("jumbo", networkdata.Jumbo) - d.Set("mtu", networkdata.Mtu) - d.Set("access_config", networkdata.AccessConfig) return nil - } diff --git a/ibm/service/power/data_source_ibm_pi_network_port.go b/ibm/service/power/data_source_ibm_pi_network_port.go index e98a9c3b1b..5fef77e7af 100644 --- a/ibm/service/power/data_source_ibm_pi_network_port.go +++ b/ibm/service/power/data_source_ibm_pi_network_port.go @@ -7,69 +7,74 @@ import ( "context" "log" + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" "github.com/IBM-Cloud/power-go-client/power/models" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/go-uuid" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - //"fmt" - "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/IBM-Cloud/power-go-client/helpers" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) func DataSourceIBMPINetworkPort() *schema.Resource { - return &schema.Resource{ ReadContext: dataSourceIBMPINetworkPortsRead, Schema: map[string]*schema.Schema{ - helpers.PINetworkName: { - Type: schema.TypeString, + // Arguments + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", Required: true, - Description: "Network Name to be used for pvminstances", + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, - helpers.PICloudInstanceId: { - Type: schema.TypeString, + Arg_NetworkName: { + Description: "The unique identifier or name of a network.", Required: true, + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, - // Computed Attributes - "network_ports": { + // Attributes + Attr_NetworkPorts: { Type: schema.TypeList, Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "ipaddress": { - Type: schema.TypeString, - Optional: true, - Computed: true, + Attr_Description: { + Computed: true, + Description: "The description for the network port.", + Type: schema.TypeString, }, - "macaddress": { - Type: schema.TypeString, - Computed: true, + Attr_Href: { + Computed: true, + Description: "Network port href.", + Type: schema.TypeString, }, - "portid": { - Type: schema.TypeString, - Computed: true, + Attr_IPAddress: { + Computed: true, + Description: "The IP address of the port.", + Type: schema.TypeString, }, - "status": { - Type: schema.TypeString, - Computed: true, + Attr_MacAddress: { + Computed: true, + Description: "The MAC address of the port.", + Type: schema.TypeString, }, - "href": { - Type: schema.TypeString, - Computed: true, + Attr_PortID: { + Computed: true, + Description: "The ID of the port.", + Type: schema.TypeString, }, - "description": { - Type: schema.TypeString, - Required: true, + Attr_PublicIP: { + Computed: true, + Description: "The public IP associated with the port.", + Type: schema.TypeString, }, - "public_ip": { - Type: schema.TypeString, - Computed: true, + Attr_Status: { + Computed: true, + Description: "The status of the port.", + Type: schema.TypeString, }, }, }, @@ -84,7 +89,8 @@ func dataSourceIBMPINetworkPortsRead(ctx context.Context, d *schema.ResourceData return diag.FromErr(err) } - cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) + networkportC := instance.NewIBMPINetworkClient(ctx, sess, cloudInstanceID) networkportdata, err := networkportC.GetAllPorts(d.Get(helpers.PINetworkName).(string)) if err != nil { @@ -93,10 +99,9 @@ func dataSourceIBMPINetworkPortsRead(ctx context.Context, d *schema.ResourceData var clientgenU, _ = uuid.GenerateUUID() d.SetId(clientgenU) - d.Set("network_ports", flattenNetworkPorts(networkportdata.Ports)) + d.Set(Attr_NetworkPorts, flattenNetworkPorts(networkportdata.Ports)) return nil - } func flattenNetworkPorts(networkPorts []*models.NetworkPort) interface{} { @@ -104,14 +109,14 @@ func flattenNetworkPorts(networkPorts []*models.NetworkPort) interface{} { log.Printf("the number of ports is %d", len(networkPorts)) for _, i := range networkPorts { l := map[string]interface{}{ - "portid": *i.PortID, - "status": *i.Status, - "href": i.Href, - "ipaddress": *i.IPAddress, - "macaddress": *i.MacAddress, - "public_ip": i.ExternalIP, + Attr_Description: i.Description, + Attr_Href: i.Href, + Attr_IPAddress: *i.IPAddress, + Attr_MacAddress: *i.MacAddress, + Attr_PortID: *i.PortID, + Attr_PublicIP: i.ExternalIP, + Attr_Status: *i.Status, } - result = append(result, l) } return result diff --git a/ibm/service/power/data_source_ibm_pi_network_port_test.go b/ibm/service/power/data_source_ibm_pi_network_port_test.go new file mode 100644 index 0000000000..24a386af2d --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_network_port_test.go @@ -0,0 +1,36 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMPINetworkPortDataSource_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPINetworkPortDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_pi_network_port.testacc_ds_network_port", "id"), + ), + }, + }, + }) +} + +func testAccCheckIBMPINetworkPortDataSourceConfig() string { + return fmt.Sprintf(` + data "ibm_pi_network_port" "testacc_ds_network_port" { + pi_network_name = "%s" + pi_cloud_instance_id = "%s" + }`, acc.Pi_network_name, acc.Pi_cloud_instance_id) +} diff --git a/ibm/service/power/data_source_ibm_pi_network_test.go b/ibm/service/power/data_source_ibm_pi_network_test.go index 873681869a..c4c09fa58c 100644 --- a/ibm/service/power/data_source_ibm_pi_network_test.go +++ b/ibm/service/power/data_source_ibm_pi_network_test.go @@ -29,9 +29,8 @@ func TestAccIBMPINetworkDataSource_basic(t *testing.T) { func testAccCheckIBMPINetworkDataSourceConfig() string { return fmt.Sprintf(` -data "ibm_pi_network" "testacc_ds_network" { - pi_network_name = "%s" - pi_cloud_instance_id = "%s" -}`, acc.Pi_network_name, acc.Pi_cloud_instance_id) - + data "ibm_pi_network" "testacc_ds_network" { + pi_network_name = "%s" + pi_cloud_instance_id = "%s" + }`, acc.Pi_network_name, acc.Pi_cloud_instance_id) } diff --git a/ibm/service/power/data_source_ibm_pi_placement_group.go b/ibm/service/power/data_source_ibm_pi_placement_group.go index 9792aa331d..6b90a44f98 100644 --- a/ibm/service/power/data_source_ibm_pi_placement_group.go +++ b/ibm/service/power/data_source_ibm_pi_placement_group.go @@ -7,55 +7,56 @@ import ( "context" "log" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - st "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/power-go-client/clients/instance" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "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" ) func DataSourceIBMPIPlacementGroup() *schema.Resource { - return &schema.Resource{ ReadContext: dataSourceIBMPIPlacementGroupRead, Schema: map[string]*schema.Schema{ - helpers.PIPlacementGroupName: { - Type: schema.TypeString, - Required: true, - }, - - "policy": { - Type: schema.TypeString, - Computed: true, - }, - - helpers.PICloudInstanceId: { + // Arguments + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", + Required: true, Type: schema.TypeString, + ValidateFunc: validation.NoZeroValues, + }, + Arg_PlacementGroupName: { + Description: "The name of the placement group.", Required: true, + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, - PIPlacementGroupMembers: { - Type: schema.TypeList, - Elem: &schema.Schema{Type: schema.TypeString}, - Computed: true, + // Attribute + Attr_Members: { + Computed: true, + Description: "List of server instances IDs that are members of the placement group.", + Elem: &schema.Schema{Type: schema.TypeString}, + Type: schema.TypeList, + }, + Attr_Policy: { + Computed: true, + Description: "The value of the group's affinity policy. Valid values are affinity and anti-affinity.", + Type: schema.TypeString, }, }, } } func dataSourceIBMPIPlacementGroupRead(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(helpers.PICloudInstanceId).(string) - placementGroupName := d.Get(helpers.PIPlacementGroupName).(string) - client := st.NewIBMPIPlacementGroupClient(ctx, sess, cloudInstanceID) + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) + placementGroupName := d.Get(Arg_PlacementGroupName).(string) + client := instance.NewIBMPIPlacementGroupClient(ctx, sess, cloudInstanceID) response, err := client.Get(placementGroupName) if err != nil { @@ -64,8 +65,8 @@ func dataSourceIBMPIPlacementGroupRead(ctx context.Context, d *schema.ResourceDa } d.SetId(*response.ID) - d.Set("policy", response.Policy) - d.Set(PIPlacementGroupMembers, response.Members) + d.Set(Attr_Members, response.Members) + d.Set(Attr_Policy, response.Policy) return nil } diff --git a/ibm/service/power/data_source_ibm_pi_placement_group_test.go b/ibm/service/power/data_source_ibm_pi_placement_group_test.go index 0738266a98..05478cc72a 100644 --- a/ibm/service/power/data_source_ibm_pi_placement_group_test.go +++ b/ibm/service/power/data_source_ibm_pi_placement_group_test.go @@ -28,9 +28,8 @@ func TestAccIBMPIPlacementGroupDataSource_basic(t *testing.T) { func testAccCheckIBMPIPlacementGroupDataSourceConfig() string { return fmt.Sprintf(` -data "ibm_pi_placement_group" "testacc_ds_placement_group" { - pi_placement_group_name = "%s" - pi_cloud_instance_id = "%s" -}`, acc.Pi_placement_group_name, acc.Pi_cloud_instance_id) - + data "ibm_pi_placement_group" "testacc_ds_placement_group" { + pi_placement_group_name = "%s" + pi_cloud_instance_id = "%s" + }`, acc.Pi_placement_group_name, acc.Pi_cloud_instance_id) } diff --git a/ibm/service/power/data_source_ibm_pi_placement_groups.go b/ibm/service/power/data_source_ibm_pi_placement_groups.go index 345f2bf05c..6b25ed99ba 100644 --- a/ibm/service/power/data_source_ibm_pi_placement_groups.go +++ b/ibm/service/power/data_source_ibm_pi_placement_groups.go @@ -7,52 +7,52 @@ import ( "context" "log" + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "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" - - st "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/IBM-Cloud/power-go-client/helpers" - "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" -) - -const ( - PIPlacementGroups = "placement_groups" ) func DataSourceIBMPIPlacementGroups() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMPIPlacementGroupsRead, Schema: map[string]*schema.Schema{ - helpers.PICloudInstanceId: { - Type: schema.TypeString, + // Arguments + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", Required: true, - Description: "PI cloud instance ID", + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, - // Computed Attributes - PIPlacementGroups: { + + // Attributes + Attr_PlacementGroups: { Type: schema.TypeList, Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, + Attr_ID: { + Computed: true, + Description: "The ID of the placement group.", + Type: schema.TypeString, }, - "name": { - Type: schema.TypeString, - Computed: true, + Attr_Members: { + Computed: true, + Description: "List of server instances IDs that are members of the placement group.", + Elem: &schema.Schema{Type: schema.TypeString}, + Type: schema.TypeList, }, - PIPlacementGroupMembers: { - Type: schema.TypeList, - Elem: &schema.Schema{Type: schema.TypeString}, - Computed: true, + Attr_Name: { + Computed: true, + Description: "User defined name for the placement group.", + Type: schema.TypeString, }, - "policy": { - Type: schema.TypeString, - Computed: true, + Attr_Policy: { + Computed: true, + Description: "The value of the group's affinity policy. Valid values are affinity and anti-affinity.", + Type: schema.TypeString, }, }, }, @@ -67,9 +67,9 @@ func dataSourceIBMPIPlacementGroupsRead(ctx context.Context, d *schema.ResourceD return diag.FromErr(err) } - cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) - client := st.NewIBMPIPlacementGroupClient(ctx, sess, cloudInstanceID) + client := instance.NewIBMPIPlacementGroupClient(ctx, sess, cloudInstanceID) groups, err := client.GetAll() if err != nil { log.Printf("[ERROR] get all placement groups failed %v", err) @@ -79,17 +79,17 @@ func dataSourceIBMPIPlacementGroupsRead(ctx context.Context, d *schema.ResourceD result := make([]map[string]interface{}, 0, len(groups.PlacementGroups)) for _, placementGroup := range groups.PlacementGroups { key := map[string]interface{}{ - "id": placementGroup.ID, - "name": placementGroup.Name, - PIPlacementGroupMembers: placementGroup.Members, - "policy": placementGroup.Policy, + Attr_ID: placementGroup.ID, + Attr_Members: placementGroup.Members, + Attr_Name: placementGroup.Name, + Attr_Policy: placementGroup.Policy, } result = append(result, key) } var genID, _ = uuid.GenerateUUID() d.SetId(genID) - d.Set(PIPlacementGroups, result) + d.Set(Attr_PlacementGroups, result) return nil } diff --git a/ibm/service/power/data_source_ibm_pi_placement_groups_test.go b/ibm/service/power/data_source_ibm_pi_placement_groups_test.go index 2f0e8131c8..d520f3f1e0 100644 --- a/ibm/service/power/data_source_ibm_pi_placement_groups_test.go +++ b/ibm/service/power/data_source_ibm_pi_placement_groups_test.go @@ -30,6 +30,5 @@ func testAccCheckIBMPIPlacementGrousDataSourceConfig() string { return fmt.Sprintf(` data "ibm_pi_placement_groups" "test" { pi_cloud_instance_id = "%s" - } - `, acc.Pi_cloud_instance_id) + }`, acc.Pi_cloud_instance_id) } diff --git a/ibm/service/power/data_source_ibm_pi_public_network.go b/ibm/service/power/data_source_ibm_pi_public_network.go index ca5cc380e2..ef8195c964 100644 --- a/ibm/service/power/data_source_ibm_pi_public_network.go +++ b/ibm/service/power/data_source_ibm_pi_public_network.go @@ -4,41 +4,42 @@ package power import ( - //"fmt" "context" + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "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/helpers" - "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" ) func DataSourceIBMPIPublicNetwork() *schema.Resource { - return &schema.Resource{ ReadContext: dataSourceIBMPIPublicNetworkRead, Schema: map[string]*schema.Schema{ - helpers.PICloudInstanceId: { - Type: schema.TypeString, + // Arguments + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", Required: true, + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, - // Computed Attributes - "name": { - Type: schema.TypeString, - Computed: true, + // Attributes + Attr_Name: { + Computed: true, + Description: "The name of the network.", + Type: schema.TypeString, }, - "type": { - Type: schema.TypeString, - Computed: true, + Attr_Type: { + Computed: true, + Description: "The type of VLAN that the network is connected to.", + Type: schema.TypeString, }, - "vlan_id": { - Type: schema.TypeInt, - Computed: true, + Attr_VLanID: { + Computed: true, + Description: "The ID of the VLAN that the network is connected to.", + Type: schema.TypeInt, }, }, } @@ -50,7 +51,7 @@ func dataSourceIBMPIPublicNetworkRead(ctx context.Context, d *schema.ResourceDat return diag.FromErr(err) } - cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) networkC := instance.NewIBMPINetworkClient(ctx, sess, cloudInstanceID) networkdata, err := networkC.GetAllPublic() @@ -62,14 +63,14 @@ func dataSourceIBMPIPublicNetworkRead(ctx context.Context, d *schema.ResourceDat } d.SetId(*networkdata.Networks[0].NetworkID) - if networkdata.Networks[0].Type != nil { - d.Set("type", networkdata.Networks[0].Type) - } if networkdata.Networks[0].Name != nil { - d.Set("name", networkdata.Networks[0].Name) + d.Set(Attr_Name, networkdata.Networks[0].Name) + } + if networkdata.Networks[0].Type != nil { + d.Set(Attr_Type, networkdata.Networks[0].Type) } if networkdata.Networks[0].VlanID != nil { - d.Set("vlan_id", networkdata.Networks[0].VlanID) + d.Set(Attr_VLanID, networkdata.Networks[0].VlanID) } return nil diff --git a/ibm/service/power/data_source_ibm_pi_public_network_test.go b/ibm/service/power/data_source_ibm_pi_public_network_test.go index f8c3eb1c5b..3ac39c13a6 100644 --- a/ibm/service/power/data_source_ibm_pi_public_network_test.go +++ b/ibm/service/power/data_source_ibm_pi_public_network_test.go @@ -29,8 +29,7 @@ func TestAccIBMPIPublicNetworkDataSource_basic(t *testing.T) { func testAccCheckIBMPIPublicNetworkDataSourceConfig() string { return fmt.Sprintf(` -data "ibm_pi_public_network" "testacc_ds_public_network" { - pi_cloud_instance_id = "%s" -}`, acc.Pi_cloud_instance_id) - + data "ibm_pi_public_network" "testacc_ds_public_network" { + pi_cloud_instance_id = "%s" + }`, acc.Pi_cloud_instance_id) } diff --git a/ibm/service/power/data_source_ibm_pi_pvm_snapshot.go b/ibm/service/power/data_source_ibm_pi_pvm_snapshot.go new file mode 100644 index 0000000000..a3e6021a6c --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_pvm_snapshot.go @@ -0,0 +1,135 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "log" + + "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" + "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" +) + +func DataSourceIBMPIPVMSnapshot() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMPISnapshotRead, + 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, + }, + Arg_InstanceName: { + Description: "The unique identifier or name of the instance.", + Required: true, + Type: schema.TypeString, + ValidateFunc: validation.NoZeroValues, + }, + + // Attributes + Attr_PVMSnapshots: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_Action: { + Computed: true, + Description: "Action performed on the instance snapshot.", + Type: schema.TypeString, + }, + Attr_CreationDate: { + Computed: true, + Description: "Date of snapshot creation.", + Type: schema.TypeString, + }, + Attr_Description: { + Computed: true, + Description: "The description of the snapshot.", + Type: schema.TypeString, + }, + Attr_ID: { + Computed: true, + Description: "The unique identifier of the Power Virtual Machine instance snapshot.", + Type: schema.TypeString, + }, + Attr_LastUpdatedDate: { + Computed: true, + Description: "Date of last update.", + Type: schema.TypeString, + }, + Attr_Name: { + Computed: true, + Description: "The name of the Power Virtual Machine instance snapshot.", + Type: schema.TypeString, + }, + Attr_PercentComplete: { + Computed: true, + Description: "The snapshot completion percentage.", + Type: schema.TypeInt, + }, + Attr_Status: { + Computed: true, + Description: "The status of the Power Virtual Machine instance snapshot.", + Type: schema.TypeString, + }, + Attr_VolumeSnapshots: { + Computed: true, + Description: "A map of volume snapshots included in the Power Virtual Machine instance snapshot.", + Type: schema.TypeMap, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMPISnapshotRead(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) + powerinstancename := d.Get(Arg_InstanceName).(string) + snapshot := instance.NewIBMPIInstanceClient(ctx, sess, cloudInstanceID) + snapshotData, err := snapshot.GetSnapShotVM(powerinstancename) + + if err != nil { + return diag.FromErr(err) + } + + var clientgenU, _ = uuid.GenerateUUID() + d.SetId(clientgenU) + d.Set(Attr_PVMSnapshots, flattenPVMSnapshotInstances(snapshotData.Snapshots)) + + return nil +} + +func flattenPVMSnapshotInstances(list []*models.Snapshot) []map[string]interface{} { + log.Printf("Calling the flattenPVMSnapshotInstances call with list %d", len(list)) + result := make([]map[string]interface{}, 0, len(list)) + for _, i := range list { + l := map[string]interface{}{ + Attr_Action: i.Action, + Attr_CreationDate: i.CreationDate.String(), + Attr_Description: i.Description, + Attr_ID: *i.SnapshotID, + Attr_LastUpdatedDate: i.LastUpdateDate.String(), + Attr_Name: *i.Name, + Attr_PercentComplete: i.PercentComplete, + Attr_Status: i.Status, + Attr_VolumeSnapshots: i.VolumeSnapshots, + } + result = append(result, l) + } + return result +} diff --git a/ibm/service/power/data_source_ibm_pi_snapshot_test.go b/ibm/service/power/data_source_ibm_pi_pvm_snapshot_test.go similarity index 82% rename from ibm/service/power/data_source_ibm_pi_snapshot_test.go rename to ibm/service/power/data_source_ibm_pi_pvm_snapshot_test.go index 3636fbf048..e5c502c1cb 100644 --- a/ibm/service/power/data_source_ibm_pi_snapshot_test.go +++ b/ibm/service/power/data_source_ibm_pi_pvm_snapshot_test.go @@ -29,10 +29,8 @@ func TestAccIBMPISnapshotDataSource_basic(t *testing.T) { func testAccCheckIBMPISnapshotDataSourceConfig() string { return fmt.Sprintf(` - -data "ibm_pi_pvm_snapshots" "testacc_pi_snapshots" { - pi_instance_name = "%s" - pi_cloud_instance_id = "%s" -}`, acc.Pi_instance_name, acc.Pi_cloud_instance_id) - + data "ibm_pi_pvm_snapshots" "testacc_pi_snapshots" { + pi_instance_name = "%s" + pi_cloud_instance_id = "%s" + }`, acc.Pi_instance_name, acc.Pi_cloud_instance_id) } diff --git a/ibm/service/power/data_source_ibm_pi_sap_profile.go b/ibm/service/power/data_source_ibm_pi_sap_profile.go index 43510987d1..1f53d1ad72 100644 --- a/ibm/service/power/data_source_ibm_pi_sap_profile.go +++ b/ibm/service/power/data_source_ibm_pi_sap_profile.go @@ -7,49 +7,51 @@ import ( "context" "log" + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "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/helpers" - "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" ) func DataSourceIBMPISAPProfile() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMPISAPProfileRead, Schema: map[string]*schema.Schema{ - helpers.PICloudInstanceId: { - Type: schema.TypeString, + // Arguments + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", Required: true, + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, - PISAPInstanceProfileID: { - Type: schema.TypeString, - Required: true, - Description: "SAP Profile ID", + Arg_SAPProfileID: { + Description: "SAP Profile ID", + Required: true, + Type: schema.TypeString, + ValidateFunc: validation.NoZeroValues, }, - // Computed Attributes - PISAPProfileCertified: { - Type: schema.TypeBool, + + // Attributes + Attr_Certified: { Computed: true, - Description: "Has certification been performed on profile", + Description: "Has certification been performed on profile.", + Type: schema.TypeBool, }, - PISAPProfileCores: { - Type: schema.TypeInt, + Attr_Cores: { Computed: true, - Description: "Amount of cores", - }, - PISAPProfileMemory: { + Description: "Amount of cores.", Type: schema.TypeInt, + }, + Attr_Memory: { Computed: true, - Description: "Amount of memory (in GB)", + Description: "Amount of memory (in GB).", + Type: schema.TypeInt, }, - PISAPProfileType: { - Type: schema.TypeString, + Attr_Type: { Computed: true, - Description: "Type of profile", + Description: "Type of profile.", + Type: schema.TypeString, }, }, } @@ -61,8 +63,8 @@ func dataSourceIBMPISAPProfileRead(ctx context.Context, d *schema.ResourceData, return diag.FromErr(err) } - cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) - profileID := d.Get(PISAPInstanceProfileID).(string) + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) + profileID := d.Get(Arg_SAPProfileID).(string) client := instance.NewIBMPISAPInstanceClient(ctx, sess, cloudInstanceID) sapProfile, err := client.GetSAPProfile(profileID) @@ -72,10 +74,10 @@ func dataSourceIBMPISAPProfileRead(ctx context.Context, d *schema.ResourceData, } d.SetId(*sapProfile.ProfileID) - d.Set(PISAPProfileCertified, *sapProfile.Certified) - d.Set(PISAPProfileCores, *sapProfile.Cores) - d.Set(PISAPProfileMemory, *sapProfile.Memory) - d.Set(PISAPProfileType, *sapProfile.Type) + d.Set(Attr_Certified, *sapProfile.Certified) + d.Set(Attr_Cores, *sapProfile.Cores) + d.Set(Attr_Memory, *sapProfile.Memory) + d.Set(Attr_Type, *sapProfile.Type) return nil } diff --git a/ibm/service/power/data_source_ibm_pi_sap_profiles.go b/ibm/service/power/data_source_ibm_pi_sap_profiles.go index 0b314791ca..a3c3c5f5a6 100644 --- a/ibm/service/power/data_source_ibm_pi_sap_profiles.go +++ b/ibm/service/power/data_source_ibm_pi_sap_profiles.go @@ -7,58 +7,60 @@ import ( "context" "log" + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "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/helpers" - "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" ) func DataSourceIBMPISAPProfiles() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMPISAPProfilesRead, Schema: map[string]*schema.Schema{ - helpers.PICloudInstanceId: { - Type: schema.TypeString, + // Arguments + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", Required: true, + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, - // Computed Attributes - PISAPProfiles: { - Type: schema.TypeList, - Computed: true, + + // Attributes + Attr_Profiles: { + Computed: true, + Description: "List of all the SAP Profiles.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - PISAPProfileCertified: { - Type: schema.TypeBool, + Attr_Certified: { Computed: true, - Description: "Has certification been performed on profile", + Description: "Has certification been performed on profile.", + Type: schema.TypeBool, }, - PISAPProfileCores: { - Type: schema.TypeInt, + Attr_Cores: { Computed: true, - Description: "Amount of cores", - }, - PISAPProfileMemory: { + Description: "Amount of cores.", Type: schema.TypeInt, - Computed: true, - Description: "Amount of memory (in GB)", }, - PISAPProfileID: { - Type: schema.TypeString, + Attr_Memory: { Computed: true, - Description: "SAP Profile ID", + Description: "Amount of memory (in GB).", + Type: schema.TypeInt, }, - PISAPProfileType: { + Attr_ProfileID: { + Computed: true, + Description: "SAP Profile ID.", Type: schema.TypeString, + }, + Attr_Type: { Computed: true, - Description: "Type of profile", + Description: "Type of profile.", + Type: schema.TypeString, }, }, }, + Type: schema.TypeList, }, }, } @@ -70,7 +72,7 @@ func dataSourceIBMPISAPProfilesRead(ctx context.Context, d *schema.ResourceData, return diag.FromErr(err) } - cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) client := instance.NewIBMPISAPInstanceClient(ctx, sess, cloudInstanceID) sapProfiles, err := client.GetAllSAPProfiles(cloudInstanceID) @@ -82,18 +84,18 @@ func dataSourceIBMPISAPProfilesRead(ctx context.Context, d *schema.ResourceData, result := make([]map[string]interface{}, 0, len(sapProfiles.Profiles)) for _, sapProfile := range sapProfiles.Profiles { profile := map[string]interface{}{ - PISAPProfileCertified: *sapProfile.Certified, - PISAPProfileCores: *sapProfile.Cores, - PISAPProfileMemory: *sapProfile.Memory, - PISAPProfileID: *sapProfile.ProfileID, - PISAPProfileType: *sapProfile.Type, + Attr_Certified: *sapProfile.Certified, + Attr_Cores: *sapProfile.Cores, + Attr_Memory: *sapProfile.Memory, + Attr_ProfileID: *sapProfile.ProfileID, + Attr_Type: *sapProfile.Type, } result = append(result, profile) } var genID, _ = uuid.GenerateUUID() d.SetId(genID) - d.Set(PISAPProfiles, result) + d.Set(Attr_Profiles, result) return nil } diff --git a/ibm/service/power/data_source_ibm_pi_shared_processor_pool.go b/ibm/service/power/data_source_ibm_pi_shared_processor_pool.go index e3fcc1be34..b6c04c4f58 100644 --- a/ibm/service/power/data_source_ibm_pi_shared_processor_pool.go +++ b/ibm/service/power/data_source_ibm_pi_shared_processor_pool.go @@ -6,143 +6,137 @@ package power import ( "context" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - st "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/power-go-client/clients/instance" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "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" ) func DataSourceIBMPISharedProcessorPool() *schema.Resource { - return &schema.Resource{ ReadContext: dataSourceIBMPISharedProcessorPoolRead, Schema: map[string]*schema.Schema{ - Arg_SharedProcessorPoolID: { - Type: schema.TypeString, - Required: true, - }, - + // Arguments Arg_CloudInstanceID: { - Type: schema.TypeString, - Required: true, - Description: "PI cloud instance ID", + Description: "The GUID of the service instance associated with an account.", + Required: true, + Type: schema.TypeString, + ValidateFunc: validation.NoZeroValues, }, - - Attr_SharedProcessorPoolName: { - Type: schema.TypeString, - Computed: true, - Description: "Name of the shared processor pool", - }, - - Attr_SharedProcessorPoolHostID: { - Type: schema.TypeInt, - Computed: true, - Description: "The host ID where the shared processor pool resides", - }, - - Attr_SharedProcessorPoolReservedCores: { - Type: schema.TypeInt, - Computed: true, - Description: "The amount of reserved cores for the shared processor pool", + Arg_SharedProcessorPoolID: { + Description: "The ID of the shared processor pool.", + Required: true, + Type: schema.TypeString, + ValidateFunc: validation.NoZeroValues, }, - Attr_SharedProcessorPoolAvailableCores: { - Type: schema.TypeFloat, + // Attributes + Attr_AllocatedCores: { Computed: true, - Description: "Shared processor pool available cores", - }, - - Attr_SharedProcessorPoolAllocatedCores: { + Description: "The allocated cores in the shared processor pool.", Type: schema.TypeFloat, - Computed: true, - Description: "Shared processor pool allocated cores", }, - - Attr_SharedProcessorPoolStatus: { - Type: schema.TypeString, + Attr_AvailableCores: { Computed: true, - Description: "The status of the shared processor pool", + Description: "The available cores in the shared processor pool.", + Type: schema.TypeFloat, }, - - Attr_SharedProcessorPoolStatusDetail: { - Type: schema.TypeString, + Attr_HostID: { Computed: true, - Description: "The status details of the shared processor pool", + Description: "The host ID where the shared processor pool resides.", + Type: schema.TypeInt, }, - - Attr_SharedProcessorPoolInstances: { - Type: schema.TypeList, + Attr_Instances: { Computed: true, - Description: "List of server instances deployed in the shared processor pool", + Description: "List of server instances deployed in the shared processor pool.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - Attr_SharedProcessorPoolInstanceCpus: { - Type: schema.TypeInt, - Optional: true, + Attr_AvailabilityZone: { Computed: true, - Description: "The amount of cpus for the server instance", - }, - Attr_SharedProcessorPoolInstanceUncapped: { - Type: schema.TypeBool, + Description: "Availability zone for the server instances.", Optional: true, - Computed: true, - Description: "Identifies if uncapped or not", - }, - Attr_SharedProcessorPoolInstanceAvailabilityZone: { Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "Availability zone for the server instances", }, - Attr_SharedProcessorPoolInstanceId: { - Type: schema.TypeString, - Optional: true, + Attr_CPUs: { Computed: true, - Description: "The server instance ID", - }, - Attr_SharedProcessorPoolInstanceMemory: { - Type: schema.TypeInt, + Description: "The amount of cpus for the server instance.", Optional: true, - Computed: true, - Description: "The amount of memory for the server instance", + Type: schema.TypeInt, }, - Attr_SharedProcessorPoolInstanceName: { - Type: schema.TypeString, + Attr_ID: { + Computed: true, + Description: "The server instance ID.", Optional: true, + Type: schema.TypeString, + }, + Attr_Memory: { Computed: true, - Description: "The server instance name", + Description: "The amount of memory for the server instance.", + Optional: true, + Type: schema.TypeInt, }, - Attr_SharedProcessorPoolInstanceStatus: { - Type: schema.TypeString, + Attr_Name: { + Computed: true, + Description: "The server instance name.", Optional: true, + Type: schema.TypeString, + }, + Attr_Status: { Computed: true, - Description: "Status of the server", + Description: "Status of the instance.", + Optional: true, + Type: schema.TypeString, }, - Attr_SharedProcessorPoolInstanceVcpus: { - Type: schema.TypeFloat, + Attr_Uncapped: { + Computed: true, + Description: "Identifies if uncapped or not.", Optional: true, + Type: schema.TypeBool, + }, + Attr_VCPUs: { Computed: true, - Description: "The amout of vcpus for the server instance", + Description: "The amout of vcpus for the server instance.", + Optional: true, + Type: schema.TypeFloat, }, }, }, + Type: schema.TypeList, + }, + Attr_Name: { + Computed: true, + Description: "The name of the shared processor pool.", + Type: schema.TypeString, + }, + Attr_ReservedCores: { + Computed: true, + Description: "The amount of reserved cores for the shared processor pool.", + Type: schema.TypeInt, + }, + Attr_Status: { + Computed: true, + Description: "The status of the shared processor pool.", + Type: schema.TypeString, + }, + Attr_StatusDetail: { + Computed: true, + Description: "The status details of the shared processor pool.", + Type: schema.TypeString, }, }, } } func dataSourceIBMPISharedProcessorPoolRead(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(helpers.PICloudInstanceId).(string) + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) poolID := d.Get(Arg_SharedProcessorPoolID).(string) - client := st.NewIBMPISharedProcessorPoolClient(ctx, sess, cloudInstanceID) + client := instance.NewIBMPISharedProcessorPoolClient(ctx, sess, cloudInstanceID) response, err := client.Get(poolID) if err != nil || response == nil { @@ -150,33 +144,33 @@ func dataSourceIBMPISharedProcessorPoolRead(ctx context.Context, d *schema.Resou } d.SetId(*response.SharedProcessorPool.ID) - d.Set(Attr_SharedProcessorPoolName, response.SharedProcessorPool.Name) - d.Set(Attr_SharedProcessorPoolReservedCores, response.SharedProcessorPool.ReservedCores) - d.Set(Attr_SharedProcessorPoolAllocatedCores, response.SharedProcessorPool.AllocatedCores) - d.Set(Attr_SharedProcessorPoolAvailableCores, response.SharedProcessorPool.AvailableCores) - d.Set(Attr_SharedProcessorPoolHostID, response.SharedProcessorPool.HostID) - d.Set(Attr_SharedProcessorPoolStatus, response.SharedProcessorPool.Status) - d.Set(Attr_SharedProcessorPoolStatusDetail, response.SharedProcessorPool.StatusDetail) + d.Set(Attr_AllocatedCores, response.SharedProcessorPool.AllocatedCores) + d.Set(Attr_AvailableCores, response.SharedProcessorPool.AvailableCores) + d.Set(Attr_HostID, response.SharedProcessorPool.HostID) + d.Set(Attr_Name, response.SharedProcessorPool.Name) + d.Set(Attr_ReservedCores, response.SharedProcessorPool.ReservedCores) + d.Set(Attr_Status, response.SharedProcessorPool.Status) + d.Set(Attr_StatusDetail, response.SharedProcessorPool.StatusDetail) serversMap := []map[string]interface{}{} if response.Servers != nil { for _, s := range response.Servers { if s != nil { v := map[string]interface{}{ - Attr_SharedProcessorPoolInstanceCpus: s.Cpus, - Attr_SharedProcessorPoolInstanceUncapped: s.Uncapped, - Attr_SharedProcessorPoolInstanceAvailabilityZone: s.AvailabilityZone, - Attr_SharedProcessorPoolInstanceId: s.ID, - Attr_SharedProcessorPoolInstanceMemory: s.Memory, - Attr_SharedProcessorPoolInstanceName: s.Name, - Attr_SharedProcessorPoolInstanceStatus: s.Status, - Attr_SharedProcessorPoolInstanceVcpus: s.Vcpus, + Attr_AvailabilityZone: s.AvailabilityZone, + Attr_CPUs: s.Cpus, + Attr_ID: s.ID, + Attr_Memory: s.Memory, + Attr_Name: s.Name, + Attr_Status: s.Status, + Attr_Uncapped: s.Uncapped, + Attr_VCPUs: s.Vcpus, } serversMap = append(serversMap, v) } } } - d.Set(Attr_SharedProcessorPoolInstances, serversMap) + d.Set(Attr_Instances, serversMap) return nil } diff --git a/ibm/service/power/data_source_ibm_pi_shared_processor_pool_test.go b/ibm/service/power/data_source_ibm_pi_shared_processor_pool_test.go index a39f509265..17df24c366 100644 --- a/ibm/service/power/data_source_ibm_pi_shared_processor_pool_test.go +++ b/ibm/service/power/data_source_ibm_pi_shared_processor_pool_test.go @@ -28,9 +28,8 @@ func TestAccIBMPIPISharedProcessorPoolDataSource_basic(t *testing.T) { func testAccCheckIBMPIPISharedProcessorPoolDataSourceConfig() string { return fmt.Sprintf(` -data "ibm_pi_shared_processor_pool" "test_pool" { - pi_shared_processor_pool_id = "%s" - pi_cloud_instance_id = "%s" -}`, acc.Pi_shared_processor_pool_id, acc.Pi_cloud_instance_id) - + data "ibm_pi_shared_processor_pool" "test_pool" { + pi_shared_processor_pool_id = "%s" + pi_cloud_instance_id = "%s" + }`, acc.Pi_shared_processor_pool_id, acc.Pi_cloud_instance_id) } diff --git a/ibm/service/power/data_source_ibm_pi_shared_processor_pools.go b/ibm/service/power/data_source_ibm_pi_shared_processor_pools.go index e14611d878..74ccf37d22 100644 --- a/ibm/service/power/data_source_ibm_pi_shared_processor_pools.go +++ b/ibm/service/power/data_source_ibm_pi_shared_processor_pools.go @@ -6,70 +6,75 @@ package power import ( "context" + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "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" - - st "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/IBM-Cloud/power-go-client/helpers" - "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" -) - -const ( - PISharedProcessorPools = "shared_processor_pools" ) func DataSourceIBMPISharedProcessorPools() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMPISharedProcessorPoolsRead, Schema: map[string]*schema.Schema{ - helpers.PICloudInstanceId: { - Type: schema.TypeString, + // Arguments + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", Required: true, - Description: "PI cloud instance ID", + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, - // Computed Attributes - PISharedProcessorPools: { - Type: schema.TypeList, - Computed: true, + + // Attributes + Attr_SharedProcessorPools: { + Computed: true, + Description: "List of all the shared processor pools.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - Attr_SharedProcessorPoolID: { - Type: schema.TypeString, - Computed: true, + Attr_AllocatedCores: { + Computed: true, + Description: "The allocated cores in the shared processor pool.", + Type: schema.TypeFloat, }, - Attr_SharedProcessorPoolAllocatedCores: { - Type: schema.TypeFloat, - Computed: true, + Attr_AvailableCores: { + Computed: true, + Description: "The available cores in the shared processor pool.", + Type: schema.TypeInt, }, - Attr_SharedProcessorPoolAvailableCores: { - Type: schema.TypeInt, - Computed: true, + Attr_HostID: { + Computed: true, + Description: "The host ID where the shared processor pool resides.", + Type: schema.TypeInt, }, - Attr_SharedProcessorPoolName: { - Type: schema.TypeString, - Computed: true, + Attr_Name: { + Computed: true, + Description: "The name of the shared processor pool.", + Type: schema.TypeString, }, - Attr_SharedProcessorPoolReservedCores: { - Type: schema.TypeInt, - Computed: true, + Attr_ReservedCores: { + Computed: true, + Description: "The amount of reserved cores for the shared processor pool.", + Type: schema.TypeInt, }, - Attr_SharedProcessorPoolHostID: { - Type: schema.TypeInt, - Computed: true, + Attr_SharedProcessorPoolID: { + Computed: true, + Description: "The shared processor pool's unique ID.", + Type: schema.TypeString, }, - Attr_SharedProcessorPoolStatus: { - Type: schema.TypeString, - Computed: true, + Attr_Status: { + Computed: true, + Description: "The status of the shared processor pool.", + Type: schema.TypeString, }, - Attr_SharedProcessorPoolStatusDetail: { - Type: schema.TypeString, - Computed: true, + Attr_StatusDetail: { + Computed: true, + Description: "The status details of the shared processor pool.", + Type: schema.TypeString, }, }, }, + Type: schema.TypeList, }, }, } @@ -81,9 +86,9 @@ func dataSourceIBMPISharedProcessorPoolsRead(ctx context.Context, d *schema.Reso return diag.FromErr(err) } - cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) - client := st.NewIBMPISharedProcessorPoolClient(ctx, sess, cloudInstanceID) + client := instance.NewIBMPISharedProcessorPoolClient(ctx, sess, cloudInstanceID) pools, err := client.GetAll() if err != nil || pools == nil { return diag.Errorf("error fetching shared processor pools: %v", err) @@ -92,21 +97,21 @@ func dataSourceIBMPISharedProcessorPoolsRead(ctx context.Context, d *schema.Reso result := make([]map[string]interface{}, 0, len(pools.SharedProcessorPools)) for _, pool := range pools.SharedProcessorPools { key := map[string]interface{}{ - Attr_SharedProcessorPoolID: *pool.ID, - Attr_SharedProcessorPoolName: *pool.Name, - Attr_SharedProcessorPoolAllocatedCores: *pool.AllocatedCores, - Attr_SharedProcessorPoolAvailableCores: *pool.AvailableCores, - Attr_SharedProcessorPoolReservedCores: *pool.ReservedCores, - Attr_SharedProcessorPoolHostID: pool.HostID, - Attr_SharedProcessorPoolStatus: pool.Status, - Attr_SharedProcessorPoolStatusDetail: pool.StatusDetail, + Attr_AllocatedCores: *pool.AllocatedCores, + Attr_AvailableCores: *pool.AvailableCores, + Attr_HostID: pool.HostID, + Attr_Name: *pool.Name, + Attr_ReservedCores: *pool.ReservedCores, + Attr_SharedProcessorPoolID: *pool.ID, + Attr_Status: pool.Status, + Attr_StatusDetail: pool.StatusDetail, } result = append(result, key) } var genID, _ = uuid.GenerateUUID() d.SetId(genID) - d.Set(PISharedProcessorPools, result) + d.Set(Attr_SharedProcessorPools, result) return nil } diff --git a/ibm/service/power/data_source_ibm_pi_shared_processor_pools_test.go b/ibm/service/power/data_source_ibm_pi_shared_processor_pools_test.go index fcbb9c4dbb..1d5367bf85 100644 --- a/ibm/service/power/data_source_ibm_pi_shared_processor_pools_test.go +++ b/ibm/service/power/data_source_ibm_pi_shared_processor_pools_test.go @@ -30,6 +30,5 @@ func testAccCheckIBMPISharedProcessorPoolsDataSourceConfig() string { return fmt.Sprintf(` data "ibm_pi_shared_processor_pools" "test" { pi_cloud_instance_id = "%s" - } - `, acc.Pi_cloud_instance_id) + }`, acc.Pi_cloud_instance_id) } diff --git a/ibm/service/power/data_source_ibm_pi_snapshot.go b/ibm/service/power/data_source_ibm_pi_snapshot.go deleted file mode 100644 index b852f1024f..0000000000 --- a/ibm/service/power/data_source_ibm_pi_snapshot.go +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package power - -import ( - "context" - "log" - - "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/IBM-Cloud/power-go-client/helpers" - "github.com/IBM-Cloud/power-go-client/power/models" - "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" - "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" -) - -func DataSourceIBMPISnapshot() *schema.Resource { - - return &schema.Resource{ - ReadContext: dataSourceIBMPISnapshotRead, - Schema: map[string]*schema.Schema{ - - helpers.PICloudInstanceId: { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.NoZeroValues, - }, - - helpers.PIInstanceName: { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.NoZeroValues, - }, - //Computed Attributes - - "pvm_snapshots": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - }, - "name": { - Type: schema.TypeString, - Computed: true, - }, - "percent_complete": { - Type: schema.TypeInt, - Computed: true, - }, - - "description": { - Type: schema.TypeString, - Computed: true, - }, - "action": { - Type: schema.TypeString, - Computed: true, - }, - "status": { - Type: schema.TypeString, - Computed: true, - }, - "creation_date": { - Type: schema.TypeString, - Computed: true, - }, - "last_updated_date": { - Type: schema.TypeString, - Computed: true, - }, - "volume_snapshots": { - Type: schema.TypeMap, - Computed: true, - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMPISnapshotRead(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(helpers.PICloudInstanceId).(string) - powerinstancename := d.Get(helpers.PIInstanceName).(string) - snapshot := instance.NewIBMPIInstanceClient(ctx, sess, cloudInstanceID) - snapshotData, err := snapshot.GetSnapShotVM(powerinstancename) - - if err != nil { - return diag.FromErr(err) - } - - var clientgenU, _ = uuid.GenerateUUID() - d.SetId(clientgenU) - d.Set("pvm_snapshots", flattenPVMSnapshotInstances(snapshotData.Snapshots)) - - return nil - -} - -func flattenPVMSnapshotInstances(list []*models.Snapshot) []map[string]interface{} { - log.Printf("Calling the flattensnapshotinstances call with list %d", len(list)) - result := make([]map[string]interface{}, 0, len(list)) - for _, i := range list { - l := map[string]interface{}{ - "id": *i.SnapshotID, - "name": *i.Name, - "description": i.Description, - "creation_date": i.CreationDate.String(), - "last_updated_date": i.LastUpdateDate.String(), - "action": i.Action, - "percent_complete": i.PercentComplete, - "status": i.Status, - "volume_snapshots": i.VolumeSnapshots, - } - - result = append(result, l) - } - - return result -} diff --git a/ibm/service/power/data_source_ibm_pi_snapshots.go b/ibm/service/power/data_source_ibm_pi_snapshots.go deleted file mode 100644 index 273c0fcef8..0000000000 --- a/ibm/service/power/data_source_ibm_pi_snapshots.go +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package power - -import ( - "context" - "log" - - "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/IBM-Cloud/power-go-client/helpers" - "github.com/IBM-Cloud/power-go-client/power/models" - "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" - "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" -) - -func DataSourceIBMPISnapshots() *schema.Resource { - - return &schema.Resource{ - ReadContext: dataSourceIBMPISnapshotsRead, - Schema: map[string]*schema.Schema{ - helpers.PICloudInstanceId: { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.NoZeroValues, - }, - - //Computed Attributes - "instance_snapshots": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - }, - "name": { - Type: schema.TypeString, - Computed: true, - }, - "percent_complete": { - Type: schema.TypeInt, - Computed: true, - }, - "description": { - Type: schema.TypeString, - Computed: true, - }, - "action": { - Type: schema.TypeString, - Computed: true, - }, - "status": { - Type: schema.TypeString, - Computed: true, - }, - "creation_date": { - Type: schema.TypeString, - Computed: true, - }, - "last_updated_date": { - Type: schema.TypeString, - Computed: true, - }, - "volume_snapshots": { - Type: schema.TypeMap, - Computed: true, - }, - }, - }, - }, - }, - } -} - -func dataSourceIBMPISnapshotsRead(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(helpers.PICloudInstanceId).(string) - snapshot := instance.NewIBMPISnapshotClient(ctx, sess, cloudInstanceID) - snapshotData, err := snapshot.GetAll() - if err != nil { - return diag.FromErr(err) - } - - var clientgenU, _ = uuid.GenerateUUID() - d.SetId(clientgenU) - d.Set("instance_snapshots", flattenSnapshotsInstances(snapshotData.Snapshots)) - - return nil -} - -func flattenSnapshotsInstances(list []*models.Snapshot) []map[string]interface{} { - log.Printf("Calling the flattensnapshotsinstances call with list %d", len(list)) - result := make([]map[string]interface{}, 0, len(list)) - for _, i := range list { - l := map[string]interface{}{ - "id": *i.SnapshotID, - "name": *i.Name, - "description": i.Description, - "creation_date": i.CreationDate.String(), - "last_updated_date": i.LastUpdateDate.String(), - "action": i.Action, - "percent_complete": i.PercentComplete, - "status": i.Status, - "volume_snapshots": i.VolumeSnapshots, - } - - result = append(result, l) - } - - return result -} diff --git a/ibm/service/power/data_source_ibm_pi_spp_placement_group.go b/ibm/service/power/data_source_ibm_pi_spp_placement_group.go index 5b6f632ae3..2985750318 100644 --- a/ibm/service/power/data_source_ibm_pi_spp_placement_group.go +++ b/ibm/service/power/data_source_ibm_pi_spp_placement_group.go @@ -6,60 +6,61 @@ package power import ( "context" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - st "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/IBM-Cloud/power-go-client/helpers" + "github.com/IBM-Cloud/power-go-client/clients/instance" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "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" ) func DataSourceIBMPISPPPlacementGroup() *schema.Resource { - return &schema.Resource{ ReadContext: dataSourceIBMPISPPPlacementGroupRead, Schema: map[string]*schema.Schema{ - Arg_SPPPlacementGroupID: { - Type: schema.TypeString, - Required: true, - }, - - Attr_SPPPlacementGroupName: { - Type: schema.TypeString, - Computed: true, - }, - - Attr_SPPPlacementGroupPolicy: { - Type: schema.TypeString, - Computed: true, - }, - - helpers.PICloudInstanceId: { + // Arguments + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", + Required: true, Type: schema.TypeString, + ValidateFunc: validation.NoZeroValues, + }, + Arg_SPPPlacementGroupID: { + Description: "The ID of the shared processor pool placement group.", Required: true, + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, - Attr_SPPPlacementGroupMembers: { - Type: schema.TypeList, - Elem: &schema.Schema{Type: schema.TypeString}, - Computed: true, + // Attributes + Attr_Members: { + Computed: true, + Description: "List of shared processor pool IDs that are members of the placement group.", + Elem: &schema.Schema{Type: schema.TypeString}, + Type: schema.TypeList, + }, + Attr_Name: { + Computed: true, + Description: "The name of the shared processor pool placement group.", + Type: schema.TypeString, + }, + Attr_Policy: { + Computed: true, + Description: "The value of the group's affinity policy. Valid values are affinity and anti-affinity.", + Type: schema.TypeString, }, }, } } func dataSourceIBMPISPPPlacementGroupRead(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(helpers.PICloudInstanceId).(string) + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) placementGroupID := d.Get(Arg_SPPPlacementGroupID).(string) - client := st.NewIBMPISPPPlacementGroupClient(ctx, sess, cloudInstanceID) + client := instance.NewIBMPISPPPlacementGroupClient(ctx, sess, cloudInstanceID) response, err := client.Get(placementGroupID) if err != nil || response == nil { @@ -67,9 +68,9 @@ func dataSourceIBMPISPPPlacementGroupRead(ctx context.Context, d *schema.Resourc } d.SetId(*response.ID) - d.Set(Attr_SPPPlacementGroupName, response.Name) - d.Set(Attr_SPPPlacementGroupPolicy, response.Policy) - d.Set(Attr_SPPPlacementGroupMembers, response.MemberSharedProcessorPools) + d.Set(Attr_Members, response.MemberSharedProcessorPools) + d.Set(Attr_Name, response.Name) + d.Set(Attr_Policy, response.Policy) return nil } diff --git a/ibm/service/power/data_source_ibm_pi_spp_placement_group_test.go b/ibm/service/power/data_source_ibm_pi_spp_placement_group_test.go index a5f5d9d187..515a72b089 100644 --- a/ibm/service/power/data_source_ibm_pi_spp_placement_group_test.go +++ b/ibm/service/power/data_source_ibm_pi_spp_placement_group_test.go @@ -28,9 +28,8 @@ func TestAccIBMPISPPPlacementGroupDataSource_basic(t *testing.T) { func testAccCheckIBMPISPPPlacementGroupDataSourceConfig() string { return fmt.Sprintf(` -data "ibm_pi_spp_placement_group" "testacc_ds_spp_placement_group" { - pi_spp_placement_group_id = "%s" - pi_cloud_instance_id = "%s" -}`, acc.Pi_spp_placement_group_id, acc.Pi_cloud_instance_id) - + data "ibm_pi_spp_placement_group" "testacc_ds_spp_placement_group" { + pi_spp_placement_group_id = "%s" + pi_cloud_instance_id = "%s" + }`, acc.Pi_spp_placement_group_id, acc.Pi_cloud_instance_id) } diff --git a/ibm/service/power/data_source_ibm_pi_spp_placement_groups.go b/ibm/service/power/data_source_ibm_pi_spp_placement_groups.go index 8ac4d5d678..b75ab43e42 100644 --- a/ibm/service/power/data_source_ibm_pi_spp_placement_groups.go +++ b/ibm/service/power/data_source_ibm_pi_spp_placement_groups.go @@ -6,55 +6,56 @@ package power import ( "context" + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "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" - - st "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/IBM-Cloud/power-go-client/helpers" - "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" -) - -const ( - PISPPPlacementGroups = "spp_placement_groups" ) func DataSourceIBMPISPPPlacementGroups() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMPISPPPlacementGroupsRead, Schema: map[string]*schema.Schema{ - helpers.PICloudInstanceId: { - Type: schema.TypeString, + // Arguments + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", Required: true, - Description: "PI cloud instance ID", + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, - // Computed Attributes - PISPPPlacementGroups: { - Type: schema.TypeList, - Computed: true, + + // Attributes + Attr_SPPPlacementGroups: { + Computed: true, + Description: "List of all the shared processor pool placement groups.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - Attr_SPPPlacementGroupID: { - Type: schema.TypeString, - Computed: true, + Attr_Members: { + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "The list of shared processor pool IDs that are members of the shared processor pool placement group.", + Type: schema.TypeList, }, - Attr_SPPPlacementGroupName: { - Type: schema.TypeString, - Computed: true, + Attr_Name: { + Computed: true, + Description: "User defined name for the shared processor pool placement group.", + Type: schema.TypeString, }, - Attr_SPPPlacementGroupMembers: { - Type: schema.TypeList, - Elem: &schema.Schema{Type: schema.TypeString}, - Computed: true, + Attr_Policy: { + Computed: true, + Description: "The value of the group's affinity policy. Valid values are affinity and anti-affinity.", + Type: schema.TypeString, }, - Attr_SPPPlacementGroupPolicy: { - Type: schema.TypeString, - Computed: true, + Attr_SPPPlacementGroupID: { + Computed: true, + Description: "The ID of the shared processor pool placement group.", + Type: schema.TypeString, }, }, }, + Type: schema.TypeList, }, }, } @@ -66,9 +67,9 @@ func dataSourceIBMPISPPPlacementGroupsRead(ctx context.Context, d *schema.Resour return diag.FromErr(err) } - cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) - client := st.NewIBMPISPPPlacementGroupClient(ctx, sess, cloudInstanceID) + client := instance.NewIBMPISPPPlacementGroupClient(ctx, sess, cloudInstanceID) groups, err := client.GetAll() if err != nil || groups == nil { return diag.Errorf("error fetching spp placement groups: %v", err) @@ -77,17 +78,17 @@ func dataSourceIBMPISPPPlacementGroupsRead(ctx context.Context, d *schema.Resour result := make([]map[string]interface{}, 0, len(groups.SppPlacementGroups)) for _, placementGroup := range groups.SppPlacementGroups { key := map[string]interface{}{ - Attr_SPPPlacementGroupID: placementGroup.ID, - Attr_SPPPlacementGroupName: placementGroup.Name, - Attr_SPPPlacementGroupMembers: placementGroup.MemberSharedProcessorPools, - Attr_SPPPlacementGroupPolicy: placementGroup.Policy, + Attr_Members: placementGroup.MemberSharedProcessorPools, + Attr_Name: placementGroup.Name, + Attr_Policy: placementGroup.Policy, + Attr_SPPPlacementGroupID: placementGroup.ID, } result = append(result, key) } var genID, _ = uuid.GenerateUUID() d.SetId(genID) - d.Set(PISPPPlacementGroups, result) + d.Set(Attr_SPPPlacementGroups, result) return nil } diff --git a/ibm/service/power/data_source_ibm_pi_storage_pool_capacity.go b/ibm/service/power/data_source_ibm_pi_storage_pool_capacity.go index 84500c05d0..004cffea82 100644 --- a/ibm/service/power/data_source_ibm_pi_storage_pool_capacity.go +++ b/ibm/service/power/data_source_ibm_pi_storage_pool_capacity.go @@ -6,58 +6,53 @@ package power import ( "context" "fmt" - "log" - st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/clients/instance" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" - - "github.com/IBM-Cloud/power-go-client/helpers" "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" ) -const ( - PIPoolName = "pi_storage_pool" -) - func DataSourceIBMPIStoragePoolCapacity() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMPIStoragePoolCapacityRead, Schema: map[string]*schema.Schema{ - helpers.PICloudInstanceId: { - Type: schema.TypeString, + // Arguments + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", Required: true, + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, - PIPoolName: { - Type: schema.TypeString, + Arg_StoragePool: { + Description: "The storage pool name.", Required: true, + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, - Description: "Storage pool name", }, - // Computed Attributes - MaxAllocationSize: { - Type: schema.TypeInt, + + // Attributes + Attr_MaxAllocationSize: { Computed: true, - Description: "Maximum allocation storage size (GB)", + Description: "Maximum allocation storage size (GB).", + Type: schema.TypeInt, }, - StorageType: { - Type: schema.TypeString, + Attr_ReplicationEnabled: { Computed: true, - Description: "Storage type of the storage pool", + Description: "Replication status of the storage pool.", + Type: schema.TypeBool, }, - TotalCapacity: { - Type: schema.TypeInt, + Attr_StorageType: { Computed: true, - Description: "Total pool capacity (GB)", + Description: "Storage type of the storage pool.", + Type: schema.TypeString, }, - ReplicationEnabled: { - Type: schema.TypeBool, + Attr_TotalCapacity: { Computed: true, - Description: "Replication status of the storage pool", + Description: "Total pool capacity (GB).", + Type: schema.TypeInt, }, }, } @@ -69,10 +64,10 @@ func dataSourceIBMPIStoragePoolCapacityRead(ctx context.Context, d *schema.Resou return diag.FromErr(err) } - cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) - storagePool := d.Get(PIPoolName).(string) + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) + storagePool := d.Get(Arg_StoragePool).(string) - client := st.NewIBMPIStorageCapacityClient(ctx, sess, cloudInstanceID) + client := instance.NewIBMPIStorageCapacityClient(ctx, sess, cloudInstanceID) sp, err := client.GetStoragePoolCapacity(storagePool) if err != nil { log.Printf("[ERROR] get storage pool capacity failed %v", err) @@ -80,9 +75,9 @@ func dataSourceIBMPIStoragePoolCapacityRead(ctx context.Context, d *schema.Resou } d.SetId(fmt.Sprintf("%s/%s", cloudInstanceID, storagePool)) - d.Set(MaxAllocationSize, *sp.MaxAllocationSize) - d.Set(StorageType, sp.StorageType) - d.Set(TotalCapacity, sp.TotalCapacity) - d.Set(ReplicationEnabled, *sp.ReplicationEnabled) + d.Set(Attr_MaxAllocationSize, *sp.MaxAllocationSize) + d.Set(Attr_ReplicationEnabled, *sp.ReplicationEnabled) + d.Set(Attr_StorageType, sp.StorageType) + d.Set(Attr_TotalCapacity, sp.TotalCapacity) return nil } diff --git a/ibm/service/power/data_source_ibm_pi_storage_pools_capacity.go b/ibm/service/power/data_source_ibm_pi_storage_pools_capacity.go index 4e64ec5209..6c5ac36fd4 100644 --- a/ibm/service/power/data_source_ibm_pi_storage_pools_capacity.go +++ b/ibm/service/power/data_source_ibm_pi_storage_pools_capacity.go @@ -5,95 +5,82 @@ package power import ( "context" - "log" - st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/clients/instance" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" - - "github.com/IBM-Cloud/power-go-client/helpers" "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" ) -const ( - MaximumStorageAllocation = "maximum_storage_allocation" - StoragePoolsCapacity = "storage_pools_capacity" - MaxAllocationSize = "max_allocation_size" - PoolName = "pool_name" - StoragePool = "storage_pool" - StorageType = "storage_type" - TotalCapacity = "total_capacity" - ReplicationEnabled = "replication_enabled" -) - func DataSourceIBMPIStoragePoolsCapacity() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMPIStoragePoolsCapacityRead, Schema: map[string]*schema.Schema{ - helpers.PICloudInstanceId: { - Type: schema.TypeString, + // Arguments + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", Required: true, + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, - // Computed Attributes - MaximumStorageAllocation: { - Type: schema.TypeMap, + + // Attributes + Attr_MaximumStorageAllocation: { Computed: true, - Description: "Maximum storage allocation", + Description: "Maximum storage allocation.", + Type: schema.TypeMap, }, - StoragePoolsCapacity: { - Type: schema.TypeList, + Attr_StoragePoolsCapacity: { Computed: true, - Description: "Storage pools capacity", + Description: "List of storage pools capacity.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - MaxAllocationSize: { - Type: schema.TypeInt, + Attr_MaxAllocationSize: { Computed: true, - Description: "Maximum allocation storage size (GB)", + Description: "Maximum allocation storage size (GB).", + Type: schema.TypeInt, }, - PoolName: { - Type: schema.TypeString, + Attr_PoolName: { Computed: true, - Description: "Pool name", - }, - StorageType: { + Description: "The pool name.", Type: schema.TypeString, + }, + Attr_ReplicationEnabled: { Computed: true, - Description: "Storage type of the storage pool", + Description: "Replication status of the storage pool.", + Type: schema.TypeBool, }, - TotalCapacity: { - Type: schema.TypeInt, + Attr_StorageType: { Computed: true, - Description: "Total pool capacity (GB)", + Description: "Storage type of the storage pool.", + Type: schema.TypeString, }, - ReplicationEnabled: { - Type: schema.TypeBool, + Attr_TotalCapacity: { Computed: true, - Description: "Replication status of the storage pool", + Description: "Total pool capacity (GB).", + Type: schema.TypeInt, }, }, }, + Type: schema.TypeList, }, }, } } func dataSourceIBMPIStoragePoolsCapacityRead(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(helpers.PICloudInstanceId).(string) + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) - client := st.NewIBMPIStorageCapacityClient(ctx, sess, cloudInstanceID) + client := instance.NewIBMPIStorageCapacityClient(ctx, sess, cloudInstanceID) spc, err := client.GetAllStoragePoolsCapacity() if err != nil { log.Printf("[ERROR] get all storage pools capacity failed %v", err) @@ -106,26 +93,25 @@ func dataSourceIBMPIStoragePoolsCapacityRead(ctx context.Context, d *schema.Reso if spc.MaximumStorageAllocation != nil { msa := spc.MaximumStorageAllocation data := map[string]interface{}{ - MaxAllocationSize: *msa.MaxAllocationSize, - StoragePool: *msa.StoragePool, - StorageType: *msa.StorageType, + Attr_MaxAllocationSize: *msa.MaxAllocationSize, + Attr_StoragePool: *msa.StoragePool, + Attr_StorageType: *msa.StorageType, } - d.Set(MaximumStorageAllocation, flex.Flatten(data)) + d.Set(Attr_MaximumStorageAllocation, flex.Flatten(data)) } result := make([]map[string]interface{}, 0, len(spc.StoragePoolsCapacity)) for _, sp := range spc.StoragePoolsCapacity { data := map[string]interface{}{ - MaxAllocationSize: *sp.MaxAllocationSize, - PoolName: sp.PoolName, - StorageType: sp.StorageType, - TotalCapacity: sp.TotalCapacity, - ReplicationEnabled: *sp.ReplicationEnabled, + Attr_MaxAllocationSize: *sp.MaxAllocationSize, + Attr_PoolName: sp.PoolName, + Attr_ReplicationEnabled: *sp.ReplicationEnabled, + Attr_StorageType: sp.StorageType, + Attr_TotalCapacity: sp.TotalCapacity, } - result = append(result, data) } - d.Set(StoragePoolsCapacity, result) + d.Set(Attr_StoragePoolsCapacity, result) return nil } diff --git a/ibm/service/power/data_source_ibm_pi_storage_type_capacity.go b/ibm/service/power/data_source_ibm_pi_storage_type_capacity.go index d33d338ff1..6fa01bab6c 100644 --- a/ibm/service/power/data_source_ibm_pi_storage_type_capacity.go +++ b/ibm/service/power/data_source_ibm_pi_storage_type_capacity.go @@ -40,33 +40,33 @@ func DataSourceIBMPIStorageTypeCapacity() *schema.Resource { Description: "Storage type name", }, // Computed Attributes - MaximumStorageAllocation: { + Attr_MaximumStorageAllocation: { Type: schema.TypeMap, Computed: true, Description: "Maximum storage allocation", }, - StoragePoolsCapacity: { + Attr_StoragePoolsCapacity: { Type: schema.TypeList, Computed: true, Description: "Storage pools capacity", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - MaxAllocationSize: { + Attr_MaxAllocationSize: { Type: schema.TypeInt, Computed: true, Description: "Maximum allocation storage size (GB)", }, - PoolName: { + Attr_PoolName: { Type: schema.TypeString, Computed: true, Description: "Pool name", }, - StorageType: { + Attr_StorageType: { Type: schema.TypeString, Computed: true, Description: "Storage type of the storage pool", }, - TotalCapacity: { + Attr_TotalCapacity: { Type: schema.TypeInt, Computed: true, Description: "Total pool capacity (GB)", @@ -99,24 +99,24 @@ func dataSourceIBMPIStorageTypeCapacityRead(ctx context.Context, d *schema.Resou if stc.MaximumStorageAllocation != nil { msa := stc.MaximumStorageAllocation data := map[string]interface{}{ - MaxAllocationSize: *msa.MaxAllocationSize, - StoragePool: *msa.StoragePool, - StorageType: *msa.StorageType, + Attr_MaxAllocationSize: *msa.MaxAllocationSize, + Attr_StoragePool: *msa.StoragePool, + Attr_StorageType: *msa.StorageType, } - d.Set(MaximumStorageAllocation, flex.Flatten(data)) + d.Set(Attr_MaximumStorageAllocation, flex.Flatten(data)) } result := make([]map[string]interface{}, 0, len(stc.StoragePoolsCapacity)) for _, sp := range stc.StoragePoolsCapacity { data := map[string]interface{}{ - MaxAllocationSize: *sp.MaxAllocationSize, - PoolName: sp.PoolName, - StorageType: sp.StorageType, - TotalCapacity: sp.TotalCapacity, + Attr_MaxAllocationSize: *sp.MaxAllocationSize, + Attr_PoolName: sp.PoolName, + Attr_StorageType: sp.StorageType, + Attr_TotalCapacity: sp.TotalCapacity, } result = append(result, data) } - d.Set(StoragePoolsCapacity, result) + d.Set(Attr_StoragePoolsCapacity, result) return nil } diff --git a/ibm/service/power/data_source_ibm_pi_storage_types_capacity.go b/ibm/service/power/data_source_ibm_pi_storage_types_capacity.go index 59feb27952..5f3f169dbe 100644 --- a/ibm/service/power/data_source_ibm_pi_storage_types_capacity.go +++ b/ibm/service/power/data_source_ibm_pi_storage_types_capacity.go @@ -34,7 +34,7 @@ func DataSourceIBMPIStorageTypesCapacity() *schema.Resource { ValidateFunc: validation.NoZeroValues, }, // Computed Attributes - MaximumStorageAllocation: { + Attr_MaximumStorageAllocation: { Type: schema.TypeMap, Computed: true, Description: "Maximum storage allocation", @@ -45,33 +45,33 @@ func DataSourceIBMPIStorageTypesCapacity() *schema.Resource { Description: "Storage types capacity", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - MaximumStorageAllocation: { + Attr_MaximumStorageAllocation: { Type: schema.TypeMap, Computed: true, Description: "Maximum storage allocation", }, - StoragePoolsCapacity: { + Attr_StoragePoolsCapacity: { Type: schema.TypeList, Computed: true, Description: "Storage pools capacity", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - MaxAllocationSize: { + Attr_MaxAllocationSize: { Type: schema.TypeInt, Computed: true, Description: "Maximum allocation storage size (GB)", }, - PoolName: { + Attr_PoolName: { Type: schema.TypeString, Computed: true, Description: "Pool name", }, - StorageType: { + Attr_StorageType: { Type: schema.TypeString, Computed: true, Description: "Storage type of the storage pool", }, - TotalCapacity: { + Attr_TotalCapacity: { Type: schema.TypeInt, Computed: true, Description: "Total pool capacity (GB)", @@ -79,7 +79,7 @@ func DataSourceIBMPIStorageTypesCapacity() *schema.Resource { }, }, }, - StorageType: { + Attr_StorageType: { Type: schema.TypeString, Computed: true, Description: "The storage type", @@ -112,11 +112,11 @@ func dataSourceIBMPIStorageTypesCapacityRead(ctx context.Context, d *schema.Reso if stc.MaximumStorageAllocation != nil { msa := stc.MaximumStorageAllocation data := map[string]interface{}{ - MaxAllocationSize: *msa.MaxAllocationSize, - StoragePool: *msa.StoragePool, - StorageType: *msa.StorageType, + Attr_MaxAllocationSize: *msa.MaxAllocationSize, + Attr_StoragePool: *msa.StoragePool, + Attr_StorageType: *msa.StorageType, } - d.Set(MaximumStorageAllocation, flex.Flatten(data)) + d.Set(Attr_MaximumStorageAllocation, flex.Flatten(data)) } stcResult := make([]map[string]interface{}, 0, len(stc.StorageTypesCapacity)) for _, st := range stc.StorageTypesCapacity { @@ -124,24 +124,24 @@ func dataSourceIBMPIStorageTypesCapacityRead(ctx context.Context, d *schema.Reso if st.MaximumStorageAllocation != nil { msa := st.MaximumStorageAllocation data := map[string]interface{}{ - MaxAllocationSize: *msa.MaxAllocationSize, - StoragePool: *msa.StoragePool, - StorageType: *msa.StorageType, + Attr_MaxAllocationSize: *msa.MaxAllocationSize, + Attr_StoragePool: *msa.StoragePool, + Attr_StorageType: *msa.StorageType, } - stResult[MaximumStorageAllocation] = flex.Flatten(data) + stResult[Attr_MaximumStorageAllocation] = flex.Flatten(data) } spc := make([]map[string]interface{}, 0, len(st.StoragePoolsCapacity)) for _, sp := range st.StoragePoolsCapacity { data := map[string]interface{}{ - MaxAllocationSize: *sp.MaxAllocationSize, - PoolName: sp.PoolName, - StorageType: sp.StorageType, - TotalCapacity: sp.TotalCapacity, + Attr_MaxAllocationSize: *sp.MaxAllocationSize, + Attr_PoolName: sp.PoolName, + Attr_StorageType: sp.StorageType, + Attr_TotalCapacity: sp.TotalCapacity, } spc = append(spc, data) } - stResult[StoragePoolsCapacity] = spc - stResult[StorageType] = st.StorageType + stResult[Attr_StoragePoolsCapacity] = spc + stResult[Attr_StorageType] = st.StorageType stcResult = append(stcResult, stResult) } diff --git a/ibm/service/power/data_source_ibm_pi_system_pools.go b/ibm/service/power/data_source_ibm_pi_system_pools.go index 7e2f52b633..f1664e0bc6 100644 --- a/ibm/service/power/data_source_ibm_pi_system_pools.go +++ b/ibm/service/power/data_source_ibm_pi_system_pools.go @@ -5,121 +5,100 @@ package power import ( "context" - "log" - st "github.com/IBM-Cloud/power-go-client/clients/instance" + "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" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" - - "github.com/IBM-Cloud/power-go-client/helpers" "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" ) -const ( - SystemPoolName = "system_pool_name" - SystemPools = "system_pools" - SystemPool = "system_pool" - Capacity = "capacity" - CoreMemoryRatio = "core_memory_ratio" - MaxAvailable = "max_available" - MaxCoresAvailable = "max_cores_available" - MaxMemoryAvailable = "max_memory_available" - SharedCoreRatio = "shared_core_ratio" - Type = "type" - Systems = "systems" - Cores = "cores" - ID = "id" - Memory = "memory" - Default = "default" - Max = "max" - Min = "min" -) - func DataSourceIBMPISystemPools() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMPISystemPoolsRead, Schema: map[string]*schema.Schema{ - helpers.PICloudInstanceId: { - Type: schema.TypeString, + // Arguments + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", Required: true, + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, - // Computed Attributes - SystemPools: { + + // Attributes + Attr_SystemPools: { Type: schema.TypeList, Computed: true, - Description: "List of available system pools within a particular DataCenter", + Description: "List of available system pools within a particular Datacenter.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - SystemPoolName: { - Type: schema.TypeString, + Attr_Capacity: { Computed: true, - Description: "The system pool name", - }, - Capacity: { + Description: "Advertised capacity cores and memory (GB).", Type: schema.TypeMap, - Computed: true, - Description: "Advertised capacity cores and memory (GB)", }, - CoreMemoryRatio: { - Type: schema.TypeFloat, + Attr_CoreMemoryRatio: { Computed: true, - Description: "Processor to Memory (GB) Ratio", + Description: "Processor to Memory (GB) Ratio.", + Type: schema.TypeFloat, }, - MaxAvailable: { - Type: schema.TypeMap, + Attr_MaxAvailable: { Computed: true, - Description: "Maximum configurable cores and memory (GB) (aggregated from all hosts)", - }, - MaxCoresAvailable: { + Description: "Maximum configurable cores and memory (GB) (aggregated from all hosts).", Type: schema.TypeMap, - Computed: true, - Description: "Maximum configurable cores available combined with available memory of that host", }, - MaxMemoryAvailable: { + Attr_MaxCoresAvailable: { + Computed: true, + Description: "Maximum configurable cores available combined with available memory of that host.", Type: schema.TypeMap, + }, + Attr_MaxMemoryAvailable: { Computed: true, - Description: "Maximum configurable memory available combined with available cores of that host", + Description: "Maximum configurable memory available combined with available cores of that host.", + Type: schema.TypeMap, }, - SharedCoreRatio: { + Attr_SharedCoreRatio: { + Computed: true, + Description: "The min-max-default allocation percentage of shared core per vCPU.", Type: schema.TypeMap, + }, + Attr_SystemPoolName: { Computed: true, - Description: "The min-max-default allocation percentage of shared core per vCPU", + Description: "The system pool name", + Type: schema.TypeString, }, - Systems: { - Type: schema.TypeList, + Attr_Systems: { Computed: true, - Description: "The DataCenter list of servers and their available resources", + Description: "The Datacenter list of servers and their available resources.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - Cores: { - Type: schema.TypeString, + Attr_Cores: { Computed: true, - Description: "The host available Processor units", - }, - ID: { + Description: "The host available Processor units.", Type: schema.TypeString, - Computed: true, - Description: "The host identifier", }, - Memory: { + Attr_ID: { + Computed: true, + Description: "The host identifier.", Type: schema.TypeString, + }, + Attr_Memory: { Computed: true, - Description: "The host available RAM memory in GiB", + Description: "The host available RAM memory in GiB.", + Type: schema.TypeString, }, }, }, + Type: schema.TypeList, }, - Type: { - Type: schema.TypeString, + Attr_Type: { Computed: true, - Description: "Type of system hardware", + Description: "Type of system hardware.", + Type: schema.TypeString, }, }, }, @@ -134,9 +113,9 @@ func dataSourceIBMPISystemPoolsRead(ctx context.Context, d *schema.ResourceData, return diag.FromErr(err) } - cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) - client := st.NewIBMPISystemPoolClient(ctx, sess, cloudInstanceID) + client := instance.NewIBMPISystemPoolClient(ctx, sess, cloudInstanceID) sps, err := client.GetSystemPools() if err != nil { log.Printf("[ERROR] get system pools capacity failed %v", err) @@ -149,37 +128,37 @@ func dataSourceIBMPISystemPoolsRead(ctx context.Context, d *schema.ResourceData, result := make([]map[string]interface{}, 0, len(sps)) for s, sp := range sps { data := map[string]interface{}{ - SystemPoolName: s, - Capacity: flattenMax(sp.Capacity), - CoreMemoryRatio: sp.CoreMemoryRatio, - MaxAvailable: flattenMax(sp.MaxAvailable), - MaxCoresAvailable: flattenMax(sp.MaxCoresAvailable), - MaxMemoryAvailable: flattenMax(sp.MaxMemoryAvailable), - SharedCoreRatio: flattenSharedCoreRatio(sp.SharedCoreRatio), - Type: sp.Type, - Systems: flattenSystems(sp.Systems), + Attr_SystemPoolName: s, + Attr_Capacity: flattenMax(sp.Capacity), + Attr_CoreMemoryRatio: sp.CoreMemoryRatio, + Attr_MaxAvailable: flattenMax(sp.MaxAvailable), + Attr_MaxCoresAvailable: flattenMax(sp.MaxCoresAvailable), + Attr_MaxMemoryAvailable: flattenMax(sp.MaxMemoryAvailable), + Attr_SharedCoreRatio: flattenSharedCoreRatio(sp.SharedCoreRatio), + Attr_Type: sp.Type, + Attr_Systems: flattenSystems(sp.Systems), } result = append(result, data) } - d.Set(SystemPools, result) + d.Set(Attr_SystemPools, result) return nil } func flattenMax(s *models.System) map[string]string { ret := map[string]interface{}{ - Cores: *s.Cores, - Memory: *s.Memory, + Attr_Cores: *s.Cores, + Attr_Memory: *s.Memory, } return flex.Flatten(ret) } func flattenSystem(s *models.System) map[string]string { ret := map[string]interface{}{ - Cores: *s.Cores, - ID: s.ID, - Memory: *s.Memory, + Attr_Cores: *s.Cores, + Attr_ID: s.ID, + Attr_Memory: *s.Memory, } return flex.Flatten(ret) } @@ -197,9 +176,9 @@ func flattenSystems(sl []*models.System) (systems []map[string]string) { func flattenSharedCoreRatio(scr *models.MinMaxDefault) map[string]string { ret := map[string]interface{}{ - Default: scr.Default, - Max: scr.Max, - Min: scr.Min, + Attr_Default: scr.Default, + Attr_Max: scr.Max, + Attr_Min: scr.Min, } return flex.Flatten(ret) } diff --git a/ibm/service/power/data_source_ibm_pi_workspace.go b/ibm/service/power/data_source_ibm_pi_workspace.go index 6fb23303ea..0864470922 100644 --- a/ibm/service/power/data_source_ibm_pi_workspace.go +++ b/ibm/service/power/data_source_ibm_pi_workspace.go @@ -7,7 +7,6 @@ import ( "context" "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/IBM-Cloud/power-go-client/helpers" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" @@ -15,68 +14,63 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) -const ( - WorkspaceCreationDate = "creation_date" - WorkspaceCRN = "crn" - WorkspaceRegion = "region" - WorkspaceType = "type" - WorkspaceUrl = "url" -) - func DatasourceIBMPIWorkspace() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMPIWorkspaceRead, Schema: map[string]*schema.Schema{ + // Arguments Arg_CloudInstanceID: { - Type: schema.TypeString, + Description: "The GUID of the service instance associated with an account.", Required: true, + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, + + // Attributes Attr_WorkspaceCapabilities: { - Type: schema.TypeMap, Computed: true, - Description: "Workspace Capabilities", + Description: "Workspace Capabilities.", Elem: &schema.Schema{ Type: schema.TypeBool, }, + Type: schema.TypeMap, }, Attr_WorkspaceDetails: { - Type: schema.TypeMap, Computed: true, - Description: "Workspace information", + Description: "Workspace information.", + Type: schema.TypeMap, }, Attr_WorkspaceLocation: { - Type: schema.TypeMap, Computed: true, - Description: "Workspace location", + Description: "Workspace location.", + Type: schema.TypeMap, }, Attr_WorkspaceName: { - Type: schema.TypeString, Computed: true, - Description: "Workspace name", + Description: "Workspace name.", + Type: schema.TypeString, }, Attr_WorkspaceStatus: { - Type: schema.TypeString, Computed: true, - Description: "Workspace status", + Description: "Workspace status, active, critical, failed, provisioning.", + Type: schema.TypeString, }, Attr_WorkspaceType: { - Type: schema.TypeString, Computed: true, - Description: "Workspace type", + Description: "Workspace type, off-premises or on-premises.", + Type: schema.TypeString, }, }, } } func dataSourceIBMPIWorkspaceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - // session sess, err := meta.(conns.ClientSession).IBMPISession() if err != nil { return diag.FromErr(err) } - cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) client := instance.NewIBMPIWorkspacesClient(ctx, sess, cloudInstanceID) wsData, err := client.Get(cloudInstanceID) if err != nil { @@ -88,14 +82,14 @@ func dataSourceIBMPIWorkspaceRead(ctx context.Context, d *schema.ResourceData, m d.Set(Attr_WorkspaceType, wsData.Type) d.Set(Attr_WorkspaceCapabilities, wsData.Capabilities) wsdetails := map[string]interface{}{ - WorkspaceCreationDate: wsData.Details.CreationDate.String(), - WorkspaceCRN: *wsData.Details.Crn, + Attr_CreationDate: wsData.Details.CreationDate.String(), + Attr_CRN: *wsData.Details.Crn, } d.Set(Attr_WorkspaceDetails, flex.Flatten(wsdetails)) wslocation := map[string]interface{}{ - WorkspaceRegion: *wsData.Location.Region, - WorkspaceType: wsData.Location.Type, - WorkspaceUrl: wsData.Location.URL, + Attr_Region: *wsData.Location.Region, + Attr_Type: wsData.Location.Type, + Attr_URL: wsData.Location.URL, } d.Set(Attr_WorkspaceLocation, flex.Flatten(wslocation)) d.SetId(*wsData.ID) diff --git a/ibm/service/power/data_source_ibm_pi_workspace_test.go b/ibm/service/power/data_source_ibm_pi_workspace_test.go index b2adea8072..4a7df8e63a 100644 --- a/ibm/service/power/data_source_ibm_pi_workspace_test.go +++ b/ibm/service/power/data_source_ibm_pi_workspace_test.go @@ -25,10 +25,10 @@ func TestAccIBMPIWorkspaceDataSourceBasic(t *testing.T) { }, }) } + func testAccCheckIBMPIWorkspaceDataSourceConfig() string { return fmt.Sprintf(` data "ibm_pi_workspace" "test" { pi_cloud_instance_id = "%s" - } - `, acc.Pi_cloud_instance_id) + }`, acc.Pi_cloud_instance_id) } diff --git a/ibm/service/power/data_source_ibm_pi_workspaces.go b/ibm/service/power/data_source_ibm_pi_workspaces.go index c66e924b63..1208562947 100644 --- a/ibm/service/power/data_source_ibm_pi_workspaces.go +++ b/ibm/service/power/data_source_ibm_pi_workspaces.go @@ -7,7 +7,6 @@ import ( "context" "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/IBM-Cloud/power-go-client/helpers" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/hashicorp/go-uuid" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" @@ -15,62 +14,61 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) -const ( - Workspaces = "workspaces" -) - func DatasourceIBMPIWorkspaces() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMPIWorkspacesRead, Schema: map[string]*schema.Schema{ + // Arguments Arg_CloudInstanceID: { - Type: schema.TypeString, + Description: "The GUID of the service instance associated with an account.", Required: true, + Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, - Workspaces: { + + // Attributes + Attr_Workspaces: { Type: schema.TypeList, Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - Attr_WorkspaceCapabilities: { - Type: schema.TypeMap, Computed: true, - Description: "Workspace Capabilities", + Description: "Workspace Capabilities.", Elem: &schema.Schema{ Type: schema.TypeBool, }, + Type: schema.TypeMap, }, Attr_WorkspaceDetails: { - Type: schema.TypeMap, Computed: true, - Description: "Workspace information", + Description: "Workspace information.", + Type: schema.TypeMap, }, Attr_WorkspaceID: { - Type: schema.TypeString, Computed: true, - Description: "Workspace ID", + Description: "Workspace ID.", + Type: schema.TypeString, }, Attr_WorkspaceLocation: { - Type: schema.TypeMap, Computed: true, - Description: "Workspace location", + Description: "Workspace location.", + Type: schema.TypeMap, }, Attr_WorkspaceName: { - Type: schema.TypeString, Computed: true, - Description: "Workspace name", + Description: "Workspace name.", + Type: schema.TypeString, }, Attr_WorkspaceStatus: { - Type: schema.TypeString, Computed: true, - Description: "Workspace status", + Description: "Workspace status, active, critical, failed, provisioning.", + Type: schema.TypeString, }, Attr_WorkspaceType: { - Type: schema.TypeString, Computed: true, - Description: "Workspace type", + Description: "Workspace type, off-premises or on-premises.", + Type: schema.TypeString, }, }, }, @@ -79,13 +77,12 @@ func DatasourceIBMPIWorkspaces() *schema.Resource { } } func dataSourceIBMPIWorkspacesRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - // session sess, err := meta.(conns.ClientSession).IBMPISession() if err != nil { return diag.FromErr(err) } - cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) client := instance.NewIBMPIWorkspacesClient(ctx, sess, cloudInstanceID) wsData, err := client.GetAll() if err != nil { @@ -95,26 +92,26 @@ func dataSourceIBMPIWorkspacesRead(ctx context.Context, d *schema.ResourceData, for _, ws := range wsData.Workspaces { if ws != nil { workspace := map[string]interface{}{ - Attr_WorkspaceName: ws.Name, - Attr_WorkspaceID: ws.ID, - Attr_WorkspaceStatus: ws.Status, - Attr_WorkspaceType: ws.Type, Attr_WorkspaceCapabilities: ws.Capabilities, Attr_WorkspaceDetails: map[string]interface{}{ - WorkspaceCreationDate: ws.Details.CreationDate.String(), - WorkspaceCRN: *ws.Details.Crn, + Attr_CreationDate: ws.Details.CreationDate.String(), + Attr_CRN: *ws.Details.Crn, }, + Attr_WorkspaceID: ws.ID, Attr_WorkspaceLocation: map[string]interface{}{ - WorkspaceRegion: *ws.Location.Region, - WorkspaceType: ws.Location.Type, - WorkspaceUrl: ws.Location.URL, + Attr_Region: *ws.Location.Region, + Attr_Type: ws.Location.Type, + Attr_URL: ws.Location.URL, }, + Attr_WorkspaceName: ws.Name, + Attr_WorkspaceStatus: ws.Status, + Attr_WorkspaceType: ws.Type, } workspaces = append(workspaces, workspace) } } var clientgenU, _ = uuid.GenerateUUID() d.SetId(clientgenU) - d.Set(Workspaces, workspaces) + d.Set(Attr_Workspaces, workspaces) return nil } diff --git a/ibm/service/power/data_source_ibm_pi_workspaces_test.go b/ibm/service/power/data_source_ibm_pi_workspaces_test.go index 076d65a342..10b38e677a 100644 --- a/ibm/service/power/data_source_ibm_pi_workspaces_test.go +++ b/ibm/service/power/data_source_ibm_pi_workspaces_test.go @@ -30,6 +30,5 @@ func testAccCheckIBMPIWorkspacesDataSourceConfig() string { return fmt.Sprintf(` data "ibm_pi_workspaces" "test" { pi_cloud_instance_id = "%s" - } - `, acc.Pi_cloud_instance_id) + }`, acc.Pi_cloud_instance_id) } diff --git a/ibm/service/power/ibm_pi_constants.go b/ibm/service/power/ibm_pi_constants.go index b4f18b330c..11f7a890dc 100644 --- a/ibm/service/power/ibm_pi_constants.go +++ b/ibm/service/power/ibm_pi_constants.go @@ -3,18 +3,253 @@ package power import "time" const ( - // used by all - Arg_CloudInstanceID = "pi_cloud_instance_id" + // Arguments + Arg_CloudConnectionName = "pi_cloud_connection_name" + Arg_CloudInstanceID = "pi_cloud_instance_id" + Arg_ImageName = "pi_image_name" + Arg_InstanceName = "pi_instance_name" + Arg_Key = "pi_ssh_key" + Arg_KeyName = "pi_key_name" + Arg_NetworkName = "pi_network_name" + Arg_PlacementGroupName = "pi_placement_group_name" + Arg_SAP = "sap" + Arg_SAPProfileID = "pi_sap_profile_id" + Arg_SPPPlacementGroupID = "pi_spp_placement_group_id" + Arg_SPPPlacementGroupName = "pi_spp_placement_group_name" + Arg_SPPPlacementGroupPolicy = "pi_spp_placement_group_policy" + Arg_SharedProcessorPoolHostGroup = "pi_shared_processor_pool_host_group" + Arg_SharedProcessorPoolID = "pi_shared_processor_pool_id" + Arg_SharedProcessorPoolName = "pi_shared_processor_pool_name" + Arg_SharedProcessorPoolPlacementGroupID = "pi_shared_processor_pool_placement_group_id" + Arg_SharedProcessorPoolReservedCores = "pi_shared_processor_pool_reserved_cores" + Arg_SnapshotID = "pi_snapshot_id" + Arg_StoragePool = "pi_storage_pool" + Arg_StorageType = "pi_storage_type" + Arg_VTL = "vtl" + Arg_VolumeGroupID = "pi_volume_group_id" + Arg_VolumeID = "pi_volume_id" + Arg_VolumeOnboardingID = "pi_volume_onboarding_id" - // Keys - Arg_KeyName = "pi_key_name" - Arg_Key = "pi_ssh_key" + // Attributes + Attr_AccessConfig = "access_config" + Attr_Action = "action" + Attr_Addresses = "addresses" + Attr_AllocatedCores = "allocated_cores" + Attr_Architecture = "architecture" + Attr_Auxiliary = "auxiliary" + Attr_AuxiliaryChangedVolumeName = "auxiliary_changed_volume_name" + Attr_AuxiliaryVolumeName = "auxiliary_volume_name" + Attr_AvailabilityZone = "availability_zone" + Attr_AvailableCores = "available_cores" + Attr_AvailableIPCount = "available_ip_count" + Attr_BootVolumeID = "boot_volume_id" + Attr_Bootable = "bootable" + Attr_CIDR = "cidr" + Attr_CPUs = "cpus" + Attr_CRN = "crn" + Attr_Capabilities = "capabilities" + Attr_Capacity = "capacity" + Attr_Certified = "certified" + Attr_ClassicEnabled = "classic_enabled" + Attr_CloudConnectionID = "cloud_connection_id" + Attr_CloudInstanceID = "cloud_instance_id" + Attr_CloudInstances = "cloud_instances" + Attr_Code = "code" + Attr_ConnectionMode = "connection_mode" + Attr_Connections = "connections" + Attr_ConsistencyGroupName = "consistency_group_name" + Attr_ConsoleLanguages = "console_languages" + Attr_ContainerFormat = "container_format" + Attr_CopyRate = "copy_rate" + Attr_CopyType = "copy_type" + Attr_CoreMemoryRatio = "core_memory_ratio" + Attr_Cores = "cores" + Attr_CreateTime = "create_time" + Attr_CreationDate = "creation_date" + Attr_CyclePeriodSeconds = "cycle_period_seconds" + Attr_CyclingMode = "cycling_mode" + Attr_DNS = "dns" + Attr_Datacenters = "datacenters" + Attr_Default = "default" + Attr_DeploymentType = "deployment_type" + Attr_Description = "description" + Attr_DisasterRecoveryLocations = "disaster_recovery_locations" + Attr_DiskFormat = "disk_format" + Attr_DiskType = "disk_type" + Attr_Enabled = "enabled" + Attr_Endianness = "endianness" + Attr_ExternalIP = "external_ip" + Attr_FailureMessage = "failure_message" + Attr_FlashCopyMappings = "flash_copy_mappings" + Attr_FlashCopyName = "flash_copy_name" + Attr_FreezeTime = "freeze_time" + Attr_Gateway = "gateway" + Attr_GlobalRouting = "global_routing" + Attr_GreDestinationAddress = "gre_destination_address" + Attr_GreSourceAddress = "gre_source_address" + Attr_GroupID = "group_id" + Attr_HealthStatus = "health_status" + Attr_HostID = "host_id" + Attr_Href = "href" + Attr_Hypervisor = "hypervisor" + Attr_HypervisorType = "hypervisor_type" + Attr_IBMIPAddress = "ibm_ip_address" + Attr_ID = "id" + Attr_IP = "ip" + Attr_IPAddress = "ipaddress" + Attr_IPOctet = "ipoctet" + Attr_ImageID = "image_id" + Attr_ImageInfo = "image_info" + Attr_ImageType = "image_type" + Attr_Images = "images" + Attr_InputVolumes = "input_volumes" + Attr_InstanceSnapshots = "instance_snapshots" + Attr_InstanceVolumes = "instance_volumes" + Attr_Instances = "instances" + Attr_IsActive = "is_active" + Attr_Jumbo = "jumbo" + Attr_Key = "key" + Attr_KeyID = "key_id" + Attr_KeyName = "name" + Attr_Keys = "keys" + Attr_Language = "language" + Attr_LastUpdateDate = "last_update_date" + Attr_LastUpdatedDate = "last_updated_date" + Attr_Leases = "leases" + Attr_LicenseRepositoryCapacity = "license_repository_capacity" + Attr_Location = "location" + Attr_MTU = "mtu" + Attr_MacAddress = "macaddress" + Attr_MasterChangedVolumeName = "master_changed_volume_name" + Attr_MasterVolumeName = "master_volume_name" + Attr_Max = "max" + Attr_MaxAllocationSize = "max_allocation_size" + Attr_MaxAvailable = "max_available" + Attr_MaxCoresAvailable = "max_cores_available" + Attr_MaxMem = "maxmem" + Attr_MaxMemoryAvailable = "max_memory_available" + Attr_MaxProc = "maxproc" + Attr_MaxVirtualCores = "max_virtual_cores" + Attr_MaximumStorageAllocation = "max_storage_allocation" + Attr_Members = "members" + Attr_Memory = "memory" + Attr_Message = "message" + Attr_Metered = "metered" + Attr_Min = "min" + Attr_MinMem = "minmem" + Attr_MinProc = "minproc" + Attr_MinVirtualCores = "min_virtual_cores" + Attr_MirroringState = "mirroring_state" + Attr_Name = "name" + Attr_NetworkID = "network_id" + Attr_NetworkName = "network_name" + Attr_NetworkPorts = "network_ports" + Attr_Networks = "networks" + Attr_NumberOfVolumes = "number_of_volumes" + Attr_Onboardings = "onboardings" + Attr_OperatingSystem = "operating_system" + Attr_PVMInstanceID = "pvm_instance_id" + Attr_PVMInstances = "pvm_instances" + Attr_PVMSnapshots = "pvm_snapshots" + Attr_PercentComplete = "percent_complete" + Attr_PinPolicy = "pin_policy" + Attr_PlacementGroupID = "placement_group_id" + Attr_PlacementGroups = "placement_groups" + Attr_Policy = "policy" + Attr_Pool = "pool" + Attr_PoolName = "pool_name" + Attr_Port = "port" + Attr_PortID = "portid" + Attr_PrimaryRole = "primary_role" + Attr_ProcType = "proctype" + Attr_Processors = "processors" + Attr_ProfileID = "profile_id" + Attr_Profiles = "profiles" + Attr_Progress = "progress" + Attr_PublicIP = "public_ip" + Attr_Region = "region" + Attr_RemoteCopyID = "remote_copy_id" + Attr_RemoteCopyRelationshipNames = "remote_copy_relationship_names" + Attr_RemoteCopyRelationships = "remote_copy_relationships" + Attr_ReplicationEnabled = "replication_enabled" + Attr_ReplicationSites = "replication_sites" + Attr_ReplicationStatus = "replication_status" + Attr_ReplicationType = "replication_type" + Attr_ReservedCores = "reserved_cores" + Attr_ResultsOnboardedVolumes = "results_onboarded_volumes" + Attr_ResultsVolumeOnboardingFailures = "results_volume_onboarding_failures" + Attr_SPPPlacementGroups = "spp_placement_groups" + Attr_SSHKey = "ssh_key" + Attr_Shareable = "shreable" + Attr_SharedCoreRatio = "shared_core_ratio" + Attr_SharedProcessorPool = "shared_processor_pool" + Attr_SharedProcessorPoolID = "shared_processor_pool_id" + Attr_SharedProcessorPoolPlacementGroups = "spp_placement_groups" + Attr_SharedProcessorPoolStatus = "status" + Attr_SharedProcessorPools = "shared_processor_pools" + Attr_SharedProcessorPoolName = "name" + Attr_SharedProcessorPoolHostID = "host_id" + Attr_SharedProcessorPoolReservedCores = "reserved_cores" + Attr_SharedProcessorPoolAvailableCores = "available_cores" + Attr_SharedProcessorPoolAllocatedCores = "allocated_cores" + Attr_SharedProcessorPoolStatusDetail = "status_detail" + Attr_SharedProcessorPoolInstances = "instances" + Attr_SharedProcessorPoolInstanceCpus = "cpus" + Attr_SharedProcessorPoolInstanceUncapped = "uncapped" + Attr_SharedProcessorPoolInstanceAvailabilityZone = "availability_zone" + Attr_SharedProcessorPoolInstanceId = "id" + Attr_SharedProcessorPoolInstanceMemory = "memory" + Attr_SharedProcessorPoolInstanceName = "name" + Attr_SharedProcessorPoolInstanceStatus = "status" + Attr_SharedProcessorPoolInstanceVcpus = "vcpus" + Attr_Size = "size" + Attr_SourceVolumeName = "source_volume_name" + Attr_Speed = "speed" + Attr_StartTime = "start_time" + Attr_State = "state" + Attr_Status = "status" + Attr_StatusDescriptionErrors = "status_description_errors" + Attr_StatusDetail = "status_detail" + Attr_StoragePool = "storage_pool" + Attr_StoragePoolAffinity = "storage_pool_affinity" + Attr_StoragePoolsCapacity = "storage_pools_capacity" + Attr_StorageType = "storage_type" + Attr_StorageTypesCapacity = "storage_types_capacity" + Attr_Synchronized = "synchronized" + Attr_SysType = "systype" + Attr_SystemPoolName = "system_pool_name" + Attr_SystemPools = "system_pools" + Attr_Systems = "systems" + Attr_TargetVolumeName = "target_volume_name" + Attr_TenantID = "tenant_id" + Attr_TenantName = "tenant_name" + Attr_TotalCapacity = "total_capacity" + Attr_TotalInstances = "total_instances" + Attr_TotalMemoryConsumed = "total_memory_consumed" + Attr_TotalProcessorsConsumed = "total_processors_consumed" + Attr_TotalSSDStorageConsumed = "total_ssd_storage_consumed" + Attr_TotalStandardStorageConsumed = "total_standard_storage_consumed" + Attr_Type = "type" + Attr_URL = "url" + Attr_Uncapped = "uncapped" + Attr_UsedIPCount = "used_ip_count" + Attr_UsedIPPercent = "used_ip_percent" + Attr_UserIPAddress = "user_ip_address" + Attr_VCPUs = "vcpus" + Attr_VLanID = "vlan_id" + Attr_VPCCRNs = "vpc_crns" + Attr_VPCEnabled = "vpc_enabled" + Attr_VirtualCoresAssigned = "virtual_cores_assigned" + Attr_VolumeGroupName = "volume_group_name" + Attr_VolumeGroups = "volume_groups" + Attr_VolumeIDs = "volume_ids" + Attr_VolumePool = "volume_pool" + Attr_VolumeSnapshots = "volume_snapshots" + Attr_Volumes = "volumes" + Attr_WWN = "wwn" + Attr_Workspaces = "workspaces" - Attr_KeyID = "key_id" - Attr_Keys = "keys" - Attr_KeyCreationDate = "creation_date" - Attr_Key = "ssh_key" - Attr_KeyName = "name" + // TODO: Second Half Cleanup, remove extra variables // SAP Profile PISAPProfiles = "profiles" @@ -46,10 +281,16 @@ const ( Arg_PVMInstanceId = "pi_instance_id" Arg_PVMInstanceActionType = "pi_action" Arg_PVMInstanceHealthStatus = "pi_health_status" + Arg_IBMiCSS = "pi_ibmi_css" + Arg_IBMiPHA = "pi_ibmi_pha" + Arg_IBMiRDSUsers = "pi_ibmi_rds_users" + Attr_IBMiCSS = "ibmi_css" + Attr_IBMiPHA = "ibmi_pha" + Attr_IBMiRDS = "ibmi_rds" + Attr_IBMiRDSUsers = "ibmi_rds_users" + OS_IBMI = "ibmi" - Attr_Status = "status" - Attr_Progress = "progress" - Attr_HealthStatus = "health_status" + Arg_PIInstanceSharedProcessorPool = "pi_shared_processor_pool" PVMInstanceHealthOk = "OK" PVMInstanceHealthWarning = "WARNING" @@ -58,14 +299,31 @@ const ( warningTimeOut = 60 * time.Second activeTimeOut = 2 * time.Minute // power service instance capabilities - CUSTOM_VIRTUAL_CORES = "custom-virtualcores" - PIInstanceDeploymentType = "pi_deployment_type" - PIInstanceNetwork = "pi_network" - PIInstanceStoragePool = "pi_storage_pool" - PISAPInstanceProfileID = "pi_sap_profile_id" - PISAPInstanceDeploymentType = "pi_sap_deployment_type" - PIInstanceStoragePoolAffinity = "pi_storage_pool_affinity" - Arg_PIInstanceSharedProcessorPool = "pi_shared_processor_pool" + CUSTOM_VIRTUAL_CORES = "custom-virtualcores" + + PIConsoleLanguageCode = "pi_language_code" + PICloudConnectionId = "cloud_connection_id" + PICloudConnectionStatus = "status" + PICloudConnectionIBMIPAddress = "ibm_ip_address" + PICloudConnectionUserIPAddress = "user_ip_address" + PICloudConnectionPort = "port" + PICloudConnectionClassicGreSource = "gre_source_address" + PICloudConnectionConnectionMode = "connection_mode" + PIInstanceDeploymentType = "pi_deployment_type" + PIInstanceMigratable = "pi_migratable" + PIInstanceNetwork = "pi_network" + PIInstanceLicenseRepositoryCapacity = "pi_license_repository_capacity" + PIInstanceStoragePool = "pi_storage_pool" + PIInstanceStorageType = "pi_storage_type" + PISAPInstanceProfileID = "pi_sap_profile_id" + PISAPInstanceDeploymentType = "pi_sap_deployment_type" + PIInstanceSharedProcessorPool = "pi_shared_processor_pool" + PIInstanceStorageConnection = "pi_storage_connection" + PIInstanceStoragePoolAffinity = "pi_storage_pool_affinity" + + PIInstanceUserData = "pi_user_data" + PIInstanceVolumeIds = "pi_volume_ids" + Attr_PIInstanceSharedProcessorPool = "shared_processor_pool" Attr_PIInstanceSharedProcessorPoolID = "shared_processor_pool_id" @@ -109,37 +367,10 @@ const ( // Cloud Connections PICloudConnectionTransitEnabled = "pi_cloud_connection_transit_enabled" - // Shared Processor Pool - Arg_SharedProcessorPoolName = "pi_shared_processor_pool_name" - Arg_SharedProcessorPoolHostGroup = "pi_shared_processor_pool_host_group" - Arg_SharedProcessorPoolPlacementGroupID = "pi_shared_processor_pool_placement_group_id" - Arg_SharedProcessorPoolReservedCores = "pi_shared_processor_pool_reserved_cores" - Arg_SharedProcessorPoolID = "pi_shared_processor_pool_id" - Attr_SharedProcessorPoolID = "shared_processor_pool_id" - Attr_SharedProcessorPoolName = "name" - Attr_SharedProcessorPoolReservedCores = "reserved_cores" - Attr_SharedProcessorPoolAvailableCores = "available_cores" - Attr_SharedProcessorPoolAllocatedCores = "allocated_cores" - Attr_SharedProcessorPoolHostID = "host_id" - Attr_SharedProcessorPoolStatus = "status" - Attr_SharedProcessorPoolStatusDetail = "status_detail" - Attr_SharedProcessorPoolPlacementGroups = "spp_placement_groups" - Attr_SharedProcessorPoolInstances = "instances" - Attr_SharedProcessorPoolInstanceCpus = "cpus" - Attr_SharedProcessorPoolInstanceUncapped = "uncapped" - Attr_SharedProcessorPoolInstanceAvailabilityZone = "availability_zone" - Attr_SharedProcessorPoolInstanceId = "id" - Attr_SharedProcessorPoolInstanceMemory = "memory" - Attr_SharedProcessorPoolInstanceName = "name" - Attr_SharedProcessorPoolInstanceStatus = "status" - Attr_SharedProcessorPoolInstanceVcpus = "vcpus" - // SPP Placement Group - Arg_SPPPlacementGroupName = "pi_spp_placement_group_name" - Arg_SPPPlacementGroupPolicy = "pi_spp_placement_group_policy" + Attr_SPPPlacementGroupID = "spp_placement_group_id" Attr_SPPPlacementGroupMembers = "members" - Arg_SPPPlacementGroupID = "pi_spp_placement_group_id" Attr_SPPPlacementGroupPolicy = "policy" Attr_SPPPlacementGroupName = "name" @@ -180,4 +411,6 @@ const ( PIWorkspaceDatacenter = "pi_datacenter" PIWorkspaceResourceGroup = "pi_resource_group_id" PIWorkspacePlan = "pi_plan" + + PIVirtualOpticalDevice = "pi_virtual_optical_device" ) diff --git a/ibm/service/power/resource_ibm_pi_dhcp.go b/ibm/service/power/resource_ibm_pi_dhcp.go index c4d1d96532..071b3d80ad 100644 --- a/ibm/service/power/resource_ibm_pi_dhcp.go +++ b/ibm/service/power/resource_ibm_pi_dhcp.go @@ -98,11 +98,6 @@ func ResourceIBMPIDhcp() *schema.Resource { }, }, }, - Attr_DhcpNetworkDeprecated: { - Type: schema.TypeString, - Computed: true, - Description: "The ID of the DHCP Server private network (deprecated - replaced by network_id)", - }, Attr_DhcpNetworkID: { Type: schema.TypeString, Computed: true, @@ -210,7 +205,6 @@ func resourceIBMPIDhcpRead(ctx context.Context, d *schema.ResourceData, meta int if dhcpServer.Network != nil { dhcpNetwork := dhcpServer.Network if dhcpNetwork.ID != nil { - d.Set(Attr_DhcpNetworkDeprecated, *dhcpNetwork.ID) d.Set(Attr_DhcpNetworkID, *dhcpNetwork.ID) } if dhcpNetwork.Name != nil { diff --git a/ibm/service/power/resource_ibm_pi_instance.go b/ibm/service/power/resource_ibm_pi_instance.go index 37236ed8ae..5fb5f876fd 100644 --- a/ibm/service/power/resource_ibm_pi_instance.go +++ b/ibm/service/power/resource_ibm_pi_instance.go @@ -56,12 +56,6 @@ func ResourceIBMPIInstance() *schema.Resource { Computed: true, Description: "PI instance status", }, - "pi_migratable": { - Type: schema.TypeBool, - Optional: true, - Computed: true, - Description: "set to true to enable migration of the PI instance", - }, "min_processors": { Type: schema.TypeFloat, Computed: true, @@ -83,20 +77,19 @@ func ResourceIBMPIInstance() *schema.Resource { Description: "Maximum memory size", }, helpers.PIInstanceVolumeIds: { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - DiffSuppressFunc: flex.ApplyOnce, - Description: "List of PI volumes", + Type: schema.TypeSet, + ForceNew: true, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "List of PI volumes", }, - helpers.PIInstanceUserData: { Type: schema.TypeString, + ForceNew: true, Optional: true, Description: "Base64 encoded data to be passed in for invoking a cloud init script", }, - helpers.PIInstanceStorageType: { Type: schema.TypeString, Optional: true, @@ -154,10 +147,10 @@ func ResourceIBMPIInstance() *schema.Resource { Description: "Indicates if all volumes attached to the server must reside in the same storage pool", }, PIInstanceNetwork: { - Type: schema.TypeList, - Required: true, - DiffSuppressFunc: flex.ApplyOnce, - Description: "List of one or more networks to attach to the instance", + Type: schema.TypeList, + ForceNew: true, + Required: true, + Description: "List of one or more networks to attach to the instance", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "ip_address": { @@ -190,13 +183,14 @@ func ResourceIBMPIInstance() *schema.Resource { }, helpers.PIPlacementGroupID: { Type: schema.TypeString, + ForceNew: true, Optional: true, Description: "Placement group ID", }, Arg_PIInstanceSharedProcessorPool: { Type: schema.TypeString, - Optional: true, ForceNew: true, + Optional: true, ConflictsWith: []string{PISAPInstanceProfileID}, Description: "Shared Processor Pool the instance is deployed on", }, @@ -247,10 +241,10 @@ func ResourceIBMPIInstance() *schema.Resource { Description: "Instance processor type", }, helpers.PIInstanceSSHKeyName: { - Type: schema.TypeString, - Optional: true, - DiffSuppressFunc: flex.ApplyOnce, - Description: "SSH key name", + Type: schema.TypeString, + ForceNew: true, + Optional: true, + Description: "SSH key name", }, helpers.PIInstanceMemory: { Type: schema.TypeFloat, @@ -260,9 +254,11 @@ func ResourceIBMPIInstance() *schema.Resource { Description: "Memory size", }, PIInstanceDeploymentType: { - Type: schema.TypeString, - Optional: true, - Description: "Custom Deployment Type Information", + Type: schema.TypeString, + ForceNew: true, + Optional: true, + ValidateFunc: validate.ValidateAllowedStringValues([]string{"EPIC", "VMNoStorage"}), + Description: "Custom Deployment Type Information", }, PISAPInstanceProfileID: { Type: schema.TypeString, @@ -272,23 +268,33 @@ func ResourceIBMPIInstance() *schema.Resource { }, PISAPInstanceDeploymentType: { Type: schema.TypeString, + ForceNew: true, Optional: true, Description: "Custom SAP Deployment Type Information", }, + PIVirtualOpticalDevice: { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.ValidateAllowedStringValues([]string{"attach"}), + Description: "Virtual Machine's Cloud Initialization Virtual Optical Device", + }, helpers.PIInstanceSystemType: { Type: schema.TypeString, + ForceNew: true, Optional: true, Computed: true, Description: "PI Instance system type", }, helpers.PIInstanceReplicants: { Type: schema.TypeInt, + ForceNew: true, Optional: true, Default: 1, Description: "PI Instance replicas count", }, helpers.PIInstanceReplicationPolicy: { Type: schema.TypeString, + ForceNew: true, Optional: true, ValidateFunc: validate.ValidateAllowedStringValues([]string{"affinity", "anti-affinity", "none"}), Default: "none", @@ -296,6 +302,7 @@ func ResourceIBMPIInstance() *schema.Resource { }, helpers.PIInstanceReplicationScheme: { Type: schema.TypeString, + ForceNew: true, Optional: true, ValidateFunc: validate.ValidateAllowedStringValues([]string{"prefix", "suffix"}), Default: "suffix", @@ -313,12 +320,6 @@ func ResourceIBMPIInstance() *schema.Resource { Default: "none", ValidateFunc: validate.ValidateAllowedStringValues([]string{"none", "soft", "hard"}), }, - - // "reboot_for_resource_change": { - // Type: schema.TypeString, - // Optional: true, - // Description: "Flag to be passed for CPU/Memory changes that require a reboot to take effect", - // }, "operating_system": { Type: schema.TypeString, Computed: true, @@ -352,6 +353,28 @@ func ResourceIBMPIInstance() *schema.Resource { Computed: true, Description: "Minimum Virtual Cores Assigned to the PVMInstance", }, + Arg_IBMiCSS: { + Type: schema.TypeBool, + Optional: true, + Description: "IBMi Cloud Storage Solution", + }, + Arg_IBMiPHA: { + Type: schema.TypeBool, + Optional: true, + Description: "IBMi Power High Availability", + }, + Attr_IBMiRDS: { + Type: schema.TypeBool, + Optional: false, + Required: false, + Computed: true, + Description: "IBMi Rational Dev Studio", + }, + Arg_IBMiRDSUsers: { + Type: schema.TypeInt, + Optional: true, + Description: "IBMi Rational Dev Studio Number of User Licenses", + }, }, } } @@ -385,10 +408,18 @@ func resourceIBMPIInstanceCreate(ctx context.Context, d *schema.ResourceData, me d.SetId(fmt.Sprintf("%s/%s", cloudInstanceID, *(*pvmList)[0].PvmInstanceID)) for _, s := range *pvmList { - _, err = isWaitForPIInstanceAvailable(ctx, client, *s.PvmInstanceID, instanceReadyStatus) - if err != nil { - return diag.FromErr(err) + if dt, ok := d.GetOk(PIInstanceDeploymentType); ok && dt.(string) == "VMNoStorage" { + _, err = isWaitForPIInstanceShutoff(ctx, client, *s.PvmInstanceID, instanceReadyStatus) + if err != nil { + return diag.FromErr(err) + } + } else { + _, err = isWaitForPIInstanceAvailable(ctx, client, *s.PvmInstanceID, instanceReadyStatus) + if err != nil { + return diag.FromErr(err) + } } + } // If Storage Pool Affinity is given as false we need to update the vm instance. @@ -407,6 +438,20 @@ func resourceIBMPIInstanceCreate(ctx context.Context, d *schema.ResourceData, me } } } + // If virtual optical device provided then update cloud initialization + if vod, ok := d.GetOk(PIVirtualOpticalDevice); ok { + for _, s := range *pvmList { + body := &models.PVMInstanceUpdate{ + CloudInitialization: &models.CloudInitialization{ + VirtualOpticalDevice: vod.(string), + }, + } + _, err = client.Update(*s.PvmInstanceID, body) + if err != nil { + return diag.FromErr(err) + } + } + } return resourceIBMPIInstanceRead(ctx, d, meta) @@ -435,12 +480,9 @@ func resourceIBMPIInstanceRead(ctx context.Context, d *schema.ResourceData, meta d.Set("status", powervmdata.Status) } d.Set(helpers.PIInstanceProcType, powervmdata.ProcType) - if powervmdata.Migratable != nil { - d.Set("pi_migratable", powervmdata.Migratable) - } d.Set("min_processors", powervmdata.Minproc) d.Set(helpers.PIInstanceProgress, powervmdata.Progress) - if powervmdata.StorageType != nil { + if powervmdata.StorageType != nil && *powervmdata.StorageType != "" { d.Set(helpers.PIInstanceStorageType, powervmdata.StorageType) } d.Set(PIInstanceStoragePool, powervmdata.StoragePool) @@ -482,9 +524,7 @@ func resourceIBMPIInstanceRead(ctx context.Context, d *schema.ResourceData, meta d.Set("max_memory", powervmdata.Maxmem) d.Set("pin_policy", powervmdata.PinPolicy) d.Set("operating_system", powervmdata.OperatingSystem) - if powervmdata.OsType != nil { - d.Set("os_type", powervmdata.OsType) - } + d.Set("os_type", powervmdata.OsType) if powervmdata.Health != nil { d.Set("health_status", powervmdata.Health.Status) @@ -496,6 +536,16 @@ func resourceIBMPIInstanceRead(ctx context.Context, d *schema.ResourceData, meta } d.Set(helpers.PIInstanceLicenseRepositoryCapacity, powervmdata.LicenseRepositoryCapacity) d.Set(PIInstanceDeploymentType, powervmdata.DeploymentType) + if powervmdata.SoftwareLicenses != nil { + d.Set(Arg_IBMiCSS, powervmdata.SoftwareLicenses.IbmiCSS) + d.Set(Arg_IBMiPHA, powervmdata.SoftwareLicenses.IbmiPHA) + d.Set(Attr_IBMiRDS, powervmdata.SoftwareLicenses.IbmiRDS) + if *powervmdata.SoftwareLicenses.IbmiRDS { + d.Set(Arg_IBMiRDSUsers, powervmdata.SoftwareLicenses.IbmiRDSUsers) + } else { + d.Set(Arg_IBMiRDSUsers, 0) + } + } return nil } @@ -531,13 +581,17 @@ func resourceIBMPIInstanceUpdate(ctx context.Context, d *schema.ResourceData, me } cores_enabled := checkCloudInstanceCapability(cloudInstance, CUSTOM_VIRTUAL_CORES) - if d.HasChange(helpers.PIInstanceName) { - body := &models.PVMInstanceUpdate{ - ServerName: name, + if d.HasChanges(helpers.PIInstanceName, PIVirtualOpticalDevice) { + body := &models.PVMInstanceUpdate{} + if d.HasChange(helpers.PIInstanceName) { + body.ServerName = name + } + if d.HasChange(PIVirtualOpticalDevice) { + body.CloudInitialization.VirtualOpticalDevice = d.Get(PIVirtualOpticalDevice).(string) } _, err = client.Update(instanceID, body) if err != nil { - return diag.Errorf("failed to update the lpar with the change for name: %v", err) + return diag.Errorf("failed to update the lpar: %v", err) } _, err = isWaitForPIInstanceAvailable(ctx, client, instanceID, "OK") if err != nil { @@ -546,7 +600,6 @@ func resourceIBMPIInstanceUpdate(ctx context.Context, d *schema.ResourceData, me } if d.HasChange(helpers.PIInstanceProcType) { - // Stop the lpar if d.Get("status") == "SHUTOFF" { log.Printf("the lpar is in the shutoff state. Nothing to do . Moving on ") @@ -598,7 +651,7 @@ func resourceIBMPIInstanceUpdate(ctx context.Context, d *schema.ResourceData, me } // Start of the change for Memory and Processors - if d.HasChange(helpers.PIInstanceMemory) || d.HasChange(helpers.PIInstanceProcessors) || d.HasChange("pi_migratable") { + if d.HasChange(helpers.PIInstanceMemory) || d.HasChange(helpers.PIInstanceProcessors) { maxMemLpar := d.Get("max_memory").(float64) maxCPULpar := d.Get("max_processors").(float64) @@ -627,10 +680,6 @@ func resourceIBMPIInstanceUpdate(ctx context.Context, d *schema.ResourceData, me Memory: mem, Processors: procs, } - if m, ok := d.GetOk("pi_migratable"); ok { - migratable := m.(bool) - body.Migratable = &migratable - } if cores_enabled { log.Printf("support for %s is enabled", CUSTOM_VIRTUAL_CORES) body.VirtualCores = &models.VirtualCores{Assigned: &assignedVirtualCores} @@ -659,7 +708,6 @@ func resourceIBMPIInstanceUpdate(ctx context.Context, d *schema.ResourceData, me // License repository capacity will be updated only if service instance is a vtl instance // might need to check if lrc was set if d.HasChange(helpers.PIInstanceLicenseRepositoryCapacity) { - lrc := d.Get(helpers.PIInstanceLicenseRepositoryCapacity).(int64) body := &models.PVMInstanceUpdate{ LicenseRepositoryCapacity: lrc, @@ -720,7 +768,6 @@ func resourceIBMPIInstanceUpdate(ctx context.Context, d *schema.ResourceData, me } if d.HasChange(helpers.PIPlacementGroupID) { - pgClient := st.NewIBMPIPlacementGroupClient(ctx, sess, cloudInstanceID) oldRaw, newRaw := d.GetChange(helpers.PIPlacementGroupID) @@ -754,9 +801,37 @@ func resourceIBMPIInstanceUpdate(ctx context.Context, d *schema.ResourceData, me } } } + if d.HasChanges(Arg_IBMiCSS, Arg_IBMiPHA, Arg_IBMiRDSUsers) { + if d.Get("status") == "ACTIVE" { + log.Printf("the lpar is in the Active state, continuing with update") + } else { + _, err = isWaitForPIInstanceAvailable(ctx, client, instanceID, "OK") + if err != nil { + return diag.FromErr(err) + } + } - return resourceIBMPIInstanceRead(ctx, d, meta) + sl := &models.SoftwareLicenses{} + sl.IbmiCSS = flex.PtrToBool(d.Get(Arg_IBMiCSS).(bool)) + sl.IbmiPHA = flex.PtrToBool(d.Get(Arg_IBMiPHA).(bool)) + ibmrdsUsers := d.Get(Arg_IBMiRDSUsers).(int) + if ibmrdsUsers < 0 { + return diag.Errorf("request with IBMi Rational Dev Studio property requires IBMi Rational Dev Studio number of users") + } + sl.IbmiRDS = flex.PtrToBool(ibmrdsUsers > 0) + sl.IbmiRDSUsers = int64(ibmrdsUsers) + updatebody := &models.PVMInstanceUpdate{SoftwareLicenses: sl} + _, err = client.Update(instanceID, updatebody) + if err != nil { + return diag.FromErr(err) + } + _, err = isWaitForPIInstanceSoftwareLicenses(ctx, client, instanceID, sl) + if err != nil { + return diag.FromErr(err) + } + } + return resourceIBMPIInstanceRead(ctx, d, meta) } func resourceIBMPIInstanceDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { @@ -822,7 +897,7 @@ func isWaitForPIInstanceAvailable(ctx context.Context, client *st.IBMPIInstanceC stateConf := &resource.StateChangeConf{ Pending: []string{"PENDING", helpers.PIInstanceBuilding, helpers.PIInstanceHealthWarning}, - Target: []string{helpers.PIInstanceAvailable, helpers.PIInstanceHealthOk, "ERROR", ""}, + Target: []string{helpers.PIInstanceAvailable, helpers.PIInstanceHealthOk, "ERROR", "", "SHUTOFF"}, Refresh: isPIInstanceRefreshFunc(client, id, instanceReadyStatus), Delay: 30 * time.Second, MinTimeout: queryTimeOut, @@ -856,6 +931,101 @@ func isPIInstanceRefreshFunc(client *st.IBMPIInstanceClient, id, instanceReadySt } } +func isWaitForPIInstanceSoftwareLicenses(ctx context.Context, client *st.IBMPIInstanceClient, id string, softwareLicenses *models.SoftwareLicenses) (interface{}, error) { + log.Printf("Waiting for PIInstance Software Licenses (%s) to be updated ", id) + + queryTimeOut := activeTimeOut + + stateConf := &resource.StateChangeConf{ + Pending: []string{"notdone"}, + Target: []string{"done"}, + Refresh: isPIInstanceSoftwareLicensesRefreshFunc(client, id, softwareLicenses), + Delay: 90 * time.Second, + MinTimeout: queryTimeOut, + Timeout: 120 * time.Minute, + } + + return stateConf.WaitForStateContext(ctx) +} + +func isPIInstanceSoftwareLicensesRefreshFunc(client *st.IBMPIInstanceClient, id string, softwareLicenses *models.SoftwareLicenses) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + + pvm, err := client.Get(id) + if err != nil { + return nil, "", err + } + + // Check that each software license we modified has been updated + if softwareLicenses.IbmiCSS != nil { + if *softwareLicenses.IbmiCSS != *pvm.SoftwareLicenses.IbmiCSS { + return pvm, "notdone", nil + } + } + + if softwareLicenses.IbmiPHA != nil { + if *softwareLicenses.IbmiPHA != *pvm.SoftwareLicenses.IbmiPHA { + return pvm, "notdone", nil + } + } + + if softwareLicenses.IbmiRDS != nil { + // If the update set IBMiRDS to false, don't check IBMiRDSUsers as it will be updated on the terraform side on the read + if !*softwareLicenses.IbmiRDS { + if *softwareLicenses.IbmiRDS != *pvm.SoftwareLicenses.IbmiRDS { + return pvm, "notdone", nil + } + } else if (*softwareLicenses.IbmiRDS != *pvm.SoftwareLicenses.IbmiRDS) || (softwareLicenses.IbmiRDSUsers != pvm.SoftwareLicenses.IbmiRDSUsers) { + return pvm, "notdone", nil + } + } + + return pvm, "done", nil + } +} + +func isWaitForPIInstanceShutoff(ctx context.Context, client *st.IBMPIInstanceClient, id string, instanceReadyStatus string) (interface{}, error) { + log.Printf("Waiting for PIInstance (%s) to be shutoff and health active ", id) + + queryTimeOut := activeTimeOut + if instanceReadyStatus == helpers.PIInstanceHealthWarning { + queryTimeOut = warningTimeOut + } + + stateConf := &resource.StateChangeConf{ + Pending: []string{StatusPending, helpers.PIInstanceBuilding, helpers.PIInstanceHealthWarning}, + Target: []string{helpers.PIInstanceHealthOk, StatusError, "", StatusShutoff}, + Refresh: isPIInstanceShutoffRefreshFunc(client, id, instanceReadyStatus), + Delay: 30 * time.Second, + MinTimeout: queryTimeOut, + Timeout: 120 * time.Minute, + } + + return stateConf.WaitForStateContext(ctx) +} +func isPIInstanceShutoffRefreshFunc(client *st.IBMPIInstanceClient, id, instanceReadyStatus string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + + pvm, err := client.Get(id) + if err != nil { + return nil, "", err + } + if *pvm.Status == StatusShutoff && (pvm.Health.Status == instanceReadyStatus || pvm.Health.Status == helpers.PIInstanceHealthOk) { + return pvm, StatusShutoff, nil + } + if *pvm.Status == StatusError { + if pvm.Fault != nil { + err = fmt.Errorf("failed to create the lpar: %s", pvm.Fault.Message) + } else { + err = fmt.Errorf("failed to create the lpar") + } + return pvm, *pvm.Status, err + } + + return pvm, helpers.PIInstanceBuilding, nil + } +} + // This function takes the input string and encodes into base64 if isn't already encoded func encodeBase64(userData string) string { _, err := base64.StdEncoding.DecodeString(userData) @@ -1184,11 +1354,6 @@ func createPVMInstance(d *schema.ResourceData, client *st.IBMPIInstanceClient, i if r, ok := d.GetOk(helpers.PIInstanceReplicationScheme); ok { replicationNamingScheme = r.(string) } - var migratable bool - if m, ok := d.GetOk("pi_migratable"); ok { - migratable = m.(bool) - } - var pinpolicy string if p, ok := d.GetOk(helpers.PIInstancePinPolicy); ok { pinpolicy = p.(string) @@ -1202,9 +1367,7 @@ func createPVMInstance(d *schema.ResourceData, client *st.IBMPIInstanceClient, i userData = u.(string) } - //publicinterface := d.Get(helpers.PIInstancePublicNetwork).(bool) body := &models.PVMInstanceCreate{ - //NetworkIds: networks, Processors: &procs, Memory: &mem, ServerName: flex.PtrToString(name), @@ -1216,7 +1379,6 @@ func createPVMInstance(d *schema.ResourceData, client *st.IBMPIInstanceClient, i ReplicantNamingScheme: flex.PtrToString(replicationNamingScheme), ReplicantAffinityPolicy: flex.PtrToString(replicationpolicy), Networks: pvmNetworks, - Migratable: &migratable, } if s, ok := d.GetOk(helpers.PIInstanceSSHKeyName); ok { sshkey := s.(string) @@ -1285,18 +1447,15 @@ func createPVMInstance(d *schema.ResourceData, client *st.IBMPIInstanceClient, i if spp, ok := d.GetOk(Arg_PIInstanceSharedProcessorPool); ok { body.SharedProcessorPool = spp.(string) } - - if lrc, ok := d.GetOk(helpers.PIInstanceLicenseRepositoryCapacity); ok { - // check if using vtl image - // check if vtl image is stock image - imageData, err := imageClient.GetStockImage(imageid) + imageData, err := imageClient.GetStockImage(imageid) + if err != nil { + // check if vtl image is cloud instance image + imageData, err = imageClient.Get(imageid) if err != nil { - // check if vtl image is cloud instance image - imageData, err = imageClient.Get(imageid) - if err != nil { - return nil, fmt.Errorf("image doesn't exist. %e", err) - } + return nil, fmt.Errorf("image doesn't exist. %e", err) } + } + if lrc, ok := d.GetOk(helpers.PIInstanceLicenseRepositoryCapacity); ok { if imageData.Specifications.ImageType == "stock-vtl" { body.LicenseRepositoryCapacity = int64(lrc.(int)) @@ -1305,6 +1464,31 @@ func createPVMInstance(d *schema.ResourceData, client *st.IBMPIInstanceClient, i } } + if imageData.Specifications.OperatingSystem == OS_IBMI { + // Default value + falseBool := false + sl := &models.SoftwareLicenses{ + IbmiCSS: &falseBool, + IbmiPHA: &falseBool, + IbmiRDS: &falseBool, + IbmiRDSUsers: 0, + } + if ibmiCSS, ok := d.GetOk(Arg_IBMiCSS); ok { + sl.IbmiCSS = flex.PtrToBool(ibmiCSS.(bool)) + } + if ibmiPHA, ok := d.GetOk(Arg_IBMiPHA); ok { + sl.IbmiPHA = flex.PtrToBool(ibmiPHA.(bool)) + } + if ibmrdsUsers, ok := d.GetOk(Arg_IBMiRDSUsers); ok { + if ibmrdsUsers.(int) < 0 { + return nil, fmt.Errorf("request with IBMi Rational Dev Studio property requires IBMi Rational Dev Studio number of users") + } + sl.IbmiRDS = flex.PtrToBool(ibmrdsUsers.(int) > 0) + sl.IbmiRDSUsers = int64(ibmrdsUsers.(int)) + } + body.SoftwareLicenses = sl + } + pvmList, err := client.Create(body) if err != nil { diff --git a/ibm/service/power/resource_ibm_pi_instance_console_language.go b/ibm/service/power/resource_ibm_pi_instance_console_language.go index a825760d04..4f065a0a36 100644 --- a/ibm/service/power/resource_ibm_pi_instance_console_language.go +++ b/ibm/service/power/resource_ibm_pi_instance_console_language.go @@ -18,10 +18,6 @@ import ( "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" ) -const ( - PIConsoleLanguageCode = "pi_language_code" -) - func ResourceIBMPIInstanceConsoleLanguage() *schema.Resource { return &schema.Resource{ CreateContext: resourceIBMPIInstanceConsoleLanguageCreate, @@ -93,7 +89,7 @@ func resourceIBMPIInstanceConsoleLanguageUpdate(ctx context.Context, d *schema.R return diag.FromErr(err) } - if d.HasChange(ConsoleLanguageCode) { + if d.HasChange(PIConsoleLanguageCode) { cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) instanceName := d.Get(helpers.PIInstanceName).(string) code := d.Get(PIConsoleLanguageCode).(string) diff --git a/ibm/service/power/resource_ibm_pi_instance_test.go b/ibm/service/power/resource_ibm_pi_instance_test.go index d28e294322..4711fd423b 100644 --- a/ibm/service/power/resource_ibm_pi_instance_test.go +++ b/ibm/service/power/resource_ibm_pi_instance_test.go @@ -64,48 +64,7 @@ func testAccCheckIBMPIInstanceConfig(name, instanceHealthStatus string) string { `, acc.Pi_cloud_instance_id, name, acc.Pi_image, acc.Pi_network_name, instanceHealthStatus, acc.PiStorageType) } -func testAccCheckIBMPIInstanceUserDataConfig(name, instanceHealthStatus string) string { - return fmt.Sprintf(` - resource "ibm_pi_key" "key" { - pi_cloud_instance_id = "%[1]s" - pi_key_name = "%[2]s" - pi_ssh_key = "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEArb2aK0mekAdbYdY9rwcmeNSxqVCwez3WZTYEq+1Nwju0x5/vQFPSD2Kp9LpKBbxx3OVLN4VffgGUJznz9DAr7veLkWaf3iwEil6U4rdrhBo32TuDtoBwiczkZ9gn1uJzfIaCJAJdnO80Kv9k0smbQFq5CSb9H+F5VGyFue/iVd5/b30MLYFAz6Jg1GGWgw8yzA4Gq+nO7HtyuA2FnvXdNA3yK/NmrTiPCdJAtEPZkGu9LcelkQ8y90ArlKfjtfzGzYDE4WhOufFxyWxciUePh425J2eZvElnXSdGha+FCfYjQcvqpCVoBAG70U4fJBGjB+HL/GpCXLyiYXPrSnzC9w==" - } - data "ibm_pi_image" "power_image" { - pi_image_name = "%[3]s" - pi_cloud_instance_id = "%[1]s" - } - data "ibm_pi_network" "power_networks" { - pi_cloud_instance_id = "%[1]s" - pi_network_name = "%[4]s" - } - resource "ibm_pi_volume" "power_volume" { - pi_volume_size = 20 - pi_volume_name = "%[2]s" - pi_volume_shareable = true - pi_volume_pool = data.ibm_pi_image.power_image.storage_pool - pi_cloud_instance_id = "%[1]s" - } - resource "ibm_pi_instance" "power_instance" { - pi_memory = "2" - pi_processors = "0.25" - pi_instance_name = "%[2]s" - pi_proc_type = "shared" - pi_image_id = data.ibm_pi_image.power_image.id - pi_sys_type = "s922" - pi_cloud_instance_id = "%[1]s" - pi_storage_pool = data.ibm_pi_image.power_image.storage_pool - pi_health_status = "%[5]s" - pi_volume_ids = [ibm_pi_volume.power_volume.volume_id] - pi_network { - network_id = data.ibm_pi_network.power_networks.id - } - pi_user_data = "this is test user data" - } - `, acc.Pi_cloud_instance_id, name, acc.Pi_image, acc.Pi_network_name, instanceHealthStatus) -} - -func testAccCheckIBMPIInstanceDeploymentTypeConfig(name, instanceHealthStatus string) string { +func testAccCheckIBMPIInstanceDeploymentTypeConfig(name, instanceHealthStatus, epic, systype string) string { return fmt.Sprintf(` resource "ibm_pi_key" "key" { pi_cloud_instance_id = "%[1]s" @@ -127,16 +86,51 @@ func testAccCheckIBMPIInstanceDeploymentTypeConfig(name, instanceHealthStatus st pi_proc_type = "dedicated" pi_image_id = data.ibm_pi_image.power_image.id pi_key_pair_name = ibm_pi_key.key.key_id - pi_sys_type = "e980" + pi_sys_type = "%[7]s" pi_cloud_instance_id = "%[1]s" - pi_storage_type = "tier1" + pi_storage_type = "%[8]s" pi_health_status = "%[5]s" pi_network { network_id = data.ibm_pi_network.power_networks.id } - pi_deployment_type = "EPIC" + pi_deployment_type = "%[6]s" } - `, acc.Pi_cloud_instance_id, name, acc.Pi_image, acc.Pi_network_name, instanceHealthStatus) + `, acc.Pi_cloud_instance_id, name, acc.Pi_image, acc.Pi_network_name, instanceHealthStatus, epic, systype, acc.PiStorageType) +} + +func testAccCheckIBMPIInstanceIBMiLicense(name, instanceHealthStatus string, IBMiCSS bool, IBMiRDSUsers int) string { + return fmt.Sprintf(` + data "ibm_pi_image" "power_image" { + pi_cloud_instance_id = "%[1]s" + pi_image_name = "%[3]s" + } + data "ibm_pi_network" "power_networks" { + pi_cloud_instance_id = "%[1]s" + pi_network_name = "%[4]s" + } + resource "ibm_pi_volume" "power_volume" { + pi_cloud_instance_id = "%[1]s" + pi_volume_size = 1 + pi_volume_name = "%[2]s" + pi_volume_type = "tier3" + } + resource "ibm_pi_instance" "power_instance" { + pi_memory = "2" + pi_processors = "0.25" + pi_instance_name = "%[2]s" + pi_proc_type = "shared" + pi_image_id = data.ibm_pi_image.power_image.id + pi_sys_type = "s922" + pi_cloud_instance_id = "%[1]s" + pi_storage_pool = data.ibm_pi_image.power_image.storage_pool + pi_health_status = "%[5]s" + pi_volume_ids = [ibm_pi_volume.power_volume.volume_id] + pi_network { + network_id = data.ibm_pi_network.power_networks.id + } + pi_ibmi_css = %[6]t + pi_ibmi_rds_users = %[7]d + }`, acc.Pi_cloud_instance_id, name, acc.Pi_image, acc.Pi_network_name, instanceHealthStatus, IBMiCSS, IBMiRDSUsers) } func testAccIBMPIInstanceNetworkConfig(name, privateNetIP string) string { @@ -281,7 +275,7 @@ func TestAccIBMPIInstanceBasic(t *testing.T) { }) } -func TestAccIBMPIInstanceUserData(t *testing.T) { +func TestAccIBMPIInstanceDeploymentType(t *testing.T) { instanceRes := "ibm_pi_instance.power_instance" name := fmt.Sprintf("tf-pi-instance-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ @@ -290,7 +284,7 @@ func TestAccIBMPIInstanceUserData(t *testing.T) { CheckDestroy: testAccCheckIBMPIInstanceDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIBMPIInstanceUserDataConfig(name, helpers.PIInstanceHealthWarning), + Config: testAccCheckIBMPIInstanceDeploymentTypeConfig(name, helpers.PIInstanceHealthOk, "EPIC", "e980"), Check: resource.ComposeTestCheckFunc( testAccCheckIBMPIInstanceExists(instanceRes), resource.TestCheckResourceAttr(instanceRes, "pi_instance_name", name), @@ -300,7 +294,7 @@ func TestAccIBMPIInstanceUserData(t *testing.T) { }) } -func TestAccIBMPIInstanceDeploymentType(t *testing.T) { +func TestAccIBMPIInstanceIBMiLicense(t *testing.T) { instanceRes := "ibm_pi_instance.power_instance" name := fmt.Sprintf("tf-pi-instance-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ @@ -309,10 +303,25 @@ func TestAccIBMPIInstanceDeploymentType(t *testing.T) { CheckDestroy: testAccCheckIBMPIInstanceDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIBMPIInstanceDeploymentTypeConfig(name, helpers.PIInstanceHealthWarning), + Config: testAccCheckIBMPIInstanceIBMiLicense(name, helpers.PIInstanceHealthOk, true, 2), Check: resource.ComposeTestCheckFunc( testAccCheckIBMPIInstanceExists(instanceRes), resource.TestCheckResourceAttr(instanceRes, "pi_instance_name", name), + resource.TestCheckResourceAttr(instanceRes, "status", "ACTIVE"), + resource.TestCheckResourceAttr(instanceRes, "pi_ibmi_css", "true"), + resource.TestCheckResourceAttr(instanceRes, "pi_ibmi_rds", "true"), + resource.TestCheckResourceAttr(instanceRes, "pi_ibmi_rds_users", "2"), + ), + }, + { + Config: testAccCheckIBMPIInstanceIBMiLicense(name, helpers.PIInstanceHealthOk, false, 0), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIInstanceExists(instanceRes), + testAccCheckIBMPIInstanceStatus(instanceRes, "ACTIVE"), + resource.TestCheckResourceAttr(instanceRes, "pi_instance_name", name), + resource.TestCheckResourceAttr(instanceRes, "pi_ibmi_css", "false"), + resource.TestCheckResourceAttr(instanceRes, "pi_ibmi_rds", "false"), + resource.TestCheckResourceAttr(instanceRes, "pi_ibmi_rds_users", "0"), ), }, }, @@ -646,3 +655,22 @@ func testAccCheckIBMPIInstanceStatus(n, status string) resource.TestCheckFunc { return nil } } + +func TestAccIBMPIInstanceDeploymentTypeNoStorage(t *testing.T) { + instanceRes := "ibm_pi_instance.power_instance" + name := fmt.Sprintf("tf-pi-instance-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPIInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIInstanceDeploymentTypeConfig(name, helpers.PIInstanceHealthOk, "VMNoStorage", "s922"), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIInstanceExists(instanceRes), + resource.TestCheckResourceAttr(instanceRes, "pi_instance_name", name), + ), + }, + }, + }) +} diff --git a/ibm/service/power/resource_ibm_pi_key.go b/ibm/service/power/resource_ibm_pi_key.go index 3f305e4da2..0b691bb0f6 100644 --- a/ibm/service/power/resource_ibm_pi_key.go +++ b/ibm/service/power/resource_ibm_pi_key.go @@ -50,16 +50,11 @@ func ResourceIBMPIKey() *schema.Resource { }, // Attributes - Attr_KeyCreationDate: { + Attr_CreationDate: { Type: schema.TypeString, Computed: true, Description: "Date of SSH Key creation", }, - Attr_KeyID: { - Type: schema.TypeString, - Computed: true, - Deprecated: "User defined name for the SSH key (deprecated - replaced by name)", - }, Attr_KeyName: { Type: schema.TypeString, Computed: true, @@ -127,9 +122,8 @@ func resourceIBMPIKeyRead(ctx context.Context, d *schema.ResourceData, meta inte // set attributes d.Set(Attr_KeyName, sshkeydata.Name) - d.Set(Attr_KeyID, sshkeydata.Name) d.Set(Attr_Key, sshkeydata.SSHKey) - d.Set(Attr_KeyCreationDate, sshkeydata.CreationDate.String()) + d.Set(Attr_CreationDate, sshkeydata.CreationDate.String()) return nil } diff --git a/ibm/service/power/resource_ibm_pi_network.go b/ibm/service/power/resource_ibm_pi_network.go index d6ad8826c6..51006a68a3 100644 --- a/ibm/service/power/resource_ibm_pi_network.go +++ b/ibm/service/power/resource_ibm_pi_network.go @@ -78,7 +78,7 @@ func ResourceIBMPINetwork() *schema.Resource { Type: schema.TypeBool, Optional: true, Computed: true, - Deprecated: "deprecated use pi_network_mtu instead", + Deprecated: "This field is deprecated, use pi_network_mtu instead.", ConflictsWith: []string{helpers.PINetworkMtu}, Description: "PI network enable MTU Jumbo option", }, diff --git a/ibm/service/power/resource_ibm_pi_network_port.go b/ibm/service/power/resource_ibm_pi_network_port.go deleted file mode 100644 index 6b1ffb0cf7..0000000000 --- a/ibm/service/power/resource_ibm_pi_network_port.go +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package power - -import ( - "context" - "fmt" - "log" - "time" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - st "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/IBM-Cloud/power-go-client/helpers" - "github.com/IBM-Cloud/power-go-client/power/models" - "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" - "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" -) - -func ResourceIBMPINetworkPort() *schema.Resource { - return &schema.Resource{ - CreateContext: resourceIBMPINetworkPortCreate, - ReadContext: resourceIBMPINetworkPortRead, - UpdateContext: resourceIBMPINetworkPortUpdate, - DeleteContext: resourceIBMPINetworkPortDelete, - Importer: &schema.ResourceImporter{}, - - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(60 * time.Minute), - Delete: schema.DefaultTimeout(60 * time.Minute), - }, - - Schema: map[string]*schema.Schema{ - helpers.PINetworkName: { - Type: schema.TypeString, - Required: true, - }, - helpers.PICloudInstanceId: { - Type: schema.TypeString, - Required: true, - }, - helpers.PINetworkPortDescription: { - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - helpers.PINetworkPortIPAddress: { - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - - //Computed Attributes - "macaddress": { - Type: schema.TypeString, - Computed: true, - }, - "portid": { - Type: schema.TypeString, - Computed: true, - }, - "status": { - Type: schema.TypeString, - Computed: true, - }, - "public_ip": { - Type: schema.TypeString, - Computed: true, - }, - }, - DeprecationMessage: "Resource ibm_pi_network_port is deprecated. Use ibm_pi_network_port_attach to create & attach a network port to a pvm instance", - } -} - -func resourceIBMPINetworkPortCreate(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(helpers.PICloudInstanceId).(string) - networkname := d.Get(helpers.PINetworkName).(string) - description := d.Get(helpers.PINetworkPortDescription).(string) - - ipaddress := d.Get(helpers.PINetworkPortIPAddress).(string) - - nwportBody := &models.NetworkPortCreate{Description: description} - - if ipaddress != "" { - log.Printf("IP address provided. ") - nwportBody.IPAddress = ipaddress - } - - client := st.NewIBMPINetworkClient(ctx, sess, cloudInstanceID) - - networkPortResponse, err := client.CreatePort(networkname, nwportBody) - if err != nil { - return diag.FromErr(err) - } - - log.Printf("Printing the networkresponse %+v", &networkPortResponse) - - IBMPINetworkPortID := *networkPortResponse.PortID - - d.SetId(fmt.Sprintf("%s/%s/%s", cloudInstanceID, networkname, IBMPINetworkPortID)) - - _, err = isWaitForIBMPINetworkPortAvailable(ctx, client, IBMPINetworkPortID, networkname, d.Timeout(schema.TimeoutCreate)) - if err != nil { - return diag.FromErr(err) - } - - return resourceIBMPINetworkPortRead(ctx, d, meta) -} - -func resourceIBMPINetworkPortRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - sess, err := meta.(conns.ClientSession).IBMPISession() - if err != nil { - return diag.FromErr(err) - } - - parts, err := flex.IdParts(d.Id()) - if err != nil { - return diag.FromErr(err) - } - cloudInstanceID := parts[0] - networkname := parts[1] - portID := parts[2] - - networkC := st.NewIBMPINetworkClient(ctx, sess, cloudInstanceID) - networkdata, err := networkC.GetPort(networkname, portID) - if err != nil { - return diag.FromErr(err) - } - - d.Set(helpers.PINetworkPortIPAddress, networkdata.IPAddress) - d.Set(helpers.PINetworkPortDescription, networkdata.Description) - d.Set("macaddress", networkdata.MacAddress) - d.Set("status", networkdata.Status) - d.Set("portid", networkdata.PortID) - d.Set("public_ip", networkdata.ExternalIP) - - return nil -} - -func resourceIBMPINetworkPortUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - return nil -} - -func resourceIBMPINetworkPortDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - - log.Printf("Calling the network delete functions. ") - sess, err := meta.(conns.ClientSession).IBMPISession() - if err != nil { - return diag.FromErr(err) - } - - parts, err := flex.IdParts(d.Id()) - if err != nil { - return diag.FromErr(err) - } - cloudInstanceID := parts[0] - networkname := parts[1] - portID := parts[2] - - client := st.NewIBMPINetworkClient(ctx, sess, cloudInstanceID) - - log.Printf("Calling the delete with the following params delete with cloud instance (%s) and networkid (%s) and portid (%s) ", cloudInstanceID, networkname, portID) - err = client.DeletePort(networkname, portID) - if err != nil { - return diag.FromErr(err) - } - - d.SetId("") - return nil -} - -func isWaitForIBMPINetworkPortAvailable(ctx context.Context, client *st.IBMPINetworkClient, id string, networkname string, timeout time.Duration) (interface{}, error) { - log.Printf("Waiting for Power Network (%s) that was created for Network Zone (%s) to be available.", id, networkname) - - stateConf := &resource.StateChangeConf{ - Pending: []string{"retry", helpers.PINetworkProvisioning}, - Target: []string{"DOWN"}, - Refresh: isIBMPINetworkPortRefreshFunc(client, id, networkname), - Timeout: timeout, - Delay: 10 * time.Second, - MinTimeout: 10 * time.Minute, - } - - return stateConf.WaitForStateContext(ctx) -} - -func isIBMPINetworkPortRefreshFunc(client *st.IBMPINetworkClient, id, networkname string) resource.StateRefreshFunc { - - log.Printf("Calling the IsIBMPINetwork Refresh Function....with the following id (%s) for network port and following id (%s) for network name and waiting for network to be READY", id, networkname) - return func() (interface{}, string, error) { - network, err := client.GetPort(networkname, id) - if err != nil { - return nil, "", err - } - - if network.PortID != nil { - //if network.State == "available" { - log.Printf(" The port has been created with the following ip address and attached to an instance ") - return network, "DOWN", nil - } - - return network, helpers.PINetworkProvisioning, nil - } -} diff --git a/ibm/service/power/resource_ibm_pi_network_port_attach.go b/ibm/service/power/resource_ibm_pi_network_port_attach.go index b6dd305763..e0e342e15a 100644 --- a/ibm/service/power/resource_ibm_pi_network_port_attach.go +++ b/ibm/service/power/resource_ibm_pi_network_port_attach.go @@ -69,11 +69,6 @@ func ResourceIBMPINetworkPortAttach() *schema.Resource { Type: schema.TypeString, Computed: true, }, - "port_id": { - Type: schema.TypeString, - Computed: true, - Deprecated: "port_id attribute is deprecated, use network_port_id instead.", - }, "network_port_id": { Type: schema.TypeString, Computed: true, @@ -169,7 +164,6 @@ func resourceIBMPINetworkPortAttachRead(ctx context.Context, d *schema.ResourceD d.Set("macaddress", networkdata.MacAddress) d.Set("status", networkdata.Status) d.Set("network_port_id", networkdata.PortID) - d.Set("port_id", networkdata.PortID) d.Set("public_ip", networkdata.ExternalIP) return nil diff --git a/ibm/service/power/resource_ibm_pi_network_port_test.go b/ibm/service/power/resource_ibm_pi_network_port_test.go deleted file mode 100644 index 65f72d7168..0000000000 --- a/ibm/service/power/resource_ibm_pi_network_port_test.go +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package power_test - -import ( - "context" - "errors" - "fmt" - "testing" - - 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/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - - st "github.com/IBM-Cloud/power-go-client/clients/instance" -) - -func TestAccIBMPINetworkPortbasic(t *testing.T) { - name := fmt.Sprintf("tf-pi-network-port-%d", acctest.RandIntRange(10, 100)) - resource.Test(t, resource.TestCase{ - PreCheck: func() { acc.TestAccPreCheck(t) }, - Providers: acc.TestAccProviders, - CheckDestroy: testAccCheckIBMPINetworkPortDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMPINetworkPortConfig(name), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMPINetworkPortExists("ibm_pi_network_port.power_network_port"), - resource.TestCheckResourceAttr( - "ibm_pi_network_port.power_network_port", "pi_network_name", name), - ), - }, - }, - }) -} -func testAccCheckIBMPINetworkPortDestroy(s *terraform.State) error { - sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() - if err != nil { - return err - } - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_pi_network_port" { - continue - } - parts, err := flex.IdParts(rs.Primary.ID) - if err != nil { - return err - } - cloudInstanceID := parts[0] - networkname := parts[1] - portID := parts[2] - networkC := st.NewIBMPINetworkClient(context.Background(), sess, cloudInstanceID) - _, err = networkC.GetPort(networkname, portID) - if err == nil { - return fmt.Errorf("PI Network Port still exists: %s", rs.Primary.ID) - } - } - - return nil -} -func testAccCheckIBMPINetworkPortExists(n string) resource.TestCheckFunc { - return func(s *terraform.State) error { - - rs, ok := s.RootModule().Resources[n] - - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - if rs.Primary.ID == "" { - return errors.New("No Record ID is set") - } - - sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() - if err != nil { - return err - } - parts, err := flex.IdParts(rs.Primary.ID) - if err != nil { - return err - } - cloudInstanceID := parts[0] - networkname := parts[1] - portID := parts[2] - client := st.NewIBMPINetworkClient(context.Background(), sess, cloudInstanceID) - - _, err = client.GetPort(networkname, portID) - if err != nil { - return err - } - return nil - - } -} - -func testAccCheckIBMPINetworkPortConfig(name string) string { - return testAccCheckIBMPINetworkConfig(name) + fmt.Sprintf(` - resource "ibm_pi_network_port" "power_network_port" { - pi_cloud_instance_id = "%s" - pi_network_name = ibm_pi_network.power_networks.pi_network_name - pi_network_port_description = "IP Reserved for Test UAT" - } - `, acc.Pi_cloud_instance_id) -} diff --git a/ibm/service/power/resource_ibm_pi_snapshot.go b/ibm/service/power/resource_ibm_pi_snapshot.go index 2372e889ed..17b75a371e 100644 --- a/ibm/service/power/resource_ibm_pi_snapshot.go +++ b/ibm/service/power/resource_ibm_pi_snapshot.go @@ -63,20 +63,8 @@ func ResourceIBMPISnapshot() *schema.Resource { Optional: true, Description: "Description of the PVM instance snapshot", }, - "description": { - Type: schema.TypeString, - Optional: true, - Description: "Snapshot description", - Deprecated: "This field is deprecated, use pi_description instead", - }, // Computed Attributes - helpers.PISnapshot: { - Type: schema.TypeString, - Computed: true, - Description: "Id of the snapshot", - Deprecated: "This field is deprecated, use snapshot_id instead", - }, "snapshot_id": { Type: schema.TypeString, Computed: true, @@ -114,9 +102,6 @@ func resourceIBMPISnapshotCreate(ctx context.Context, d *schema.ResourceData, me name := d.Get(helpers.PISnapshotName).(string) var description string - if v, ok := d.GetOk("description"); ok { - description = v.(string) - } if v, ok := d.GetOk("pi_description"); ok { description = v.(string) } @@ -167,7 +152,6 @@ func resourceIBMPISnapshotRead(ctx context.Context, d *schema.ResourceData, meta } d.Set(helpers.PISnapshotName, snapshotdata.Name) - d.Set(helpers.PISnapshot, *snapshotdata.SnapshotID) d.Set("snapshot_id", *snapshotdata.SnapshotID) d.Set("status", snapshotdata.Status) d.Set("creation_date", snapshotdata.CreationDate.String()) diff --git a/ibm/service/power/resource_ibm_pi_workspace.go b/ibm/service/power/resource_ibm_pi_workspace.go index 590f6ac657..bdb0a24424 100644 --- a/ibm/service/power/resource_ibm_pi_workspace.go +++ b/ibm/service/power/resource_ibm_pi_workspace.go @@ -8,6 +8,7 @@ import ( st "github.com/IBM-Cloud/power-go-client/clients/instance" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -50,6 +51,11 @@ func ResourceIBMPIWorkspace() *schema.Resource { ForceNew: true, Description: "Plan associated with the offering; Valid values are public or private.", }, + Attr_WorkspaceDetails: { + Computed: true, + Description: "Workspace information.", + Type: schema.TypeMap, + }, }, } } @@ -121,6 +127,12 @@ func resourceIBMPIWorkspaceRead(ctx context.Context, d *schema.ResourceData, met return diag.FromErr(err) } d.Set(PIWorkspaceName, controller.Name) + wsDetails := map[string]interface{}{ + Attr_CreationDate: controller.CreatedAt, + Attr_CRN: controller.TargetCRN, + } + + d.Set(Attr_WorkspaceDetails, flex.Flatten(wsDetails)) return nil } diff --git a/ibm/service/project/data_source_ibm_project.go b/ibm/service/project/data_source_ibm_project.go index 2f662c1745..364b04543d 100644 --- a/ibm/service/project/data_source_ibm_project.go +++ b/ibm/service/project/data_source_ibm_project.go @@ -1,4 +1,4 @@ -// Copyright IBM Corp. 2023 All Rights Reserved. +// Copyright IBM Corp. 2024 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 package project @@ -142,15 +142,15 @@ func DataSourceIbmProject() *schema.Resource { Description: "The name and description of a project configuration.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ + "description": &schema.Schema{ Type: schema.TypeString, Computed: true, - Description: "The configuration name. It is unique within the account across projects and regions.", + Description: "A project configuration description.", }, - "description": &schema.Schema{ + "name": &schema.Schema{ Type: schema.TypeString, Computed: true, - Description: "A project configuration description.", + Description: "The configuration name. It is unique within the account across projects and regions.", }, }, }, @@ -198,6 +198,54 @@ func DataSourceIbmProject() *schema.Resource { Computed: true, Description: "The configuration type.", }, + "approved_version": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "approved_version", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "state", + }, + "version": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "version", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "version", + }, + }, + }, + }, + "deployed_version": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "deployed_version", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "state", + }, + "version": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "version", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "version", + }, + }, + }, + }, }, }, }, @@ -266,15 +314,15 @@ func DataSourceIbmProject() *schema.Resource { Description: "The environment definition used in the project collection.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ + "description": &schema.Schema{ Type: schema.TypeString, Computed: true, - Description: "The name of the environment. It is unique within the account across projects and regions.", + Description: "The description of the environment.", }, - "description": &schema.Schema{ + "name": &schema.Schema{ Type: schema.TypeString, Computed: true, - Description: "The description of the environment.", + Description: "The name of the environment. It is unique within the account across projects and regions.", }, }, }, @@ -293,15 +341,20 @@ func DataSourceIbmProject() *schema.Resource { Computed: true, Description: "The name of the project. It is unique within the account across regions.", }, + "destroy_on_delete": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "The policy that indicates whether the resources are destroyed or not when a project is deleted.", + }, "description": &schema.Schema{ Type: schema.TypeString, Computed: true, Description: "A brief explanation of the project's use in the configuration of a deployable architecture. It is possible to create a project without providing a description.", }, - "destroy_on_delete": &schema.Schema{ + "monitoring_enabled": &schema.Schema{ Type: schema.TypeBool, Computed: true, - Description: "The policy that indicates whether the resources are destroyed or not when a project is deleted.", + Description: "A boolean flag to enable project monitoring.", }, }, }, @@ -460,7 +513,7 @@ func dataSourceIbmProjectProjectConfigSummaryToMap(model *projectv1.ProjectConfi modelMap["created_at"] = model.CreatedAt.String() modelMap["modified_at"] = model.ModifiedAt.String() modelMap["href"] = model.Href - definitionMap, err := dataSourceIbmProjectProjectConfigDefinitionNameDescriptionToMap(model.Definition) + definitionMap, err := dataSourceIbmProjectProjectConfigSummaryDefinitionToMap(model.Definition) if err != nil { return modelMap, err } @@ -484,14 +537,14 @@ func dataSourceIbmProjectProjectConfigVersionSummaryToMap(model *projectv1.Proje return modelMap, nil } -func dataSourceIbmProjectProjectConfigDefinitionNameDescriptionToMap(model *projectv1.ProjectConfigDefinitionNameDescription) (map[string]interface{}, error) { +func dataSourceIbmProjectProjectConfigSummaryDefinitionToMap(model *projectv1.ProjectConfigSummaryDefinition) (map[string]interface{}, error) { modelMap := make(map[string]interface{}) - if model.Name != nil { - modelMap["name"] = model.Name - } if model.Description != nil { modelMap["description"] = model.Description } + if model.Name != nil { + modelMap["name"] = model.Name + } return modelMap, nil } @@ -524,7 +577,7 @@ func dataSourceIbmProjectProjectEnvironmentSummaryToMap(model *projectv1.Project modelMap["project"] = []map[string]interface{}{projectMap} modelMap["created_at"] = model.CreatedAt.String() modelMap["href"] = model.Href - definitionMap, err := dataSourceIbmProjectEnvironmentDefinitionNameDescriptionToMap(model.Definition) + definitionMap, err := dataSourceIbmProjectProjectEnvironmentSummaryDefinitionToMap(model.Definition) if err != nil { return modelMap, err } @@ -532,23 +585,20 @@ func dataSourceIbmProjectProjectEnvironmentSummaryToMap(model *projectv1.Project return modelMap, nil } -func dataSourceIbmProjectEnvironmentDefinitionNameDescriptionToMap(model *projectv1.EnvironmentDefinitionNameDescription) (map[string]interface{}, error) { +func dataSourceIbmProjectProjectEnvironmentSummaryDefinitionToMap(model *projectv1.ProjectEnvironmentSummaryDefinition) (map[string]interface{}, error) { modelMap := make(map[string]interface{}) - if model.Name != nil { - modelMap["name"] = model.Name - } if model.Description != nil { modelMap["description"] = model.Description } + modelMap["name"] = model.Name return modelMap, nil } func dataSourceIbmProjectProjectDefinitionPropertiesToMap(model *projectv1.ProjectDefinitionProperties) (map[string]interface{}, error) { modelMap := make(map[string]interface{}) modelMap["name"] = model.Name - if model.Description != nil { - modelMap["description"] = model.Description - } modelMap["destroy_on_delete"] = model.DestroyOnDelete + modelMap["description"] = model.Description + modelMap["monitoring_enabled"] = model.MonitoringEnabled return modelMap, nil } diff --git a/ibm/service/project/data_source_ibm_project_config.go b/ibm/service/project/data_source_ibm_project_config.go index 04ac065b5e..6c5c7a87ee 100644 --- a/ibm/service/project/data_source_ibm_project_config.go +++ b/ibm/service/project/data_source_ibm_project_config.go @@ -1,4 +1,4 @@ -// Copyright IBM Corp. 2023 All Rights Reserved. +// Copyright IBM Corp. 2024 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 package project @@ -307,16 +307,55 @@ func DataSourceIbmProjectConfig() *schema.Resource { Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ + "compliance_profile": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The profile required for compliance.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique ID for that compliance profile.", + }, + "instance_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A unique ID for an instance of a compliance profile.", + }, + "instance_location": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The location of the compliance instance.", + }, + "attachment_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A unique ID for the attachment to a compliance profile.", + }, + "profile_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name of the compliance profile.", + }, + }, + }, + }, + "locator_id": &schema.Schema{ Type: schema.TypeString, Computed: true, - Description: "The configuration name. It is unique within the account across projects and regions.", + Description: "A unique concatenation of catalogID.versionID that identifies the DA in the catalog. Either schematics.workspace_crn, definition.locator_id, or both must be specified.", }, "description": &schema.Schema{ Type: schema.TypeString, Computed: true, Description: "A project configuration description.", }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The configuration name. It is unique within the account across projects and regions.", + }, "environment_id": &schema.Schema{ Type: schema.TypeString, Computed: true, @@ -363,45 +402,6 @@ func DataSourceIbmProjectConfig() *schema.Resource { Type: schema.TypeString, }, }, - "compliance_profile": &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Description: "The profile required for compliance.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The unique ID for that compliance profile.", - }, - "instance_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "A unique ID for an instance of a compliance profile.", - }, - "instance_location": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The location of the compliance instance.", - }, - "attachment_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "A unique ID for the attachment to a compliance profile.", - }, - "profile_name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The name of the compliance profile.", - }, - }, - }, - }, - "locator_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "A unique concatenation of catalogID.versionID that identifies the DA in the catalog. Either schematics.workspace_crn, definition.locator_id, or both must be specified.", - }, "resource_crns": &schema.Schema{ Type: schema.TypeList, Computed: true, @@ -625,13 +625,25 @@ func dataSourceIbmProjectConfigProjectConfigResponseDefinitionToMap(model projec return dataSourceIbmProjectConfigProjectConfigResponseDefinitionDAConfigDefinitionPropertiesToMap(model.(*projectv1.ProjectConfigResponseDefinitionDAConfigDefinitionProperties)) } else if _, ok := model.(*projectv1.ProjectConfigResponseDefinitionResourceConfigDefinitionProperties); ok { return dataSourceIbmProjectConfigProjectConfigResponseDefinitionResourceConfigDefinitionPropertiesToMap(model.(*projectv1.ProjectConfigResponseDefinitionResourceConfigDefinitionProperties)) + } else if _, ok := model.(*projectv1.ProjectConfigResponseDefinitionStackConfigDefinitionProperties); ok { + return dataSourceIbmProjectConfigProjectConfigResponseDefinitionStackConfigDefinitionPropertiesToMap(model.(*projectv1.ProjectConfigResponseDefinitionStackConfigDefinitionProperties)) } else if _, ok := model.(*projectv1.ProjectConfigResponseDefinition); ok { modelMap := make(map[string]interface{}) model := model.(*projectv1.ProjectConfigResponseDefinition) - modelMap["name"] = model.Name + if model.ComplianceProfile != nil { + complianceProfileMap, err := dataSourceIbmProjectConfigProjectComplianceProfileToMap(model.ComplianceProfile) + if err != nil { + return modelMap, err + } + modelMap["compliance_profile"] = []map[string]interface{}{complianceProfileMap} + } + if model.LocatorID != nil { + modelMap["locator_id"] = model.LocatorID + } if model.Description != nil { modelMap["description"] = model.Description } + modelMap["name"] = model.Name if model.EnvironmentID != nil { modelMap["environment_id"] = model.EnvironmentID } @@ -656,16 +668,6 @@ func dataSourceIbmProjectConfigProjectConfigResponseDefinitionToMap(model projec } modelMap["settings"] = settings } - if model.ComplianceProfile != nil { - complianceProfileMap, err := dataSourceIbmProjectConfigProjectComplianceProfileToMap(model.ComplianceProfile) - if err != nil { - return modelMap, err - } - modelMap["compliance_profile"] = []map[string]interface{}{complianceProfileMap} - } - if model.LocatorID != nil { - modelMap["locator_id"] = model.LocatorID - } if model.ResourceCrns != nil { modelMap["resource_crns"] = model.ResourceCrns } @@ -675,20 +677,6 @@ func dataSourceIbmProjectConfigProjectConfigResponseDefinitionToMap(model projec } } -func dataSourceIbmProjectConfigProjectConfigAuthToMap(model *projectv1.ProjectConfigAuth) (map[string]interface{}, error) { - modelMap := make(map[string]interface{}) - if model.TrustedProfileID != nil { - modelMap["trusted_profile_id"] = model.TrustedProfileID - } - if model.Method != nil { - modelMap["method"] = model.Method - } - if model.ApiKey != nil { - modelMap["api_key"] = model.ApiKey - } - return modelMap, nil -} - func dataSourceIbmProjectConfigProjectComplianceProfileToMap(model *projectv1.ProjectComplianceProfile) (map[string]interface{}, error) { modelMap := make(map[string]interface{}) if model.ID != nil { @@ -709,14 +697,38 @@ func dataSourceIbmProjectConfigProjectComplianceProfileToMap(model *projectv1.Pr return modelMap, nil } +func dataSourceIbmProjectConfigProjectConfigAuthToMap(model *projectv1.ProjectConfigAuth) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.TrustedProfileID != nil { + modelMap["trusted_profile_id"] = model.TrustedProfileID + } + if model.Method != nil { + modelMap["method"] = model.Method + } + if model.ApiKey != nil { + modelMap["api_key"] = model.ApiKey + } + return modelMap, nil +} + func dataSourceIbmProjectConfigProjectConfigResponseDefinitionDAConfigDefinitionPropertiesToMap(model *projectv1.ProjectConfigResponseDefinitionDAConfigDefinitionProperties) (map[string]interface{}, error) { modelMap := make(map[string]interface{}) - if model.Name != nil { - modelMap["name"] = model.Name + if model.ComplianceProfile != nil { + complianceProfileMap, err := dataSourceIbmProjectConfigProjectComplianceProfileToMap(model.ComplianceProfile) + if err != nil { + return modelMap, err + } + modelMap["compliance_profile"] = []map[string]interface{}{complianceProfileMap} + } + if model.LocatorID != nil { + modelMap["locator_id"] = model.LocatorID } if model.Description != nil { modelMap["description"] = model.Description } + if model.Name != nil { + modelMap["name"] = model.Name + } if model.EnvironmentID != nil { modelMap["environment_id"] = model.EnvironmentID } @@ -741,27 +753,20 @@ func dataSourceIbmProjectConfigProjectConfigResponseDefinitionDAConfigDefinition } modelMap["settings"] = settings } - if model.ComplianceProfile != nil { - complianceProfileMap, err := dataSourceIbmProjectConfigProjectComplianceProfileToMap(model.ComplianceProfile) - if err != nil { - return modelMap, err - } - modelMap["compliance_profile"] = []map[string]interface{}{complianceProfileMap} - } - if model.LocatorID != nil { - modelMap["locator_id"] = model.LocatorID - } return modelMap, nil } func dataSourceIbmProjectConfigProjectConfigResponseDefinitionResourceConfigDefinitionPropertiesToMap(model *projectv1.ProjectConfigResponseDefinitionResourceConfigDefinitionProperties) (map[string]interface{}, error) { modelMap := make(map[string]interface{}) - if model.Name != nil { - modelMap["name"] = model.Name + if model.ResourceCrns != nil { + modelMap["resource_crns"] = model.ResourceCrns } if model.Description != nil { modelMap["description"] = model.Description } + if model.Name != nil { + modelMap["name"] = model.Name + } if model.EnvironmentID != nil { modelMap["environment_id"] = model.EnvironmentID } @@ -786,8 +791,22 @@ func dataSourceIbmProjectConfigProjectConfigResponseDefinitionResourceConfigDefi } modelMap["settings"] = settings } - if model.ResourceCrns != nil { - modelMap["resource_crns"] = model.ResourceCrns + return modelMap, nil +} + +func dataSourceIbmProjectConfigProjectConfigResponseDefinitionStackConfigDefinitionPropertiesToMap(model *projectv1.ProjectConfigResponseDefinitionStackConfigDefinitionProperties) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Description != nil { + modelMap["description"] = model.Description + } + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.LocatorID != nil { + modelMap["locator_id"] = model.LocatorID + } + if model.EnvironmentID != nil { + modelMap["environment_id"] = model.EnvironmentID } return modelMap, nil } diff --git a/ibm/service/project/data_source_ibm_project_config_test.go b/ibm/service/project/data_source_ibm_project_config_test.go index 0b78bca324..368e190f69 100644 --- a/ibm/service/project/data_source_ibm_project_config_test.go +++ b/ibm/service/project/data_source_ibm_project_config_test.go @@ -1,4 +1,4 @@ -// Copyright IBM Corp. 2023 All Rights Reserved. +// Copyright IBM Corp. 2024 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 package project_test @@ -27,6 +27,7 @@ func TestAccIbmProjectConfigDataSourceBasic(t *testing.T) { resource.TestCheckResourceAttrSet("data.ibm_project_config.project_config_instance", "is_draft"), resource.TestCheckResourceAttrSet("data.ibm_project_config.project_config_instance", "created_at"), resource.TestCheckResourceAttrSet("data.ibm_project_config.project_config_instance", "modified_at"), + resource.TestCheckResourceAttrSet("data.ibm_project_config.project_config_instance", "outputs.#"), resource.TestCheckResourceAttrSet("data.ibm_project_config.project_config_instance", "project.#"), resource.TestCheckResourceAttrSet("data.ibm_project_config.project_config_instance", "state"), resource.TestCheckResourceAttrSet("data.ibm_project_config.project_config_instance", "href"), @@ -46,6 +47,7 @@ func testAccCheckIbmProjectConfigDataSourceConfigBasic() string { name = "acme-microservice" description = "acme-microservice description" destroy_on_delete = true + monitoring_enabled = true } } diff --git a/ibm/service/project/data_source_ibm_project_environment.go b/ibm/service/project/data_source_ibm_project_environment.go index 514e19f289..e3d317edb6 100644 --- a/ibm/service/project/data_source_ibm_project_environment.go +++ b/ibm/service/project/data_source_ibm_project_environment.go @@ -1,4 +1,4 @@ -// Copyright IBM Corp. 2023 All Rights Reserved. +// Copyright IBM Corp. 2024 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 package project @@ -95,15 +95,15 @@ func DataSourceIbmProjectEnvironment() *schema.Resource { Description: "The environment definition.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ + "description": &schema.Schema{ Type: schema.TypeString, Computed: true, - Description: "The name of the environment. It is unique within the account across projects and regions.", + Description: "The description of the environment.", }, - "description": &schema.Schema{ + "name": &schema.Schema{ Type: schema.TypeString, Computed: true, - Description: "The description of the environment.", + Description: "The name of the environment. It is unique within the account across projects and regions.", }, "authorizations": &schema.Schema{ Type: schema.TypeList, @@ -262,10 +262,10 @@ func dataSourceIbmProjectEnvironmentProjectDefinitionReferenceToMap(model *proje func dataSourceIbmProjectEnvironmentEnvironmentDefinitionRequiredPropertiesToMap(model *projectv1.EnvironmentDefinitionRequiredProperties) (map[string]interface{}, error) { modelMap := make(map[string]interface{}) - modelMap["name"] = model.Name if model.Description != nil { modelMap["description"] = model.Description } + modelMap["name"] = model.Name if model.Authorizations != nil { authorizationsMap, err := dataSourceIbmProjectEnvironmentProjectConfigAuthToMap(model.Authorizations) if err != nil { diff --git a/ibm/service/project/data_source_ibm_project_environment_test.go b/ibm/service/project/data_source_ibm_project_environment_test.go index 2f2d111aba..648095c74e 100644 --- a/ibm/service/project/data_source_ibm_project_environment_test.go +++ b/ibm/service/project/data_source_ibm_project_environment_test.go @@ -1,4 +1,4 @@ -// Copyright IBM Corp. 2023 All Rights Reserved. +// Copyright IBM Corp. 2024 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 package project_test @@ -43,6 +43,7 @@ func testAccCheckIbmProjectEnvironmentDataSourceConfigBasic() string { name = "acme-microservice" description = "acme-microservice description" destroy_on_delete = true + monitoring_enabled = true } } diff --git a/ibm/service/project/data_source_ibm_project_test.go b/ibm/service/project/data_source_ibm_project_test.go index 6ac9472a3c..553e45f12c 100644 --- a/ibm/service/project/data_source_ibm_project_test.go +++ b/ibm/service/project/data_source_ibm_project_test.go @@ -1,4 +1,4 @@ -// Copyright IBM Corp. 2023 All Rights Reserved. +// Copyright IBM Corp. 2024 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 package project_test @@ -27,11 +27,14 @@ func TestAccIbmProjectDataSourceBasic(t *testing.T) { resource.TestCheckResourceAttrSet("data.ibm_project.project_instance", "project_id"), resource.TestCheckResourceAttrSet("data.ibm_project.project_instance", "crn"), resource.TestCheckResourceAttrSet("data.ibm_project.project_instance", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_project.project_instance", "cumulative_needs_attention_view.#"), resource.TestCheckResourceAttrSet("data.ibm_project.project_instance", "location"), resource.TestCheckResourceAttrSet("data.ibm_project.project_instance", "resource_group_id"), resource.TestCheckResourceAttrSet("data.ibm_project.project_instance", "state"), resource.TestCheckResourceAttrSet("data.ibm_project.project_instance", "href"), resource.TestCheckResourceAttrSet("data.ibm_project.project_instance", "resource_group"), + resource.TestCheckResourceAttrSet("data.ibm_project.project_instance", "configs.#"), + resource.TestCheckResourceAttrSet("data.ibm_project.project_instance", "environments.#"), resource.TestCheckResourceAttrSet("data.ibm_project.project_instance", "definition.#"), ), }, @@ -48,6 +51,7 @@ func testAccCheckIbmProjectDataSourceConfigBasic(projectLocation string, project name = "acme-microservice" description = "acme-microservice description" destroy_on_delete = true + monitoring_enabled = true } } diff --git a/ibm/service/project/resource_ibm_project.go b/ibm/service/project/resource_ibm_project.go index d428f33c91..fb168beb2d 100644 --- a/ibm/service/project/resource_ibm_project.go +++ b/ibm/service/project/resource_ibm_project.go @@ -1,11 +1,10 @@ -// Copyright IBM Corp. 2023 All Rights Reserved. +// Copyright IBM Corp. 2024 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 package project import ( "context" - "encoding/json" "fmt" "log" @@ -39,7 +38,7 @@ func ResourceIbmProject() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, - Description: "The resource group where the project's data and tools are created.", + Description: "The resource group name where the project's data and tools are created.", }, "definition": &schema.Schema{ Type: schema.TypeList, @@ -54,15 +53,21 @@ func ResourceIbmProject() *schema.Resource { Required: true, Description: "The name of the project. It is unique within the account across regions.", }, + "destroy_on_delete": &schema.Schema{ + Type: schema.TypeBool, + Required: true, + Description: "The policy that indicates whether the resources are destroyed or not when a project is deleted.", + }, "description": &schema.Schema{ Type: schema.TypeString, - Optional: true, + Required: true, Description: "A brief explanation of the project's use in the configuration of a deployable architecture. It is possible to create a project without providing a description.", }, - "destroy_on_delete": &schema.Schema{ + "monitoring_enabled": &schema.Schema{ Type: schema.TypeBool, - Required: true, - Description: "The policy that indicates whether the resources are destroyed or not when a project is deleted.", + Optional: true, + Default: false, + Description: "A boolean flag to enable project monitoring.", }, }, }, @@ -173,15 +178,15 @@ func ResourceIbmProject() *schema.Resource { Description: "The name and description of a project configuration.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ + "description": &schema.Schema{ Type: schema.TypeString, Computed: true, - Description: "The configuration name. It is unique within the account across projects and regions.", + Description: "A project configuration description.", }, - "description": &schema.Schema{ + "name": &schema.Schema{ Type: schema.TypeString, Computed: true, - Description: "A project configuration description.", + Description: "The configuration name. It is unique within the account across projects and regions.", }, }, }, @@ -229,6 +234,54 @@ func ResourceIbmProject() *schema.Resource { Computed: true, Description: "The configuration type.", }, + "approved_version": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "approved_version", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "state", + }, + "version": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "version", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "version", + }, + }, + }, + }, + "deployed_version": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "deployed_version", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "state", + }, + "version": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "version", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "version", + }, + }, + }, + }, }, }, }, @@ -297,15 +350,15 @@ func ResourceIbmProject() *schema.Resource { Description: "The environment definition used in the project collection.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ + "description": &schema.Schema{ Type: schema.TypeString, Computed: true, - Description: "The name of the environment. It is unique within the account across projects and regions.", + Description: "The description of the environment.", }, - "description": &schema.Schema{ + "name": &schema.Schema{ Type: schema.TypeString, Computed: true, - Description: "The description of the environment.", + Description: "The name of the environment. It is unique within the account across projects and regions.", }, }, }, @@ -434,18 +487,16 @@ func resourceIbmProjectRead(context context.Context, d *schema.ResourceData, met if err = d.Set("created_at", flex.DateTimeToString(project.CreatedAt)); err != nil { return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) } - if !core.IsNil(project.CumulativeNeedsAttentionView) { - cumulativeNeedsAttentionView := []map[string]interface{}{} - for _, cumulativeNeedsAttentionViewItem := range project.CumulativeNeedsAttentionView { - cumulativeNeedsAttentionViewItemMap, err := resourceIbmProjectCumulativeNeedsAttentionToMap(&cumulativeNeedsAttentionViewItem) - if err != nil { - return diag.FromErr(err) - } - cumulativeNeedsAttentionView = append(cumulativeNeedsAttentionView, cumulativeNeedsAttentionViewItemMap) - } - if err = d.Set("cumulative_needs_attention_view", cumulativeNeedsAttentionView); err != nil { - return diag.FromErr(fmt.Errorf("Error setting cumulative_needs_attention_view: %s", err)) + cumulativeNeedsAttentionView := []map[string]interface{}{} + for _, cumulativeNeedsAttentionViewItem := range project.CumulativeNeedsAttentionView { + cumulativeNeedsAttentionViewItemMap, err := resourceIbmProjectCumulativeNeedsAttentionToMap(&cumulativeNeedsAttentionViewItem) + if err != nil { + return diag.FromErr(err) } + cumulativeNeedsAttentionView = append(cumulativeNeedsAttentionView, cumulativeNeedsAttentionViewItemMap) + } + if err = d.Set("cumulative_needs_attention_view", cumulativeNeedsAttentionView); err != nil { + return diag.FromErr(fmt.Errorf("Error setting cumulative_needs_attention_view: %s", err)) } if !core.IsNil(project.CumulativeNeedsAttentionViewError) { if err = d.Set("cumulative_needs_attention_view_error", project.CumulativeNeedsAttentionViewError); err != nil { @@ -466,31 +517,27 @@ func resourceIbmProjectRead(context context.Context, d *schema.ResourceData, met return diag.FromErr(fmt.Errorf("Error setting event_notifications_crn: %s", err)) } } - if !core.IsNil(project.Configs) { - configs := []map[string]interface{}{} - for _, configsItem := range project.Configs { - configsItemMap, err := resourceIbmProjectProjectConfigSummaryToMap(&configsItem) - if err != nil { - return diag.FromErr(err) - } - configs = append(configs, configsItemMap) - } - if err = d.Set("configs", configs); err != nil { - return diag.FromErr(fmt.Errorf("Error setting configs: %s", err)) + configs := []map[string]interface{}{} + for _, configsItem := range project.Configs { + configsItemMap, err := resourceIbmProjectProjectConfigSummaryToMap(&configsItem) + if err != nil { + return diag.FromErr(err) } + configs = append(configs, configsItemMap) } - if !core.IsNil(project.Environments) { - environments := []map[string]interface{}{} - for _, environmentsItem := range project.Environments { - environmentsItemMap, err := resourceIbmProjectProjectEnvironmentSummaryToMap(&environmentsItem) - if err != nil { - return diag.FromErr(err) - } - environments = append(environments, environmentsItemMap) - } - if err = d.Set("environments", environments); err != nil { - return diag.FromErr(fmt.Errorf("Error setting environments: %s", err)) + if err = d.Set("configs", configs); err != nil { + return diag.FromErr(fmt.Errorf("Error setting configs: %s", err)) + } + environments := []map[string]interface{}{} + for _, environmentsItem := range project.Environments { + environmentsItemMap, err := resourceIbmProjectProjectEnvironmentSummaryToMap(&environmentsItem) + if err != nil { + return diag.FromErr(err) } + environments = append(environments, environmentsItemMap) + } + if err = d.Set("environments", environments); err != nil { + return diag.FromErr(fmt.Errorf("Error setting environments: %s", err)) } return nil @@ -538,7 +585,7 @@ func resourceIbmProjectDelete(context context.Context, d *schema.ResourceData, m deleteProjectOptions.SetID(d.Id()) - response, err := projectClient.DeleteProjectWithContext(context, deleteProjectOptions) + _, response, err := projectClient.DeleteProjectWithContext(context, deleteProjectOptions) if err != nil { log.Printf("[DEBUG] DeleteProjectWithContext failed %s\n%s", err, response) return diag.FromErr(fmt.Errorf("DeleteProjectWithContext failed %s\n%s", err, response)) @@ -552,18 +599,21 @@ func resourceIbmProjectDelete(context context.Context, d *schema.ResourceData, m func resourceIbmProjectMapToProjectPrototypeDefinition(modelMap map[string]interface{}) (*projectv1.ProjectPrototypeDefinition, error) { model := &projectv1.ProjectPrototypeDefinition{} model.Name = core.StringPtr(modelMap["name"].(string)) + if modelMap["destroy_on_delete"] != nil { + model.DestroyOnDelete = core.BoolPtr(modelMap["destroy_on_delete"].(bool)) + } if modelMap["description"] != nil && modelMap["description"].(string) != "" { model.Description = core.StringPtr(modelMap["description"].(string)) } - if modelMap["destroy_on_delete"] != nil { - model.DestroyOnDelete = core.BoolPtr(modelMap["destroy_on_delete"].(bool)) + if modelMap["monitoring_enabled"] != nil { + model.MonitoringEnabled = core.BoolPtr(modelMap["monitoring_enabled"].(bool)) } return model, nil } func resourceIbmProjectMapToProjectConfigPrototype(modelMap map[string]interface{}) (*projectv1.ProjectConfigPrototype, error) { model := &projectv1.ProjectConfigPrototype{} - DefinitionModel, err := resourceIbmProjectMapToProjectConfigPrototypeDefinitionBlock(modelMap["definition"].([]interface{})[0].(map[string]interface{})) + DefinitionModel, err := resourceIbmProjectMapToProjectConfigDefinitionBlockPrototype(modelMap["definition"].([]interface{})[0].(map[string]interface{})) if err != nil { return model, err } @@ -578,12 +628,22 @@ func resourceIbmProjectMapToProjectConfigPrototype(modelMap map[string]interface return model, nil } -func resourceIbmProjectMapToProjectConfigPrototypeDefinitionBlock(modelMap map[string]interface{}) (projectv1.ProjectConfigPrototypeDefinitionBlockIntf, error) { - model := &projectv1.ProjectConfigPrototypeDefinitionBlock{} - model.Name = core.StringPtr(modelMap["name"].(string)) +func resourceIbmProjectMapToProjectConfigDefinitionBlockPrototype(modelMap map[string]interface{}) (projectv1.ProjectConfigDefinitionBlockPrototypeIntf, error) { + model := &projectv1.ProjectConfigDefinitionBlockPrototype{} + if modelMap["compliance_profile"] != nil && len(modelMap["compliance_profile"].([]interface{})) > 0 { + ComplianceProfileModel, err := resourceIbmProjectMapToProjectComplianceProfile(modelMap["compliance_profile"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.ComplianceProfile = ComplianceProfileModel + } + if modelMap["locator_id"] != nil && modelMap["locator_id"].(string) != "" { + model.LocatorID = core.StringPtr(modelMap["locator_id"].(string)) + } if modelMap["description"] != nil && modelMap["description"].(string) != "" { model.Description = core.StringPtr(modelMap["description"].(string)) } + model.Name = core.StringPtr(modelMap["name"].(string)) if modelMap["environment_id"] != nil && modelMap["environment_id"].(string) != "" { model.EnvironmentID = core.StringPtr(modelMap["environment_id"].(string)) } @@ -595,32 +655,12 @@ func resourceIbmProjectMapToProjectConfigPrototypeDefinitionBlock(modelMap map[s model.Authorizations = AuthorizationsModel } if modelMap["inputs"] != nil { - bytes, _ := json.Marshal(modelMap["inputs"].(map[string]interface{})) - newMap := make(map[string]interface{}) - json.Unmarshal(bytes, &newMap) - if len(newMap) > 0 { - model.Inputs = newMap - } + model.Inputs = modelMap["inputs"].(map[string]interface{}) } if modelMap["settings"] != nil { - bytes, _ := json.Marshal(modelMap["settings"].(map[string]interface{})) - newMap := make(map[string]interface{}) - json.Unmarshal(bytes, &newMap) - if len(newMap) > 0 { - model.Settings = newMap - } - } - if modelMap["compliance_profile"] != nil && len(modelMap["compliance_profile"].([]interface{})) > 0 { - ComplianceProfileModel, err := resourceIbmProjectMapToProjectComplianceProfile(modelMap["compliance_profile"].([]interface{})[0].(map[string]interface{})) - if err != nil { - return model, err - } - model.ComplianceProfile = ComplianceProfileModel + model.Settings = modelMap["settings"].(map[string]interface{}) } - if modelMap["locator_id"] != nil && modelMap["locator_id"].(string) != "" { - model.LocatorID = core.StringPtr(modelMap["locator_id"].(string)) - } - if modelMap["resource_crns"] != nil && len(modelMap["resource_crns"].([]interface{})) > 0 { + if modelMap["resource_crns"] != nil { resourceCrns := []string{} for _, resourceCrnsItem := range modelMap["resource_crns"].([]interface{}) { resourceCrns = append(resourceCrns, resourceCrnsItem.(string)) @@ -630,20 +670,6 @@ func resourceIbmProjectMapToProjectConfigPrototypeDefinitionBlock(modelMap map[s return model, nil } -func resourceIbmProjectMapToProjectConfigAuth(modelMap map[string]interface{}) (*projectv1.ProjectConfigAuth, error) { - model := &projectv1.ProjectConfigAuth{} - if modelMap["trusted_profile_id"] != nil && modelMap["trusted_profile_id"].(string) != "" { - model.TrustedProfileID = core.StringPtr(modelMap["trusted_profile_id"].(string)) - } - if modelMap["method"] != nil && modelMap["method"].(string) != "" { - model.Method = core.StringPtr(modelMap["method"].(string)) - } - if modelMap["api_key"] != nil && modelMap["api_key"].(string) != "" { - model.ApiKey = core.StringPtr(modelMap["api_key"].(string)) - } - return model, nil -} - func resourceIbmProjectMapToProjectComplianceProfile(modelMap map[string]interface{}) (*projectv1.ProjectComplianceProfile, error) { model := &projectv1.ProjectComplianceProfile{} if modelMap["id"] != nil && modelMap["id"].(string) != "" { @@ -664,14 +690,38 @@ func resourceIbmProjectMapToProjectComplianceProfile(modelMap map[string]interfa return model, nil } -func resourceIbmProjectMapToProjectConfigPrototypeDefinitionBlockDAConfigDefinitionProperties(modelMap map[string]interface{}) (*projectv1.ProjectConfigPrototypeDefinitionBlockDAConfigDefinitionProperties, error) { - model := &projectv1.ProjectConfigPrototypeDefinitionBlockDAConfigDefinitionProperties{} - if modelMap["name"] != nil && modelMap["name"].(string) != "" { - model.Name = core.StringPtr(modelMap["name"].(string)) +func resourceIbmProjectMapToProjectConfigAuth(modelMap map[string]interface{}) (*projectv1.ProjectConfigAuth, error) { + model := &projectv1.ProjectConfigAuth{} + if modelMap["trusted_profile_id"] != nil && modelMap["trusted_profile_id"].(string) != "" { + model.TrustedProfileID = core.StringPtr(modelMap["trusted_profile_id"].(string)) + } + if modelMap["method"] != nil && modelMap["method"].(string) != "" { + model.Method = core.StringPtr(modelMap["method"].(string)) + } + if modelMap["api_key"] != nil && modelMap["api_key"].(string) != "" { + model.ApiKey = core.StringPtr(modelMap["api_key"].(string)) + } + return model, nil +} + +func resourceIbmProjectMapToProjectConfigDefinitionBlockPrototypeDAConfigDefinitionProperties(modelMap map[string]interface{}) (*projectv1.ProjectConfigDefinitionBlockPrototypeDAConfigDefinitionProperties, error) { + model := &projectv1.ProjectConfigDefinitionBlockPrototypeDAConfigDefinitionProperties{} + if modelMap["compliance_profile"] != nil && len(modelMap["compliance_profile"].([]interface{})) > 0 { + ComplianceProfileModel, err := resourceIbmProjectMapToProjectComplianceProfile(modelMap["compliance_profile"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.ComplianceProfile = ComplianceProfileModel + } + if modelMap["locator_id"] != nil && modelMap["locator_id"].(string) != "" { + model.LocatorID = core.StringPtr(modelMap["locator_id"].(string)) } if modelMap["description"] != nil && modelMap["description"].(string) != "" { model.Description = core.StringPtr(modelMap["description"].(string)) } + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } if modelMap["environment_id"] != nil && modelMap["environment_id"].(string) != "" { model.EnvironmentID = core.StringPtr(modelMap["environment_id"].(string)) } @@ -683,42 +733,29 @@ func resourceIbmProjectMapToProjectConfigPrototypeDefinitionBlockDAConfigDefinit model.Authorizations = AuthorizationsModel } if modelMap["inputs"] != nil { - bytes, _ := json.Marshal(modelMap["inputs"].(map[string]interface{})) - newMap := make(map[string]interface{}) - json.Unmarshal(bytes, &newMap) - if len(newMap) > 0 { - model.Inputs = newMap - } + model.Inputs = modelMap["inputs"].(map[string]interface{}) } if modelMap["settings"] != nil { - bytes, _ := json.Marshal(modelMap["settings"].(map[string]interface{})) - newMap := make(map[string]interface{}) - json.Unmarshal(bytes, &newMap) - if len(newMap) > 0 { - model.Settings = newMap - } - } - if modelMap["compliance_profile"] != nil && len(modelMap["compliance_profile"].([]interface{})) > 0 { - ComplianceProfileModel, err := resourceIbmProjectMapToProjectComplianceProfile(modelMap["compliance_profile"].([]interface{})[0].(map[string]interface{})) - if err != nil { - return model, err - } - model.ComplianceProfile = ComplianceProfileModel - } - if modelMap["locator_id"] != nil && modelMap["locator_id"].(string) != "" { - model.LocatorID = core.StringPtr(modelMap["locator_id"].(string)) + model.Settings = modelMap["settings"].(map[string]interface{}) } return model, nil } -func resourceIbmProjectMapToProjectConfigPrototypeDefinitionBlockResourceConfigDefinitionProperties(modelMap map[string]interface{}) (*projectv1.ProjectConfigPrototypeDefinitionBlockResourceConfigDefinitionProperties, error) { - model := &projectv1.ProjectConfigPrototypeDefinitionBlockResourceConfigDefinitionProperties{} - if modelMap["name"] != nil && modelMap["name"].(string) != "" { - model.Name = core.StringPtr(modelMap["name"].(string)) +func resourceIbmProjectMapToProjectConfigDefinitionBlockPrototypeResourceConfigDefinitionProperties(modelMap map[string]interface{}) (*projectv1.ProjectConfigDefinitionBlockPrototypeResourceConfigDefinitionProperties, error) { + model := &projectv1.ProjectConfigDefinitionBlockPrototypeResourceConfigDefinitionProperties{} + if modelMap["resource_crns"] != nil { + resourceCrns := []string{} + for _, resourceCrnsItem := range modelMap["resource_crns"].([]interface{}) { + resourceCrns = append(resourceCrns, resourceCrnsItem.(string)) + } + model.ResourceCrns = resourceCrns } if modelMap["description"] != nil && modelMap["description"].(string) != "" { model.Description = core.StringPtr(modelMap["description"].(string)) } + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } if modelMap["environment_id"] != nil && modelMap["environment_id"].(string) != "" { model.EnvironmentID = core.StringPtr(modelMap["environment_id"].(string)) } @@ -730,27 +767,10 @@ func resourceIbmProjectMapToProjectConfigPrototypeDefinitionBlockResourceConfigD model.Authorizations = AuthorizationsModel } if modelMap["inputs"] != nil { - bytes, _ := json.Marshal(modelMap["inputs"].(map[string]interface{})) - newMap := make(map[string]interface{}) - json.Unmarshal(bytes, &newMap) - if len(newMap) > 0 { - model.Inputs = newMap - } + model.Inputs = modelMap["inputs"].(map[string]interface{}) } if modelMap["settings"] != nil { - bytes, _ := json.Marshal(modelMap["settings"].(map[string]interface{})) - newMap := make(map[string]interface{}) - json.Unmarshal(bytes, &newMap) - if len(newMap) > 0 { - model.Settings = newMap - } - } - if modelMap["resource_crns"] != nil && len(modelMap["resource_crns"].([]interface{})) > 0 { - resourceCrns := []string{} - for _, resourceCrnsItem := range modelMap["resource_crns"].([]interface{}) { - resourceCrns = append(resourceCrns, resourceCrnsItem.(string)) - } - model.ResourceCrns = resourceCrns + model.Settings = modelMap["settings"].(map[string]interface{}) } return model, nil } @@ -775,10 +795,10 @@ func resourceIbmProjectMapToEnvironmentPrototype(modelMap map[string]interface{} func resourceIbmProjectMapToEnvironmentDefinitionRequiredProperties(modelMap map[string]interface{}) (*projectv1.EnvironmentDefinitionRequiredProperties, error) { model := &projectv1.EnvironmentDefinitionRequiredProperties{} - model.Name = core.StringPtr(modelMap["name"].(string)) if modelMap["description"] != nil && modelMap["description"].(string) != "" { model.Description = core.StringPtr(modelMap["description"].(string)) } + model.Name = core.StringPtr(modelMap["name"].(string)) if modelMap["authorizations"] != nil && len(modelMap["authorizations"].([]interface{})) > 0 { AuthorizationsModel, err := resourceIbmProjectMapToProjectConfigAuth(modelMap["authorizations"].([]interface{})[0].(map[string]interface{})) if err != nil { @@ -787,12 +807,7 @@ func resourceIbmProjectMapToEnvironmentDefinitionRequiredProperties(modelMap map model.Authorizations = AuthorizationsModel } if modelMap["inputs"] != nil { - bytes, _ := json.Marshal(modelMap["inputs"].(map[string]interface{})) - newMap := make(map[string]interface{}) - json.Unmarshal(bytes, &newMap) - if len(newMap) > 0 { - model.Inputs = newMap - } + model.Inputs = modelMap["inputs"].(map[string]interface{}) } if modelMap["compliance_profile"] != nil && len(modelMap["compliance_profile"].([]interface{})) > 0 { ComplianceProfileModel, err := resourceIbmProjectMapToProjectComplianceProfile(modelMap["compliance_profile"].([]interface{})[0].(map[string]interface{})) @@ -809,11 +824,14 @@ func resourceIbmProjectMapToProjectPatchDefinitionBlock(modelMap map[string]inte if modelMap["name"] != nil && modelMap["name"].(string) != "" { model.Name = core.StringPtr(modelMap["name"].(string)) } + if modelMap["destroy_on_delete"] != nil { + model.DestroyOnDelete = core.BoolPtr(modelMap["destroy_on_delete"].(bool)) + } if modelMap["description"] != nil && modelMap["description"].(string) != "" { model.Description = core.StringPtr(modelMap["description"].(string)) } - if modelMap["destroy_on_delete"] != nil { - model.DestroyOnDelete = core.BoolPtr(modelMap["destroy_on_delete"].(bool)) + if modelMap["monitoring_enabled"] != nil { + model.MonitoringEnabled = core.BoolPtr(modelMap["monitoring_enabled"].(bool)) } return model, nil } @@ -821,10 +839,9 @@ func resourceIbmProjectMapToProjectPatchDefinitionBlock(modelMap map[string]inte func resourceIbmProjectProjectDefinitionPropertiesToMap(model *projectv1.ProjectDefinitionProperties) (map[string]interface{}, error) { modelMap := make(map[string]interface{}) modelMap["name"] = model.Name - if model.Description != nil { - modelMap["description"] = model.Description - } modelMap["destroy_on_delete"] = model.DestroyOnDelete + modelMap["description"] = model.Description + modelMap["monitoring_enabled"] = model.MonitoringEnabled return modelMap, nil } @@ -867,7 +884,7 @@ func resourceIbmProjectProjectConfigSummaryToMap(model *projectv1.ProjectConfigS modelMap["created_at"] = model.CreatedAt.String() modelMap["modified_at"] = model.ModifiedAt.String() modelMap["href"] = model.Href - definitionMap, err := resourceIbmProjectProjectConfigDefinitionNameDescriptionToMap(model.Definition) + definitionMap, err := resourceIbmProjectProjectConfigSummaryDefinitionToMap(model.Definition) if err != nil { return modelMap, err } @@ -891,14 +908,14 @@ func resourceIbmProjectProjectConfigVersionSummaryToMap(model *projectv1.Project return modelMap, nil } -func resourceIbmProjectProjectConfigDefinitionNameDescriptionToMap(model *projectv1.ProjectConfigDefinitionNameDescription) (map[string]interface{}, error) { +func resourceIbmProjectProjectConfigSummaryDefinitionToMap(model *projectv1.ProjectConfigSummaryDefinition) (map[string]interface{}, error) { modelMap := make(map[string]interface{}) - if model.Name != nil { - modelMap["name"] = model.Name - } if model.Description != nil { modelMap["description"] = model.Description } + if model.Name != nil { + modelMap["name"] = model.Name + } return modelMap, nil } @@ -931,7 +948,7 @@ func resourceIbmProjectProjectEnvironmentSummaryToMap(model *projectv1.ProjectEn modelMap["project"] = []map[string]interface{}{projectMap} modelMap["created_at"] = model.CreatedAt.String() modelMap["href"] = model.Href - definitionMap, err := resourceIbmProjectEnvironmentDefinitionNameDescriptionToMap(model.Definition) + definitionMap, err := resourceIbmProjectProjectEnvironmentSummaryDefinitionToMap(model.Definition) if err != nil { return modelMap, err } @@ -939,13 +956,11 @@ func resourceIbmProjectProjectEnvironmentSummaryToMap(model *projectv1.ProjectEn return modelMap, nil } -func resourceIbmProjectEnvironmentDefinitionNameDescriptionToMap(model *projectv1.EnvironmentDefinitionNameDescription) (map[string]interface{}, error) { +func resourceIbmProjectProjectEnvironmentSummaryDefinitionToMap(model *projectv1.ProjectEnvironmentSummaryDefinition) (map[string]interface{}, error) { modelMap := make(map[string]interface{}) - if model.Name != nil { - modelMap["name"] = model.Name - } if model.Description != nil { modelMap["description"] = model.Description } + modelMap["name"] = model.Name return modelMap, nil } diff --git a/ibm/service/project/resource_ibm_project_config.go b/ibm/service/project/resource_ibm_project_config.go index 7b748c63c3..c17b8dfcff 100644 --- a/ibm/service/project/resource_ibm_project_config.go +++ b/ibm/service/project/resource_ibm_project_config.go @@ -1,11 +1,10 @@ -// Copyright IBM Corp. 2023 All Rights Reserved. +// Copyright IBM Corp. 2024 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 package project import ( "context" - "encoding/json" "fmt" "log" @@ -201,16 +200,58 @@ func ResourceIbmProjectConfig() *schema.Resource { Required: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ + "compliance_profile": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "The profile required for compliance.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The unique ID for that compliance profile.", + }, + "instance_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "A unique ID for an instance of a compliance profile.", + }, + "instance_location": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The location of the compliance instance.", + }, + "attachment_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "A unique ID for the attachment to a compliance profile.", + }, + "profile_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The name of the compliance profile.", + }, + }, + }, + }, + "locator_id": &schema.Schema{ Type: schema.TypeString, - Required: true, - Description: "The configuration name. It is unique within the account across projects and regions.", + Optional: true, + ForceNew: true, + Description: "A unique concatenation of catalogID.versionID that identifies the DA in the catalog. Either schematics.workspace_crn, definition.locator_id, or both must be specified.", }, "description": &schema.Schema{ Type: schema.TypeString, Optional: true, + Default: "", Description: "A project configuration description.", }, + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The configuration name. It is unique within the account across projects and regions.", + }, "environment_id": &schema.Schema{ Type: schema.TypeString, Optional: true, @@ -254,47 +295,6 @@ func ResourceIbmProjectConfig() *schema.Resource { Description: "Schematics environment variables to use to deploy the configuration. Settings are only available if they were specified when the configuration was initially created.", Elem: &schema.Schema{Type: schema.TypeString}, }, - "compliance_profile": &schema.Schema{ - Type: schema.TypeList, - MaxItems: 1, - Optional: true, - Description: "The profile required for compliance.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The unique ID for that compliance profile.", - }, - "instance_id": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "A unique ID for an instance of a compliance profile.", - }, - "instance_location": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The location of the compliance instance.", - }, - "attachment_id": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "A unique ID for the attachment to a compliance profile.", - }, - "profile_name": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The name of the compliance profile.", - }, - }, - }, - }, - "locator_id": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Description: "A unique concatenation of catalogID.versionID that identifies the DA in the catalog. Either schematics.workspace_crn, definition.locator_id, or both must be specified.", - }, "resource_crns": &schema.Schema{ Type: schema.TypeList, Optional: true, @@ -448,7 +448,7 @@ func resourceIbmProjectConfigCreate(context context.Context, d *schema.ResourceD createConfigOptions := &projectv1.CreateConfigOptions{} createConfigOptions.SetProjectID(d.Get("project_id").(string)) - definitionModel, err := resourceIbmProjectConfigMapToProjectConfigPrototypeDefinitionBlock(d.Get("definition.0").(map[string]interface{})) + definitionModel, err := resourceIbmProjectConfigMapToProjectConfigDefinitionBlockPrototype(d.Get("definition.0").(map[string]interface{})) if err != nil { return diag.FromErr(err) } @@ -511,14 +511,12 @@ func resourceIbmProjectConfigRead(context context.Context, d *schema.ResourceDat if err = d.Set("is_draft", projectConfig.IsDraft); err != nil { return diag.FromErr(fmt.Errorf("Error setting is_draft: %s", err)) } - if !core.IsNil(projectConfig.NeedsAttentionState) { - needsAttentionState := []interface{}{} - for _, needsAttentionStateItem := range projectConfig.NeedsAttentionState { - needsAttentionState = append(needsAttentionState, needsAttentionStateItem) - } - if err = d.Set("needs_attention_state", needsAttentionState); err != nil { - return diag.FromErr(fmt.Errorf("Error setting needs_attention_state: %s", err)) - } + needsAttentionState := []interface{}{} + for _, needsAttentionStateItem := range projectConfig.NeedsAttentionState { + needsAttentionState = append(needsAttentionState, needsAttentionStateItem) + } + if err = d.Set("needs_attention_state", needsAttentionState); err != nil { + return diag.FromErr(fmt.Errorf("Error setting needs_attention_state: %s", err)) } if err = d.Set("created_at", flex.DateTimeToString(projectConfig.CreatedAt)); err != nil { return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) @@ -531,18 +529,16 @@ func resourceIbmProjectConfigRead(context context.Context, d *schema.ResourceDat return diag.FromErr(fmt.Errorf("Error setting last_saved_at: %s", err)) } } - if !core.IsNil(projectConfig.Outputs) { - outputs := []map[string]interface{}{} - for _, outputsItem := range projectConfig.Outputs { - outputsItemMap, err := resourceIbmProjectConfigOutputValueToMap(&outputsItem) - if err != nil { - return diag.FromErr(err) - } - outputs = append(outputs, outputsItemMap) - } - if err = d.Set("outputs", outputs); err != nil { - return diag.FromErr(fmt.Errorf("Error setting outputs: %s", err)) + outputs := []map[string]interface{}{} + for _, outputsItem := range projectConfig.Outputs { + outputsItemMap, err := resourceIbmProjectConfigOutputValueToMap(&outputsItem) + if err != nil { + return diag.FromErr(err) } + outputs = append(outputs, outputsItemMap) + } + if err = d.Set("outputs", outputs); err != nil { + return diag.FromErr(fmt.Errorf("Error setting outputs: %s", err)) } projectMap, err := resourceIbmProjectConfigProjectReferenceToMap(projectConfig.Project) if err != nil { @@ -592,7 +588,7 @@ func resourceIbmProjectConfigUpdate(context context.Context, d *schema.ResourceD " The resource must be re-created to update this property.", "project_id")) } if d.HasChange("definition") { - definition, err := resourceIbmProjectConfigMapToProjectConfigPatchDefinitionBlock(d.Get("definition.0").(map[string]interface{})) + definition, err := resourceIbmProjectConfigMapToProjectConfigDefinitionBlockPatch(d.Get("definition.0").(map[string]interface{})) if err != nil { return diag.FromErr(err) } @@ -638,12 +634,22 @@ func resourceIbmProjectConfigDelete(context context.Context, d *schema.ResourceD return nil } -func resourceIbmProjectConfigMapToProjectConfigPrototypeDefinitionBlock(modelMap map[string]interface{}) (projectv1.ProjectConfigPrototypeDefinitionBlockIntf, error) { - model := &projectv1.ProjectConfigPrototypeDefinitionBlock{} - model.Name = core.StringPtr(modelMap["name"].(string)) +func resourceIbmProjectConfigMapToProjectConfigDefinitionBlockPrototype(modelMap map[string]interface{}) (projectv1.ProjectConfigDefinitionBlockPrototypeIntf, error) { + model := &projectv1.ProjectConfigDefinitionBlockPrototype{} + if modelMap["compliance_profile"] != nil && len(modelMap["compliance_profile"].([]interface{})) > 0 { + ComplianceProfileModel, err := resourceIbmProjectConfigMapToProjectComplianceProfile(modelMap["compliance_profile"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.ComplianceProfile = ComplianceProfileModel + } + if modelMap["locator_id"] != nil && modelMap["locator_id"].(string) != "" { + model.LocatorID = core.StringPtr(modelMap["locator_id"].(string)) + } if modelMap["description"] != nil && modelMap["description"].(string) != "" { model.Description = core.StringPtr(modelMap["description"].(string)) } + model.Name = core.StringPtr(modelMap["name"].(string)) if modelMap["environment_id"] != nil && modelMap["environment_id"].(string) != "" { model.EnvironmentID = core.StringPtr(modelMap["environment_id"].(string)) } @@ -655,32 +661,12 @@ func resourceIbmProjectConfigMapToProjectConfigPrototypeDefinitionBlock(modelMap model.Authorizations = AuthorizationsModel } if modelMap["inputs"] != nil { - bytes, _ := json.Marshal(modelMap["inputs"].(map[string]interface{})) - newMap := make(map[string]interface{}) - json.Unmarshal(bytes, &newMap) - if len(newMap) > 0 { - model.Inputs = newMap - } + model.Inputs = modelMap["inputs"].(map[string]interface{}) } if modelMap["settings"] != nil { - bytes, _ := json.Marshal(modelMap["settings"].(map[string]interface{})) - newMap := make(map[string]interface{}) - json.Unmarshal(bytes, &newMap) - if len(newMap) > 0 { - model.Settings = newMap - } + model.Settings = modelMap["settings"].(map[string]interface{}) } - if modelMap["compliance_profile"] != nil && len(modelMap["compliance_profile"].([]interface{})) > 0 { - ComplianceProfileModel, err := resourceIbmProjectConfigMapToProjectComplianceProfile(modelMap["compliance_profile"].([]interface{})[0].(map[string]interface{})) - if err != nil { - return model, err - } - model.ComplianceProfile = ComplianceProfileModel - } - if modelMap["locator_id"] != nil && modelMap["locator_id"].(string) != "" { - model.LocatorID = core.StringPtr(modelMap["locator_id"].(string)) - } - if modelMap["resource_crns"] != nil && len(modelMap["resource_crns"].([]interface{})) > 0 { + if modelMap["resource_crns"] != nil { resourceCrns := []string{} for _, resourceCrnsItem := range modelMap["resource_crns"].([]interface{}) { resourceCrns = append(resourceCrns, resourceCrnsItem.(string)) @@ -690,20 +676,6 @@ func resourceIbmProjectConfigMapToProjectConfigPrototypeDefinitionBlock(modelMap return model, nil } -func resourceIbmProjectConfigMapToProjectConfigAuth(modelMap map[string]interface{}) (*projectv1.ProjectConfigAuth, error) { - model := &projectv1.ProjectConfigAuth{} - if modelMap["trusted_profile_id"] != nil && modelMap["trusted_profile_id"].(string) != "" { - model.TrustedProfileID = core.StringPtr(modelMap["trusted_profile_id"].(string)) - } - if modelMap["method"] != nil && modelMap["method"].(string) != "" { - model.Method = core.StringPtr(modelMap["method"].(string)) - } - if modelMap["api_key"] != nil && modelMap["api_key"].(string) != "" { - model.ApiKey = core.StringPtr(modelMap["api_key"].(string)) - } - return model, nil -} - func resourceIbmProjectConfigMapToProjectComplianceProfile(modelMap map[string]interface{}) (*projectv1.ProjectComplianceProfile, error) { model := &projectv1.ProjectComplianceProfile{} if modelMap["id"] != nil && modelMap["id"].(string) != "" { @@ -724,14 +696,38 @@ func resourceIbmProjectConfigMapToProjectComplianceProfile(modelMap map[string]i return model, nil } -func resourceIbmProjectConfigMapToProjectConfigPrototypeDefinitionBlockDAConfigDefinitionProperties(modelMap map[string]interface{}) (*projectv1.ProjectConfigPrototypeDefinitionBlockDAConfigDefinitionProperties, error) { - model := &projectv1.ProjectConfigPrototypeDefinitionBlockDAConfigDefinitionProperties{} - if modelMap["name"] != nil && modelMap["name"].(string) != "" { - model.Name = core.StringPtr(modelMap["name"].(string)) +func resourceIbmProjectConfigMapToProjectConfigAuth(modelMap map[string]interface{}) (*projectv1.ProjectConfigAuth, error) { + model := &projectv1.ProjectConfigAuth{} + if modelMap["trusted_profile_id"] != nil && modelMap["trusted_profile_id"].(string) != "" { + model.TrustedProfileID = core.StringPtr(modelMap["trusted_profile_id"].(string)) + } + if modelMap["method"] != nil && modelMap["method"].(string) != "" { + model.Method = core.StringPtr(modelMap["method"].(string)) + } + if modelMap["api_key"] != nil && modelMap["api_key"].(string) != "" { + model.ApiKey = core.StringPtr(modelMap["api_key"].(string)) + } + return model, nil +} + +func resourceIbmProjectConfigMapToProjectConfigDefinitionBlockPrototypeDAConfigDefinitionProperties(modelMap map[string]interface{}) (*projectv1.ProjectConfigDefinitionBlockPrototypeDAConfigDefinitionProperties, error) { + model := &projectv1.ProjectConfigDefinitionBlockPrototypeDAConfigDefinitionProperties{} + if modelMap["compliance_profile"] != nil && len(modelMap["compliance_profile"].([]interface{})) > 0 { + ComplianceProfileModel, err := resourceIbmProjectConfigMapToProjectComplianceProfile(modelMap["compliance_profile"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.ComplianceProfile = ComplianceProfileModel + } + if modelMap["locator_id"] != nil && modelMap["locator_id"].(string) != "" { + model.LocatorID = core.StringPtr(modelMap["locator_id"].(string)) } if modelMap["description"] != nil && modelMap["description"].(string) != "" { model.Description = core.StringPtr(modelMap["description"].(string)) } + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } if modelMap["environment_id"] != nil && modelMap["environment_id"].(string) != "" { model.EnvironmentID = core.StringPtr(modelMap["environment_id"].(string)) } @@ -743,42 +739,29 @@ func resourceIbmProjectConfigMapToProjectConfigPrototypeDefinitionBlockDAConfigD model.Authorizations = AuthorizationsModel } if modelMap["inputs"] != nil { - bytes, _ := json.Marshal(modelMap["inputs"].(map[string]interface{})) - newMap := make(map[string]interface{}) - json.Unmarshal(bytes, &newMap) - if len(newMap) > 0 { - model.Inputs = newMap - } + model.Inputs = modelMap["inputs"].(map[string]interface{}) } if modelMap["settings"] != nil { - bytes, _ := json.Marshal(modelMap["settings"].(map[string]interface{})) - newMap := make(map[string]interface{}) - json.Unmarshal(bytes, &newMap) - if len(newMap) > 0 { - model.Settings = newMap - } - } - if modelMap["compliance_profile"] != nil && len(modelMap["compliance_profile"].([]interface{})) > 0 { - ComplianceProfileModel, err := resourceIbmProjectConfigMapToProjectComplianceProfile(modelMap["compliance_profile"].([]interface{})[0].(map[string]interface{})) - if err != nil { - return model, err - } - model.ComplianceProfile = ComplianceProfileModel - } - if modelMap["locator_id"] != nil && modelMap["locator_id"].(string) != "" { - model.LocatorID = core.StringPtr(modelMap["locator_id"].(string)) + model.Settings = modelMap["settings"].(map[string]interface{}) } return model, nil } -func resourceIbmProjectConfigMapToProjectConfigPrototypeDefinitionBlockResourceConfigDefinitionProperties(modelMap map[string]interface{}) (*projectv1.ProjectConfigPrototypeDefinitionBlockResourceConfigDefinitionProperties, error) { - model := &projectv1.ProjectConfigPrototypeDefinitionBlockResourceConfigDefinitionProperties{} - if modelMap["name"] != nil && modelMap["name"].(string) != "" { - model.Name = core.StringPtr(modelMap["name"].(string)) +func resourceIbmProjectConfigMapToProjectConfigDefinitionBlockPrototypeResourceConfigDefinitionProperties(modelMap map[string]interface{}) (*projectv1.ProjectConfigDefinitionBlockPrototypeResourceConfigDefinitionProperties, error) { + model := &projectv1.ProjectConfigDefinitionBlockPrototypeResourceConfigDefinitionProperties{} + if modelMap["resource_crns"] != nil { + resourceCrns := []string{} + for _, resourceCrnsItem := range modelMap["resource_crns"].([]interface{}) { + resourceCrns = append(resourceCrns, resourceCrnsItem.(string)) + } + model.ResourceCrns = resourceCrns } if modelMap["description"] != nil && modelMap["description"].(string) != "" { model.Description = core.StringPtr(modelMap["description"].(string)) } + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } if modelMap["environment_id"] != nil && modelMap["environment_id"].(string) != "" { model.EnvironmentID = core.StringPtr(modelMap["environment_id"].(string)) } @@ -790,27 +773,10 @@ func resourceIbmProjectConfigMapToProjectConfigPrototypeDefinitionBlockResourceC model.Authorizations = AuthorizationsModel } if modelMap["inputs"] != nil { - bytes, _ := json.Marshal(modelMap["inputs"].(map[string]interface{})) - newMap := make(map[string]interface{}) - json.Unmarshal(bytes, &newMap) - if len(newMap) > 0 { - model.Inputs = newMap - } + model.Inputs = modelMap["inputs"].(map[string]interface{}) } if modelMap["settings"] != nil { - bytes, _ := json.Marshal(modelMap["settings"].(map[string]interface{})) - newMap := make(map[string]interface{}) - json.Unmarshal(bytes, &newMap) - if len(newMap) > 0 { - model.Settings = newMap - } - } - if modelMap["resource_crns"] != nil && len(modelMap["resource_crns"].([]interface{})) > 0 { - resourceCrns := []string{} - for _, resourceCrnsItem := range modelMap["resource_crns"].([]interface{}) { - resourceCrns = append(resourceCrns, resourceCrnsItem.(string)) - } - model.ResourceCrns = resourceCrns + model.Settings = modelMap["settings"].(map[string]interface{}) } return model, nil } @@ -823,14 +789,24 @@ func resourceIbmProjectConfigMapToSchematicsWorkspace(modelMap map[string]interf return model, nil } -func resourceIbmProjectConfigMapToProjectConfigPatchDefinitionBlock(modelMap map[string]interface{}) (projectv1.ProjectConfigPatchDefinitionBlockIntf, error) { - model := &projectv1.ProjectConfigPatchDefinitionBlock{} - if modelMap["name"] != nil && modelMap["name"].(string) != "" { - model.Name = core.StringPtr(modelMap["name"].(string)) +func resourceIbmProjectConfigMapToProjectConfigDefinitionBlockPatch(modelMap map[string]interface{}) (projectv1.ProjectConfigDefinitionBlockPatchIntf, error) { + model := &projectv1.ProjectConfigDefinitionBlockPatch{} + if modelMap["compliance_profile"] != nil && len(modelMap["compliance_profile"].([]interface{})) > 0 { + ComplianceProfileModel, err := resourceIbmProjectConfigMapToProjectComplianceProfile(modelMap["compliance_profile"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.ComplianceProfile = ComplianceProfileModel + } + if modelMap["locator_id"] != nil && modelMap["locator_id"].(string) != "" { + model.LocatorID = core.StringPtr(modelMap["locator_id"].(string)) } if modelMap["description"] != nil && modelMap["description"].(string) != "" { model.Description = core.StringPtr(modelMap["description"].(string)) } + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } if modelMap["environment_id"] != nil && modelMap["environment_id"].(string) != "" { model.EnvironmentID = core.StringPtr(modelMap["environment_id"].(string)) } @@ -842,21 +818,23 @@ func resourceIbmProjectConfigMapToProjectConfigPatchDefinitionBlock(modelMap map model.Authorizations = AuthorizationsModel } if modelMap["inputs"] != nil { - bytes, _ := json.Marshal(modelMap["inputs"].(map[string]interface{})) - newMap := make(map[string]interface{}) - json.Unmarshal(bytes, &newMap) - if len(newMap) > 0 { - model.Inputs = newMap - } + model.Inputs = modelMap["inputs"].(map[string]interface{}) } if modelMap["settings"] != nil { - bytes, _ := json.Marshal(modelMap["settings"].(map[string]interface{})) - newMap := make(map[string]interface{}) - json.Unmarshal(bytes, &newMap) - if len(newMap) > 0 { - model.Settings = newMap + model.Settings = modelMap["settings"].(map[string]interface{}) + } + if modelMap["resource_crns"] != nil { + resourceCrns := []string{} + for _, resourceCrnsItem := range modelMap["resource_crns"].([]interface{}) { + resourceCrns = append(resourceCrns, resourceCrnsItem.(string)) } + model.ResourceCrns = resourceCrns } + return model, nil +} + +func resourceIbmProjectConfigMapToProjectConfigDefinitionBlockPatchDAConfigDefinitionPropertiesPatch(modelMap map[string]interface{}) (*projectv1.ProjectConfigDefinitionBlockPatchDAConfigDefinitionPropertiesPatch, error) { + model := &projectv1.ProjectConfigDefinitionBlockPatchDAConfigDefinitionPropertiesPatch{} if modelMap["compliance_profile"] != nil && len(modelMap["compliance_profile"].([]interface{})) > 0 { ComplianceProfileModel, err := resourceIbmProjectConfigMapToProjectComplianceProfile(modelMap["compliance_profile"].([]interface{})[0].(map[string]interface{})) if err != nil { @@ -867,24 +845,12 @@ func resourceIbmProjectConfigMapToProjectConfigPatchDefinitionBlock(modelMap map if modelMap["locator_id"] != nil && modelMap["locator_id"].(string) != "" { model.LocatorID = core.StringPtr(modelMap["locator_id"].(string)) } - if modelMap["resource_crns"] != nil && len(modelMap["resource_crns"].([]interface{})) > 0 { - resourceCrns := []string{} - for _, resourceCrnsItem := range modelMap["resource_crns"].([]interface{}) { - resourceCrns = append(resourceCrns, resourceCrnsItem.(string)) - } - model.ResourceCrns = resourceCrns + if modelMap["description"] != nil && modelMap["description"].(string) != "" { + model.Description = core.StringPtr(modelMap["description"].(string)) } - return model, nil -} - -func resourceIbmProjectConfigMapToProjectConfigPatchDefinitionBlockDAConfigDefinitionProperties(modelMap map[string]interface{}) (*projectv1.ProjectConfigPatchDefinitionBlockDAConfigDefinitionProperties, error) { - model := &projectv1.ProjectConfigPatchDefinitionBlockDAConfigDefinitionProperties{} if modelMap["name"] != nil && modelMap["name"].(string) != "" { model.Name = core.StringPtr(modelMap["name"].(string)) } - if modelMap["description"] != nil && modelMap["description"].(string) != "" { - model.Description = core.StringPtr(modelMap["description"].(string)) - } if modelMap["environment_id"] != nil && modelMap["environment_id"].(string) != "" { model.EnvironmentID = core.StringPtr(modelMap["environment_id"].(string)) } @@ -896,42 +862,29 @@ func resourceIbmProjectConfigMapToProjectConfigPatchDefinitionBlockDAConfigDefin model.Authorizations = AuthorizationsModel } if modelMap["inputs"] != nil { - bytes, _ := json.Marshal(modelMap["inputs"].(map[string]interface{})) - newMap := make(map[string]interface{}) - json.Unmarshal(bytes, &newMap) - if len(newMap) > 0 { - model.Inputs = newMap - } + model.Inputs = modelMap["inputs"].(map[string]interface{}) } if modelMap["settings"] != nil { - bytes, _ := json.Marshal(modelMap["settings"].(map[string]interface{})) - newMap := make(map[string]interface{}) - json.Unmarshal(bytes, &newMap) - if len(newMap) > 0 { - model.Settings = newMap - } - } - if modelMap["compliance_profile"] != nil && len(modelMap["compliance_profile"].([]interface{})) > 0 { - ComplianceProfileModel, err := resourceIbmProjectConfigMapToProjectComplianceProfile(modelMap["compliance_profile"].([]interface{})[0].(map[string]interface{})) - if err != nil { - return model, err - } - model.ComplianceProfile = ComplianceProfileModel - } - if modelMap["locator_id"] != nil && modelMap["locator_id"].(string) != "" { - model.LocatorID = core.StringPtr(modelMap["locator_id"].(string)) + model.Settings = modelMap["settings"].(map[string]interface{}) } return model, nil } -func resourceIbmProjectConfigMapToProjectConfigPatchDefinitionBlockResourceConfigDefinitionProperties(modelMap map[string]interface{}) (*projectv1.ProjectConfigPatchDefinitionBlockResourceConfigDefinitionProperties, error) { - model := &projectv1.ProjectConfigPatchDefinitionBlockResourceConfigDefinitionProperties{} - if modelMap["name"] != nil && modelMap["name"].(string) != "" { - model.Name = core.StringPtr(modelMap["name"].(string)) +func resourceIbmProjectConfigMapToProjectConfigDefinitionBlockPatchResourceConfigDefinitionPropertiesPatch(modelMap map[string]interface{}) (*projectv1.ProjectConfigDefinitionBlockPatchResourceConfigDefinitionPropertiesPatch, error) { + model := &projectv1.ProjectConfigDefinitionBlockPatchResourceConfigDefinitionPropertiesPatch{} + if modelMap["resource_crns"] != nil { + resourceCrns := []string{} + for _, resourceCrnsItem := range modelMap["resource_crns"].([]interface{}) { + resourceCrns = append(resourceCrns, resourceCrnsItem.(string)) + } + model.ResourceCrns = resourceCrns } if modelMap["description"] != nil && modelMap["description"].(string) != "" { model.Description = core.StringPtr(modelMap["description"].(string)) } + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } if modelMap["environment_id"] != nil && modelMap["environment_id"].(string) != "" { model.EnvironmentID = core.StringPtr(modelMap["environment_id"].(string)) } @@ -943,27 +896,10 @@ func resourceIbmProjectConfigMapToProjectConfigPatchDefinitionBlockResourceConfi model.Authorizations = AuthorizationsModel } if modelMap["inputs"] != nil { - bytes, _ := json.Marshal(modelMap["inputs"].(map[string]interface{})) - newMap := make(map[string]interface{}) - json.Unmarshal(bytes, &newMap) - if len(newMap) > 0 { - model.Inputs = newMap - } + model.Inputs = modelMap["inputs"].(map[string]interface{}) } if modelMap["settings"] != nil { - bytes, _ := json.Marshal(modelMap["settings"].(map[string]interface{})) - newMap := make(map[string]interface{}) - json.Unmarshal(bytes, &newMap) - if len(newMap) > 0 { - model.Settings = newMap - } - } - if modelMap["resource_crns"] != nil && len(modelMap["resource_crns"].([]interface{})) > 0 { - resourceCrns := []string{} - for _, resourceCrnsItem := range modelMap["resource_crns"].([]interface{}) { - resourceCrns = append(resourceCrns, resourceCrnsItem.(string)) - } - model.ResourceCrns = resourceCrns + model.Settings = modelMap["settings"].(map[string]interface{}) } return model, nil } @@ -1037,13 +973,27 @@ func resourceIbmProjectConfigProjectConfigResponseDefinitionToMap(model projectv return resourceIbmProjectConfigProjectConfigResponseDefinitionDAConfigDefinitionPropertiesToMap(model.(*projectv1.ProjectConfigResponseDefinitionDAConfigDefinitionProperties)) } else if _, ok := model.(*projectv1.ProjectConfigResponseDefinitionResourceConfigDefinitionProperties); ok { return resourceIbmProjectConfigProjectConfigResponseDefinitionResourceConfigDefinitionPropertiesToMap(model.(*projectv1.ProjectConfigResponseDefinitionResourceConfigDefinitionProperties)) + } else if _, ok := model.(*projectv1.ProjectConfigResponseDefinitionStackConfigDefinitionProperties); ok { + return resourceIbmProjectConfigProjectConfigResponseDefinitionStackConfigDefinitionPropertiesToMap(model.(*projectv1.ProjectConfigResponseDefinitionStackConfigDefinitionProperties)) } else if _, ok := model.(*projectv1.ProjectConfigResponseDefinition); ok { modelMap := make(map[string]interface{}) model := model.(*projectv1.ProjectConfigResponseDefinition) - modelMap["name"] = model.Name + if model.ComplianceProfile != nil { + complianceProfileMap, err := resourceIbmProjectConfigProjectComplianceProfileToMap(model.ComplianceProfile) + if err != nil { + return modelMap, err + } + if len(complianceProfileMap) > 0 { + modelMap["compliance_profile"] = []map[string]interface{}{complianceProfileMap} + } + } + if model.LocatorID != nil { + modelMap["locator_id"] = model.LocatorID + } if model.Description != nil { modelMap["description"] = model.Description } + modelMap["name"] = model.Name if model.EnvironmentID != nil { modelMap["environment_id"] = model.EnvironmentID } @@ -1061,32 +1011,16 @@ func resourceIbmProjectConfigProjectConfigResponseDefinitionToMap(model projectv for k, v := range model.Inputs { inputs[k] = fmt.Sprintf("%v", v) } - if len(inputs) > 0 { - modelMap["inputs"] = inputs - } + modelMap["inputs"] = inputs } if model.Settings != nil { settings := make(map[string]interface{}) for k, v := range model.Settings { settings[k] = fmt.Sprintf("%v", v) } - if len(settings) > 0 { - modelMap["settings"] = settings - } - } - if model.ComplianceProfile != nil { - complianceProfileMap, err := resourceIbmProjectConfigProjectComplianceProfileToMap(model.ComplianceProfile) - if err != nil { - return modelMap, err - } - if len(complianceProfileMap) > 0 { - modelMap["compliance_profile"] = []map[string]interface{}{complianceProfileMap} - } - } - if model.LocatorID != nil { - modelMap["locator_id"] = model.LocatorID + modelMap["settings"] = settings } - if model.ResourceCrns != nil && len(model.ResourceCrns) > 0 { + if model.ResourceCrns != nil { modelMap["resource_crns"] = model.ResourceCrns } return modelMap, nil @@ -1095,20 +1029,6 @@ func resourceIbmProjectConfigProjectConfigResponseDefinitionToMap(model projectv } } -func resourceIbmProjectConfigProjectConfigAuthToMap(model *projectv1.ProjectConfigAuth) (map[string]interface{}, error) { - modelMap := make(map[string]interface{}) - if model.TrustedProfileID != nil { - modelMap["trusted_profile_id"] = model.TrustedProfileID - } - if model.Method != nil { - modelMap["method"] = model.Method - } - if model.ApiKey != nil { - modelMap["api_key"] = model.ApiKey - } - return modelMap, nil -} - func resourceIbmProjectConfigProjectComplianceProfileToMap(model *projectv1.ProjectComplianceProfile) (map[string]interface{}, error) { modelMap := make(map[string]interface{}) if model.ID != nil { @@ -1129,14 +1049,38 @@ func resourceIbmProjectConfigProjectComplianceProfileToMap(model *projectv1.Proj return modelMap, nil } +func resourceIbmProjectConfigProjectConfigAuthToMap(model *projectv1.ProjectConfigAuth) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.TrustedProfileID != nil { + modelMap["trusted_profile_id"] = model.TrustedProfileID + } + if model.Method != nil { + modelMap["method"] = model.Method + } + if model.ApiKey != nil { + modelMap["api_key"] = model.ApiKey + } + return modelMap, nil +} + func resourceIbmProjectConfigProjectConfigResponseDefinitionDAConfigDefinitionPropertiesToMap(model *projectv1.ProjectConfigResponseDefinitionDAConfigDefinitionProperties) (map[string]interface{}, error) { modelMap := make(map[string]interface{}) - if model.Name != nil { - modelMap["name"] = model.Name + if model.ComplianceProfile != nil { + complianceProfileMap, err := resourceIbmProjectConfigProjectComplianceProfileToMap(model.ComplianceProfile) + if err != nil { + return modelMap, err + } + modelMap["compliance_profile"] = []map[string]interface{}{complianceProfileMap} + } + if model.LocatorID != nil { + modelMap["locator_id"] = model.LocatorID } if model.Description != nil { modelMap["description"] = model.Description } + if model.Name != nil { + modelMap["name"] = model.Name + } if model.EnvironmentID != nil { modelMap["environment_id"] = model.EnvironmentID } @@ -1145,51 +1089,36 @@ func resourceIbmProjectConfigProjectConfigResponseDefinitionDAConfigDefinitionPr if err != nil { return modelMap, err } - if len(authorizationsMap) > 0 { - modelMap["authorizations"] = []map[string]interface{}{authorizationsMap} - } + modelMap["authorizations"] = []map[string]interface{}{authorizationsMap} } if model.Inputs != nil { inputs := make(map[string]interface{}) for k, v := range model.Inputs { inputs[k] = fmt.Sprintf("%v", v) } - if len(inputs) > 0 { - modelMap["inputs"] = inputs - } + modelMap["inputs"] = inputs } if model.Settings != nil { settings := make(map[string]interface{}) for k, v := range model.Settings { settings[k] = fmt.Sprintf("%v", v) } - if len(settings) > 0 { - modelMap["settings"] = settings - } - } - if model.ComplianceProfile != nil { - complianceProfileMap, err := resourceIbmProjectConfigProjectComplianceProfileToMap(model.ComplianceProfile) - if err != nil { - return modelMap, err - } - if len(complianceProfileMap) > 0 { - modelMap["compliance_profile"] = []map[string]interface{}{complianceProfileMap} - } - } - if model.LocatorID != nil { - modelMap["locator_id"] = model.LocatorID + modelMap["settings"] = settings } return modelMap, nil } func resourceIbmProjectConfigProjectConfigResponseDefinitionResourceConfigDefinitionPropertiesToMap(model *projectv1.ProjectConfigResponseDefinitionResourceConfigDefinitionProperties) (map[string]interface{}, error) { modelMap := make(map[string]interface{}) - if model.Name != nil { - modelMap["name"] = model.Name + if model.ResourceCrns != nil { + modelMap["resource_crns"] = model.ResourceCrns } if model.Description != nil { modelMap["description"] = model.Description } + if model.Name != nil { + modelMap["name"] = model.Name + } if model.EnvironmentID != nil { modelMap["environment_id"] = model.EnvironmentID } @@ -1205,21 +1134,31 @@ func resourceIbmProjectConfigProjectConfigResponseDefinitionResourceConfigDefini for k, v := range model.Inputs { inputs[k] = fmt.Sprintf("%v", v) } - if len(inputs) > 0 { - modelMap["inputs"] = inputs - } + modelMap["inputs"] = inputs } if model.Settings != nil { settings := make(map[string]interface{}) for k, v := range model.Settings { settings[k] = fmt.Sprintf("%v", v) } - if len(settings) > 0 { - modelMap["settings"] = settings - } + modelMap["settings"] = settings } - if model.ResourceCrns != nil && len(model.ResourceCrns) > 0 { - modelMap["resource_crns"] = model.ResourceCrns + return modelMap, nil +} + +func resourceIbmProjectConfigProjectConfigResponseDefinitionStackConfigDefinitionPropertiesToMap(model *projectv1.ProjectConfigResponseDefinitionStackConfigDefinitionProperties) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Description != nil { + modelMap["description"] = model.Description + } + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.LocatorID != nil { + modelMap["locator_id"] = model.LocatorID + } + if model.EnvironmentID != nil { + modelMap["environment_id"] = model.EnvironmentID } return modelMap, nil } diff --git a/ibm/service/project/resource_ibm_project_config_test.go b/ibm/service/project/resource_ibm_project_config_test.go index 8a827c81f1..614b24d555 100644 --- a/ibm/service/project/resource_ibm_project_config_test.go +++ b/ibm/service/project/resource_ibm_project_config_test.go @@ -1,4 +1,4 @@ -// Copyright IBM Corp. 2023 All Rights Reserved. +// Copyright IBM Corp. 2024 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 package project_test @@ -49,6 +49,7 @@ func testAccCheckIbmProjectConfigConfigBasic() string { name = "acme-microservice" description = "acme-microservice description" destroy_on_delete = true + monitoring_enabled = true } } diff --git a/ibm/service/project/resource_ibm_project_environment.go b/ibm/service/project/resource_ibm_project_environment.go index d44f2b0497..e005537f17 100644 --- a/ibm/service/project/resource_ibm_project_environment.go +++ b/ibm/service/project/resource_ibm_project_environment.go @@ -1,11 +1,10 @@ -// Copyright IBM Corp. 2023 All Rights Reserved. +// Copyright IBM Corp. 2024 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 package project import ( "context" - "encoding/json" "fmt" "log" @@ -43,16 +42,17 @@ func ResourceIbmProjectEnvironment() *schema.Resource { Description: "The environment definition.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "The name of the environment. It is unique within the account across projects and regions.", - }, "description": &schema.Schema{ Type: schema.TypeString, Optional: true, + Default: "", Description: "The description of the environment.", }, + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The name of the environment. It is unique within the account across projects and regions.", + }, "authorizations": &schema.Schema{ Type: schema.TypeList, MaxItems: 1, @@ -317,7 +317,7 @@ func resourceIbmProjectEnvironmentUpdate(context context.Context, d *schema.Reso " The resource must be re-created to update this property.", "project_id")) } if d.HasChange("definition") { - definition, err := resourceIbmProjectEnvironmentMapToEnvironmentDefinitionProperties(d.Get("definition.0").(map[string]interface{})) + definition, err := resourceIbmProjectEnvironmentMapToEnvironmentDefinitionPropertiesPatch(d.Get("definition.0").(map[string]interface{})) if err != nil { return diag.FromErr(err) } @@ -365,10 +365,10 @@ func resourceIbmProjectEnvironmentDelete(context context.Context, d *schema.Reso func resourceIbmProjectEnvironmentMapToEnvironmentDefinitionRequiredProperties(modelMap map[string]interface{}) (*projectv1.EnvironmentDefinitionRequiredProperties, error) { model := &projectv1.EnvironmentDefinitionRequiredProperties{} - model.Name = core.StringPtr(modelMap["name"].(string)) if modelMap["description"] != nil && modelMap["description"].(string) != "" { model.Description = core.StringPtr(modelMap["description"].(string)) } + model.Name = core.StringPtr(modelMap["name"].(string)) if modelMap["authorizations"] != nil && len(modelMap["authorizations"].([]interface{})) > 0 { AuthorizationsModel, err := resourceIbmProjectEnvironmentMapToProjectConfigAuth(modelMap["authorizations"].([]interface{})[0].(map[string]interface{})) if err != nil { @@ -377,12 +377,7 @@ func resourceIbmProjectEnvironmentMapToEnvironmentDefinitionRequiredProperties(m model.Authorizations = AuthorizationsModel } if modelMap["inputs"] != nil { - bytes, _ := json.Marshal(modelMap["inputs"].(map[string]interface{})) - newMap := make(map[string]interface{}) - json.Unmarshal(bytes, &newMap) - if len(newMap) > 0 { - model.Inputs = newMap - } + model.Inputs = modelMap["inputs"].(map[string]interface{}) } if modelMap["compliance_profile"] != nil && len(modelMap["compliance_profile"].([]interface{})) > 0 { ComplianceProfileModel, err := resourceIbmProjectEnvironmentMapToProjectComplianceProfile(modelMap["compliance_profile"].([]interface{})[0].(map[string]interface{})) @@ -428,14 +423,14 @@ func resourceIbmProjectEnvironmentMapToProjectComplianceProfile(modelMap map[str return model, nil } -func resourceIbmProjectEnvironmentMapToEnvironmentDefinitionProperties(modelMap map[string]interface{}) (*projectv1.EnvironmentDefinitionProperties, error) { - model := &projectv1.EnvironmentDefinitionProperties{} - if modelMap["name"] != nil && modelMap["name"].(string) != "" { - model.Name = core.StringPtr(modelMap["name"].(string)) - } +func resourceIbmProjectEnvironmentMapToEnvironmentDefinitionPropertiesPatch(modelMap map[string]interface{}) (*projectv1.EnvironmentDefinitionPropertiesPatch, error) { + model := &projectv1.EnvironmentDefinitionPropertiesPatch{} if modelMap["description"] != nil && modelMap["description"].(string) != "" { model.Description = core.StringPtr(modelMap["description"].(string)) } + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } if modelMap["authorizations"] != nil && len(modelMap["authorizations"].([]interface{})) > 0 { AuthorizationsModel, err := resourceIbmProjectEnvironmentMapToProjectConfigAuth(modelMap["authorizations"].([]interface{})[0].(map[string]interface{})) if err != nil { @@ -444,12 +439,7 @@ func resourceIbmProjectEnvironmentMapToEnvironmentDefinitionProperties(modelMap model.Authorizations = AuthorizationsModel } if modelMap["inputs"] != nil { - bytes, _ := json.Marshal(modelMap["inputs"].(map[string]interface{})) - newMap := make(map[string]interface{}) - json.Unmarshal(bytes, &newMap) - if len(newMap) > 0 { - model.Inputs = newMap - } + model.Inputs = modelMap["inputs"].(map[string]interface{}) } if modelMap["compliance_profile"] != nil && len(modelMap["compliance_profile"].([]interface{})) > 0 { ComplianceProfileModel, err := resourceIbmProjectEnvironmentMapToProjectComplianceProfile(modelMap["compliance_profile"].([]interface{})[0].(map[string]interface{})) @@ -463,10 +453,10 @@ func resourceIbmProjectEnvironmentMapToEnvironmentDefinitionProperties(modelMap func resourceIbmProjectEnvironmentEnvironmentDefinitionRequiredPropertiesToMap(model *projectv1.EnvironmentDefinitionRequiredProperties) (map[string]interface{}, error) { modelMap := make(map[string]interface{}) - modelMap["name"] = model.Name if model.Description != nil { modelMap["description"] = model.Description } + modelMap["name"] = model.Name if model.Authorizations != nil { authorizationsMap, err := resourceIbmProjectEnvironmentProjectConfigAuthToMap(model.Authorizations) if err != nil { @@ -481,9 +471,7 @@ func resourceIbmProjectEnvironmentEnvironmentDefinitionRequiredPropertiesToMap(m for k, v := range model.Inputs { inputs[k] = fmt.Sprintf("%v", v) } - if len(inputs) > 0 { - modelMap["inputs"] = inputs - } + modelMap["inputs"] = inputs } if model.ComplianceProfile != nil { complianceProfileMap, err := resourceIbmProjectEnvironmentProjectComplianceProfileToMap(model.ComplianceProfile) diff --git a/ibm/service/project/resource_ibm_project_environment_test.go b/ibm/service/project/resource_ibm_project_environment_test.go index 5d33d6db32..fdd3fd3803 100644 --- a/ibm/service/project/resource_ibm_project_environment_test.go +++ b/ibm/service/project/resource_ibm_project_environment_test.go @@ -1,4 +1,4 @@ -// Copyright IBM Corp. 2023 All Rights Reserved. +// Copyright IBM Corp. 2024 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 package project_test @@ -49,6 +49,7 @@ func testAccCheckIbmProjectEnvironmentConfigBasic() string { name = "acme-microservice" description = "acme-microservice description" destroy_on_delete = true + monitoring_enabled = true } } diff --git a/ibm/service/project/resource_ibm_project_test.go b/ibm/service/project/resource_ibm_project_test.go index 20174656ec..a5455705e3 100644 --- a/ibm/service/project/resource_ibm_project_test.go +++ b/ibm/service/project/resource_ibm_project_test.go @@ -1,4 +1,4 @@ -// Copyright IBM Corp. 2023 All Rights Reserved. +// Copyright IBM Corp. 2024 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 package project_test @@ -51,6 +51,7 @@ func testAccCheckIbmProjectConfigBasic(location string, resourceGroup string) st name = "acme-microservice" description = "acme-microservice description" destroy_on_delete = true + monitoring_enabled = true } } `, location, resourceGroup) diff --git a/ibm/service/satellite/resource_ibm_satellite_host.go b/ibm/service/satellite/resource_ibm_satellite_host.go index 99882ae3cf..1a8d5f0678 100644 --- a/ibm/service/satellite/resource_ibm_satellite_host.go +++ b/ibm/service/satellite/resource_ibm_satellite_host.go @@ -1,4 +1,4 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Copyright IBM Corp. 2017, 2024 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 package satellite @@ -121,10 +121,17 @@ func ResourceIBMSatelliteHostValidator() *validate.ResourceValidator { satelliteHostResourceValidator := validate.ResourceValidator{ResourceName: "ibm_satellite_host", Schema: validateSchema} return &satelliteHostResourceValidator } + func resourceIBMSatelliteHostCreate(d *schema.ResourceData, meta interface{}) error { - hostName := d.Get(hostID).(string) + hostNameOrID := d.Get(hostID).(string) location := d.Get(hostLocation).(string) + //Check host attached to location + hostStatus, err := waitForHostAttachment(hostNameOrID, location, d, meta) + if err != nil { + return fmt.Errorf("[ERROR] Error waiting for attaching host (%s) to be succeeded: %s", hostNameOrID, err) + } + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() if err != nil { return err @@ -138,13 +145,7 @@ func resourceIBMSatelliteHostCreate(d *schema.ResourceData, meta interface{}) er } else { hostAssignOptions.Cluster = flex.PtrToString(location) } - hostAssignOptions.HostID = flex.PtrToString(hostName) - - //Check host attached to location - hostStatus, err := waitForHostAttachment(hostName, location, d, meta) - if err != nil { - return fmt.Errorf("[ERROR] Error waiting for attaching host (%s) to be succeeded: %s", hostName, err) - } + hostAssignOptions.HostID = flex.PtrToString(hostNameOrID) labels := make(map[string]string) if _, ok := d.GetOk(hostLabels); ok { @@ -170,12 +171,12 @@ func resourceIBMSatelliteHostCreate(d *schema.ResourceData, meta interface{}) er } } - d.SetId(fmt.Sprintf("%s/%s", location, hostName)) + d.SetId(fmt.Sprintf("%s/%s", location, hostNameOrID)) //Wait for host to reach normal state - _, err = waitForHostAttachment(hostName, location, d, meta) + _, err = waitForHostAttachment(hostNameOrID, location, d, meta) if err != nil { - return fmt.Errorf("[ERROR] Error waiting for host (%s) to get normal state: %s", hostName, err) + return fmt.Errorf("[ERROR] Error waiting for host (%s) to get normal state: %s", hostNameOrID, err) } wait, ok := d.GetOk("wait_till") if ok && wait.(string) == "location_normal" { @@ -197,7 +198,7 @@ func resourceIBMSatelliteHostRead(d *schema.ResourceData, meta interface{}) erro return fmt.Errorf("[ERROR] Incorrect ID %s: Id should be a combination of location/hostName", d.Id()) } location := parts[0] - hostName := parts[1] + hostNameOrID := parts[1] satClient, err := meta.(conns.ClientSession).SatelliteClientSession() if err != nil { @@ -218,9 +219,9 @@ func resourceIBMSatelliteHostRead(d *schema.ResourceData, meta interface{}) erro } for _, h := range hostList { - if hostName == *h.Name || hostName == *h.ID { + if hostNameOrID == flex.StringValue(h.Name) || hostNameOrID == flex.StringValue(h.ID) { d.Set(hostLocation, location) - d.Set("host_id", hostName) + d.Set("host_id", hostNameOrID) if _, ok := d.GetOk(hostLabels); ok { l := d.Get(hostLabels).(*schema.Set) @@ -228,7 +229,7 @@ func resourceIBMSatelliteHostRead(d *schema.ResourceData, meta interface{}) erro } if h.Health != nil { - d.Set(hostState, *h.Health.Status) + d.Set(hostState, flex.StringValue(h.Health.Status)) } if _, ok := d.GetOk(hostCluster); ok { @@ -238,8 +239,8 @@ func resourceIBMSatelliteHostRead(d *schema.ResourceData, meta interface{}) erro } if h.Assignment != nil { - d.Set(hostWorkerPool, *h.Assignment.WorkerPoolName) - d.Set(hostZone, *h.Assignment.Zone) + d.Set(hostWorkerPool, flex.StringValue(h.Assignment.WorkerPoolName)) + d.Set(hostZone, flex.StringValue(h.Assignment.Zone)) } } } @@ -287,7 +288,7 @@ func resourceIBMSatelliteHostDelete(d *schema.ResourceData, meta interface{}) er } location := parts[0] - hostID := parts[1] + hostNameorID := parts[1] satClient, err := meta.(conns.ClientSession).SatelliteClientSession() if err != nil { return err @@ -295,7 +296,7 @@ func resourceIBMSatelliteHostDelete(d *schema.ResourceData, meta interface{}) er removeSatHostOptions := &kubernetesserviceapiv1.RemoveSatelliteHostOptions{} removeSatHostOptions.Controller = &location - removeSatHostOptions.HostID = &hostID + removeSatHostOptions.HostID = &hostNameorID response, err := satClient.RemoveSatelliteHost(removeSatHostOptions) if err != nil { @@ -309,7 +310,7 @@ func resourceIBMSatelliteHostDelete(d *schema.ResourceData, meta interface{}) er return nil } -func waitForHostAttachment(hostName, location string, d *schema.ResourceData, meta interface{}) (interface{}, error) { +func waitForHostAttachment(hostNameOrID, location string, d *schema.ResourceData, meta interface{}) (interface{}, error) { satClient, err := meta.(conns.ClientSession).SatelliteClientSession() if err != nil { return false, err @@ -325,20 +326,19 @@ func waitForHostAttachment(hostName, location string, d *schema.ResourceData, me hostList, resp, err := satClient.GetSatelliteHosts(attachOptions) if err != nil { if apiErr, ok := err.(bmxerror.RequestFailure); ok && apiErr.StatusCode() != 404 { - return nil, "", fmt.Errorf("[ERROR] The satellite host (%s) failed to attached: %v\n%s", hostName, err, resp) + return nil, "", fmt.Errorf("[ERROR] The satellite host (%s) failed to attached: %v\n%s", hostNameOrID, err, resp) } } - if hostList != nil { - for _, h := range hostList { - if h.Health != nil { - if (hostName == *h.Name) && (*h.Health.Status == rsHostNormalStatus || *h.Health.Status == rsHostReadyStatus) { - return *h.Health.Status, *h.Health.Status, err - } + for _, h := range hostList { + if h.Health != nil { + if (hostNameOrID == flex.StringValue(h.Name) || hostNameOrID == flex.StringValue(h.ID)) && + (flex.StringValue(h.Health.Status) == rsHostNormalStatus || flex.StringValue(h.Health.Status) == rsHostReadyStatus) { + return flex.StringValue(h.Health.Status), flex.StringValue(h.Health.Status), err } } } - return hostName, rsHostProvisioningStatus, nil + return hostNameOrID, rsHostProvisioningStatus, nil }, Timeout: d.Timeout(schema.TimeoutCreate), Delay: 60 * time.Second, diff --git a/ibm/service/satellite/resource_ibm_satellite_host_test.go b/ibm/service/satellite/resource_ibm_satellite_host_test.go index a73f91a0f6..6b6a201c96 100644 --- a/ibm/service/satellite/resource_ibm_satellite_host_test.go +++ b/ibm/service/satellite/resource_ibm_satellite_host_test.go @@ -1,4 +1,4 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Copyright IBM Corp. 2017, 2024 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 package satellite_test @@ -20,6 +20,7 @@ import ( func TestAccFunctionSatelliteHost_Basic(t *testing.T) { name := fmt.Sprintf("tf-satellitelocation-%d", acctest.RandIntRange(10, 100)) resource_prefix := "tf-satellite" + rhel_image_name := "ibm-redhat-8-8-minimal-amd64-3" resource.Test(t, resource.TestCase{ PreCheck: func() { acc.TestAccPreCheck(t) }, @@ -28,7 +29,7 @@ func TestAccFunctionSatelliteHost_Basic(t *testing.T) { Steps: []resource.TestStep{ { - Config: testAccCheckSatelliteHostCreate(name, resource_prefix), + Config: testAccCheckSatelliteHostCreate(name, resource_prefix, rhel_image_name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckSatelliteHostExists("ibm_satellite_host.assign_host.0"), resource.TestCheckResourceAttr("ibm_satellite_host.assign_host.0", "host_provider", "ibm"), @@ -112,86 +113,106 @@ func testAccCheckSatelliteHostDestroy(s *terraform.State) error { return nil } -func testAccCheckSatelliteHostCreate(name, resource_prefix string) string { +func testAccCheckSatelliteHostCreate(name, resource_prefix, rhel_image_name string) string { return fmt.Sprintf(` - - provider "ibm" { - region = "us-east" - } - variable "location_zones" { description = "Allocate your hosts across these three zones" type = list(string) - default = ["us-east-1", "us-east-2", "us-east-3"] - } - - resource "ibm_satellite_location" "location" { - location = "%s" - managed_from = "wdc04" - zones = var.location_zones - } - - data "ibm_satellite_attach_host_script" "script" { - location = ibm_satellite_location.location.id - labels = ["env:prod"] - host_provider = "ibm" - } - - data "ibm_resource_group" "resource_group" { + default = ["location-zone-1", "location-zone-2", "location-zone-3"] + } + + resource "ibm_satellite_location" "location" { + location = "%[1]s" + managed_from = "dal" + zones = var.location_zones + } + + data "ibm_satellite_attach_host_script" "script" { + location = ibm_satellite_location.location.id + host_provider = "ibm" + } + + data "ibm_resource_group" "resource_group" { is_default = true - } + } - resource "ibm_is_vpc" "satellite_vpc" { - name = "%s-vpc-1" - } + resource "ibm_is_vpc" "satellite_vpc" { + name = "%[2]s-vpc-1" + resource_group = data.ibm_resource_group.resource_group.id + default_security_group_name = "%[2]s-default-sg" + default_network_acl_name = "%[2]s-default-acl" + default_routing_table_name = "%[2]s-default-rt" + } - resource "ibm_is_subnet" "satellite_subnet" { - count = 3 - - name = "%s-subnet-${count.index}" + data "ibm_is_security_group" "default_group" { + name = ibm_is_vpc.satellite_vpc.default_security_group_name + } + + resource "ibm_is_security_group_rule" "ssh_rule" { + group = data.ibm_is_security_group.default_group.id + direction = "inbound" + remote = "0.0.0.0/0" + tcp { + port_min = 22 + port_max = 22 + } + } + + resource "ibm_is_security_group_rule" "ping_rule" { + group = data.ibm_is_security_group.default_group.id + direction = "inbound" + remote = "0.0.0.0/0" + icmp { + type = 8 + code = 0 + } + } + + resource "ibm_is_subnet" "satellite_subnet" { + count = 3 + + name = "%[2]s-subnet-${count.index}" vpc = ibm_is_vpc.satellite_vpc.id total_ipv4_address_count = 256 - zone = "us-east-${count.index + 1}" + zone = "us-south-${count.index + 1}" } - resource "ibm_is_ssh_key" "satellite_ssh" { - name = "%s-ibm-ssh" - public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR" + data "ibm_is_image" "rhel8" { + name = "%[3]s" } resource "ibm_is_instance" "satellite_instance" { - count = 3 - - name = "%s-instance-${count.index}" + count = 3 + + name = "%[2]s-instance-${count.index}" vpc = ibm_is_vpc.satellite_vpc.id - zone = "us-east-${count.index + 1}" - image = "r014-931515d2-fcc3-11e9-896d-3baa2797200f" + zone = "us-south-${count.index + 1}" + image = data.ibm_is_image.rhel8.id profile = "mx2-8x64" - keys = [ibm_is_ssh_key.satellite_ssh.id] + keys = [] resource_group = data.ibm_resource_group.resource_group.id user_data = data.ibm_satellite_attach_host_script.script.host_script - + primary_network_interface { + name = "eth0" subnet = ibm_is_subnet.satellite_subnet[count.index].id } } resource "ibm_is_floating_ip" "satellite_ip" { - count = 3 - - name = "%s-fip-${count.index}" + count = 3 + + name = "%[2]s-fip-${count.index}" target = ibm_is_instance.satellite_instance[count.index].primary_network_interface[0].id } resource "ibm_satellite_host" "assign_host" { - count = 3 + count = 3 location = ibm_satellite_location.location.id host_id = element(ibm_is_instance.satellite_instance[*].name, count.index) - labels = ["env:prod"] zone = element(var.location_zones, count.index) host_provider = "ibm" } - -`, name, resource_prefix, resource_prefix, resource_prefix, resource_prefix, resource_prefix) +`, name, resource_prefix, rhel_image_name) } diff --git a/ibm/service/satellite/resource_ibm_satellite_location.go b/ibm/service/satellite/resource_ibm_satellite_location.go index 9002077795..ccb0d40b81 100644 --- a/ibm/service/satellite/resource_ibm_satellite_location.go +++ b/ibm/service/satellite/resource_ibm_satellite_location.go @@ -210,16 +210,18 @@ func ResourceIBMSatelliteLocation() *schema.Resource { Sensitive: true, }, "service_subnet": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Description: "Custom subnet CIDR to provide private IP addresses for services", + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Custom subnet CIDR to provide private IP addresses for services", + DiffSuppressFunc: flex.ApplyOnce, }, "pod_subnet": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Description: "Custom subnet CIDR to provide private IP addresses for pods", + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Custom subnet CIDR to provide private IP addresses for pods", + DiffSuppressFunc: flex.ApplyOnce, }, }, } diff --git a/ibm/service/satellite/resource_ibm_satellite_storage_assignment.go b/ibm/service/satellite/resource_ibm_satellite_storage_assignment.go index 07b5d1bc51..46cf05bda6 100644 --- a/ibm/service/satellite/resource_ibm_satellite_storage_assignment.go +++ b/ibm/service/satellite/resource_ibm_satellite_storage_assignment.go @@ -45,7 +45,8 @@ func ResourceIBMSatelliteStorageAssignment() *schema.Resource { Type: schema.TypeList, Optional: true, Elem: &schema.Schema{Type: schema.TypeString}, - ConflictsWith: []string{"cluster", "controller"}, + ConflictsWith: []string{"cluster"}, + RequiredWith: []string{"controller"}, Description: "One or more cluster groups on which you want to apply the configuration. Note that at least one cluster group is required. ", }, "cluster": { @@ -119,11 +120,9 @@ func ResourceIBMSatelliteStorageAssignment() *schema.Resource { Description: "Updating an assignment to the latest available storage configuration version.", }, "controller": { - Type: schema.TypeString, - Optional: true, - Description: "The Name or ID of the Satellite Location.", - ConflictsWith: []string{"groups"}, - RequiredWith: []string{"cluster"}, + Type: schema.TypeString, + Optional: true, + Description: "The Name or ID of the Satellite Location.", }, }, } @@ -276,8 +275,10 @@ func resourceIBMContainerStorageAssignmentUpdate(d *schema.ResourceData, meta in func resourceIBMContainerStorageAssignmentDelete(d *schema.ResourceData, meta interface{}) error { uuid := d.Get("uuid").(string) + controller := d.Get("controller").(string) removeAssignmentOptions := &kubernetesserviceapiv1.RemoveAssignmentOptions{} removeAssignmentOptions.UUID = &uuid + removeAssignmentOptions.Controller = &controller _, err := waitForAssignmentDeletionStatus(removeAssignmentOptions, meta, d) if err != nil { diff --git a/ibm/service/satellite/resource_ibm_satellite_storage_configuration.go b/ibm/service/satellite/resource_ibm_satellite_storage_configuration.go index acb74fcf77..b4140211dd 100644 --- a/ibm/service/satellite/resource_ibm_satellite_storage_configuration.go +++ b/ibm/service/satellite/resource_ibm_satellite_storage_configuration.go @@ -396,9 +396,10 @@ func resourceIBMContainerStorageConfigurationUpdate(d *schema.ResourceData, meta for _, v := range result { if len(v.Groups) != 0 { createAssignmentGroupOptions := &kubernetesserviceapiv1.CreateAssignmentOptions{ - Name: v.Name, - Groups: v.Groups, - Config: v.ChannelName, + Name: v.Name, + Groups: v.Groups, + Config: v.ChannelName, + Controller: &satLocation, } _, _, err = satClient.CreateAssignment(createAssignmentGroupOptions) if err != nil { @@ -425,41 +426,27 @@ func resourceIBMContainerStorageConfigurationUpdate(d *schema.ResourceData, meta func resourceIBMContainerStorageConfigurationDelete(d *schema.ResourceData, meta interface{}) error { uuid := d.Get("uuid").(string) name := d.Get("config_name").(string) + controller := d.Get("location").(string) delete_assignments := d.Get("delete_assignments").(bool) + removeStorageConfigurationOptions := &kubernetesserviceapiv1.RemoveStorageConfigurationOptions{} + removeStorageConfigurationOptions.UUID = &uuid + removeStorageConfigurationOptions.Controller = &controller + if delete_assignments || d.HasChange("storage_template_version") { + removeStorageConfigurationOptions.RemoveAssignments = &delete_assignments + } satClient, err := meta.(conns.ClientSession).SatelliteClientSession() if err != nil { return err } - // If delete assignments = true, then all the configuration's assignments are deleted before it is destroyed. - if delete_assignments || d.HasChange("storage_template_version") { - getAssignmentsByConfigOptions := &kubernetesserviceapiv1.GetAssignmentsByConfigOptions{ - Config: &name, - } - result, _, err := satClient.GetAssignmentsByConfig(getAssignmentsByConfigOptions) - if err != nil { - return err - } - for _, v := range result { - removeAssignmentsByConfigOptions := &kubernetesserviceapiv1.RemoveAssignmentOptions{ - UUID: v.UUID, - } - _, _, err := satClient.RemoveAssignment(removeAssignmentsByConfigOptions) - if err != nil { - return fmt.Errorf("[ERROR] Failed to Delete Assignments for Storage Configuration %s - %v", name, err) - } - } - } - - _, _, err = satClient.RemoveStorageConfiguration(&kubernetesserviceapiv1.RemoveStorageConfigurationOptions{ - UUID: &uuid, - }) + _, _, err = satClient.RemoveStorageConfiguration(removeStorageConfigurationOptions) if err != nil { return fmt.Errorf("[ERROR] Error Deleting Storage Configuration %s - %v", name, err) } getStorageConfigurationOptions := &kubernetesserviceapiv1.GetStorageConfigurationOptions{ Name: &name, } + // If we cannot Get the storage configuration, it is assumed to be successfully deleted. _, err = waitForStorageConfigurationDeletionStatus(getStorageConfigurationOptions, meta, d) if err != nil { @@ -533,7 +520,7 @@ func storageConfigurationDeletionStatusRefreshFunc(getStorageConfigurationOption return nil, "NotReady", err } _, response, err := satClient.GetStorageConfiguration(getStorageConfigurationOptions) - if response.GetStatusCode() == 500 { + if response.GetStatusCode() == 404 { return true, "Ready", nil } diff --git a/ibm/service/secretsmanager/data_source_ibm_secrets_manager_secret.go b/ibm/service/secretsmanager/data_source_ibm_secrets_manager_secret.go deleted file mode 100644 index 27dcd545e8..0000000000 --- a/ibm/service/secretsmanager/data_source_ibm_secrets_manager_secret.go +++ /dev/null @@ -1,432 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package secretsmanager - -import ( - "context" - "fmt" - "log" - "strings" - "time" - - "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" - "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" - rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" - "github.com/IBM/secrets-manager-go-sdk/v2/secretsmanagerv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func DataSourceIBMSecretsManagerSecret() *schema.Resource { - return &schema.Resource{ - ReadContext: func(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - return diag.Errorf("Data Source Removal: Data Source ibm_secrets_manager_secret is removed. Use ibm_sm__secret for managing secret of a specific type") - }, - DeprecationMessage: "Data Source Removal: Data Source ibm_secrets_manager_secret is removed. Use ibm_sm__secret for managing secret of a specific type.", - Schema: map[string]*schema.Schema{ - "instance_id": { - Type: schema.TypeString, - Required: true, - Description: "Secrets Manager instance GUID", - }, - "secret_type": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validate.InvokeDataSourceValidator("ibm_secrets_manager_secret", "secret_type"), - Description: "The secret type. Supported options include: arbitrary, iam_credentials, username_password.", - }, - "secret_id": { - Type: schema.TypeString, - Required: true, - Description: "The v4 UUID that uniquely identifies the secret.", - }, - "endpoint_type": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validate.InvokeDataSourceValidator("ibm_secrets_manager_secret", "endpoint_type"), - Description: "Endpoint Type. 'public' or 'private'", - Default: "public", - }, - "metadata": { - Type: schema.TypeList, - Computed: true, - Description: "The metadata that describes the resource array.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "collection_type": { - Type: schema.TypeString, - Computed: true, - Description: "The type of resources in the resource array.", - }, - "collection_total": { - Type: schema.TypeInt, - Computed: true, - Description: "The number of elements in the resource array.", - }, - }, - }, - }, - "type": { - Type: schema.TypeString, - Computed: true, - Description: "The MIME type that represents the secret.", - }, - "name": { - Type: schema.TypeString, - Computed: true, - Description: "A human-readable alias to assign to your secret.To protect your privacy, do not use personal data, such as your name or location, as an alias for your secret.", - }, - "description": { - Type: schema.TypeString, - Computed: true, - Description: "An extended description of your secret.To protect your privacy, do not use personal data, such as your name or location, as a description for your secret.", - }, - "secret_group_id": { - Type: schema.TypeString, - Computed: true, - Description: "The v4 UUID that uniquely identifies the secret group to assign to this secret.If you omit this parameter, your secret is assigned to the `default` secret group.", - }, - "labels": { - Type: schema.TypeList, - Computed: true, - Description: "Labels that you can use to filter for secrets in your instance.Up to 30 labels can be created. Labels can be between 2-30 characters, including spaces. Special characters not permitted include the angled bracket, comma, colon, ampersand, and vertical pipe character (|).To protect your privacy, do not use personal data, such as your name or location, as a label for your secret.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "state": { - Type: schema.TypeInt, - Computed: true, - Description: "The secret state based on NIST SP 800-57. States are integers and correspond to the Pre-activation = 0, Active = 1, Suspended = 2, Deactivated = 3, and Destroyed = 5 values.", - }, - "state_description": { - Type: schema.TypeString, - Computed: true, - Description: "A text representation of the secret state.", - }, - "crn": { - Type: schema.TypeString, - Computed: true, - Description: "The Cloud Resource Name (CRN) that uniquely identifies your Secrets Manager resource.", - }, - "creation_date": { - Type: schema.TypeString, - Computed: true, - Description: "The date the secret was created. The date format follows RFC 3339.", - }, - "created_by": { - Type: schema.TypeString, - Computed: true, - Description: "The unique identifier for the entity that created the secret.", - }, - "last_update_date": { - Type: schema.TypeString, - Computed: true, - Description: "Updates when the actual secret is modified. The date format follows RFC 3339.", - }, - "versions": { - Type: schema.TypeList, - Computed: true, - Description: "An array that contains metadata for each secret version.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - Description: "The ID of the secret version.", - }, - "creation_date": { - Type: schema.TypeString, - Computed: true, - Description: "The date that the version of the secret was created.", - }, - "created_by": { - Type: schema.TypeString, - Computed: true, - Description: "The unique identifier for the entity that created the secret.", - }, - "auto_rotated": { - Type: schema.TypeBool, - Computed: true, - Description: "Indicates whether the version of the secret was created by automatic rotation.", - }, - }, - }, - }, - "expiration_date": { - Type: schema.TypeString, - Computed: true, - Description: "The date the secret material expires. The date format follows RFC 3339.You can set an expiration date on supported secret types at their creation. If you create a secret without specifying an expiration date, the secret does not expire. The `expiration_date` field is supported for the following secret types:- `arbitrary`- `username_password`.", - }, - "payload": { - Type: schema.TypeString, - Computed: true, - Sensitive: true, - Description: "The new secret data to assign to an `arbitrary` secret.", - }, - "secret_data": { - Type: schema.TypeMap, - Sensitive: true, - Computed: true, - Description: "The secret data object", - }, - "username": { - Type: schema.TypeString, - Computed: true, - Sensitive: true, - Description: "The username to assign to this secret.", - }, - "password": { - Type: schema.TypeString, - Computed: true, - Sensitive: true, - Description: "The password to assign to this secret.", - }, - "next_rotation_date": { - Type: schema.TypeString, - Computed: true, - Description: "The date that the secret is scheduled for automatic rotation.The service automatically creates a new version of the secret on its next rotation date. This field exists only for secrets that can be auto-rotated and have an existing rotation policy.", - }, - "ttl": { - Type: schema.TypeString, - Computed: true, - Description: "The time-to-live (TTL) or lease duration to assign to generated credentials.For `iam_credentials` secrets, the TTL defines for how long each generated API key remains valid. The value can be either an integer that specifies the number of seconds, or the string representation of a duration, such as `120m` or `24h`.", - }, - "access_groups": { - Type: schema.TypeList, - Computed: true, - Description: "The access groups that define the capabilities of the service ID and API key that are generated for an`iam_credentials` secret.**Tip:** To find the ID of an access group, go to **Manage > Access (IAM) > Access groups** in the IBM Cloud console. Select the access group to inspect, and click **Details** to view its ID.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "api_key": { - Type: schema.TypeString, - Computed: true, - Sensitive: true, - Description: "The API key that is generated for this secret.After the secret reaches the end of its lease (see the `ttl` field), the API key is deleted automatically. If you want to continue to use the same API key for future read operations, see the `reuse_api_key` field.", - }, - "service_id": { - Type: schema.TypeString, - Computed: true, - Description: "The service ID under which the API key (see the `api_key` field) is created. This service ID is added to the access groups that you assign for this secret.", - }, - "reuse_api_key": { - Type: schema.TypeBool, - Computed: true, - Description: "(IAM credentials) Reuse the service ID and API key for future read operations.", - }, - }, - } -} - -func DataSourceIBMSecretsManagerSecretValidator() *validate.ResourceValidator { - - validateSchema := make([]validate.ValidateSchema, 0) - secretType := "arbitrary,iam_credentials,imported_cert,public_cert,private_cert,username_password,kv" - endpointType := "public, private" - validateSchema = append(validateSchema, - validate.ValidateSchema{ - Identifier: "secret_type", - ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, - Type: validate.TypeString, - Required: true, - AllowedValues: secretType}) - validateSchema = append(validateSchema, - validate.ValidateSchema{ - Identifier: "endpoint_type", - ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, - Type: validate.TypeString, - Optional: true, - AllowedValues: endpointType}) - - ibmSecretsManagerSecretdatasourceValidator := validate.ResourceValidator{ResourceName: "ibm_secrets_manager_secret", Schema: validateSchema} - return &ibmSecretsManagerSecretdatasourceValidator -} - -func dataSourceIBMSecretsManagerSecretRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - bluemixSession, err := meta.(conns.ClientSession).BluemixSession() - if err != nil { - return diag.FromErr(err) - } - region := bluemixSession.Config.Region - - secretsManagerClient, err := meta.(conns.ClientSession).SecretsManagerV1() - if err != nil { - return diag.FromErr(err) - } - rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() - if err != nil { - return diag.FromErr(err) - } - instanceID := d.Get("instance_id").(string) - endpointType := d.Get("endpoint_type").(string) - var smEndpointURL string - resourceInstanceOptions := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - instanceData, resp, err := rsConClient.GetResourceInstance(&resourceInstanceOptions) - if err != nil { - return diag.FromErr(fmt.Errorf("[ERROR] Error:%s Response: %s", err, resp)) - } - instanceCRN := instanceData.CRN - - crnData := strings.Split(*instanceCRN, ":") - - if crnData[4] == "secrets-manager" { - if endpointType == "private" { - smEndpointURL = "https://" + instanceID + ".private." + region + ".secrets-manager.appdomain.cloud" - } else { - smEndpointURL = "https://" + instanceID + "." + region + ".secrets-manager.appdomain.cloud" - } - smUrl := conns.EnvFallBack([]string{"IBMCLOUD_SECRETS_MANAGER_API_ENDPOINT"}, smEndpointURL) - secretsManagerClient.Service.Options.URL = smUrl - } else { - return diag.FromErr(fmt.Errorf("[ERROR] Invalid or unsupported service Instance")) - } - - secretType := d.Get("secret_type").(string) - secretID := d.Get("secret_id").(string) - getSecretOptions := &secretsmanagerv1.GetSecretOptions{ - SecretType: &secretType, - ID: &secretID, - } - - getSecret, response, err := secretsManagerClient.GetSecret(getSecretOptions) - if err != nil { - log.Printf("[DEBUG] GetSecret failed %s\n%s", err, response) - return diag.FromErr(err) - } - - d.SetId(dataSourceIBMSecretsManagerSecretID(d)) - - if getSecret.Metadata != nil { - err = d.Set("metadata", dataSourceGetSecretFlattenMetadata(*getSecret.Metadata)) - if err != nil { - return diag.FromErr(fmt.Errorf("[ERROR] Error setting metadata %s", err)) - } - } - - if getSecret.Resources != nil { - for _, resourcesItem := range getSecret.Resources { - if ritem, ok := resourcesItem.(*secretsmanagerv1.SecretResource); ok { - //if ritem.Type != nil { - // d.Set("type", *ritem.Type) - //} - if ritem.Name != nil { - d.Set("name", *ritem.Name) - } - if ritem.Description != nil { - d.Set("description", *ritem.Description) - } - if ritem.SecretGroupID != nil { - d.Set("secret_group_id", *ritem.SecretGroupID) - } - if ritem.Labels != nil { - d.Set("labels", ritem.Labels) - } - if ritem.State != nil { - d.Set("state", *ritem.State) - } - if ritem.StateDescription != nil { - d.Set("state_description", *ritem.StateDescription) - } - if ritem.CRN != nil { - d.Set("crn", *ritem.CRN) - } - if ritem.CreationDate != nil { - d.Set("creation_date", (*ritem.CreationDate).String()) - } - if ritem.CreatedBy != nil { - d.Set("created_by", *ritem.CreatedBy) - } - if ritem.LastUpdateDate != nil { - d.Set("last_update_date", (*ritem.LastUpdateDate).String()) - } - if ritem.Versions != nil { - versionsList := []map[string]interface{}{} - for _, versionsItem := range ritem.Versions { - versionsList = append(versionsList, dataSourceGetSecretResourcesVersionsToMap(versionsItem)) - } - d.Set("versions", versionsList) - } - if ritem.SecretData != nil { - secretData := ritem.SecretData - d.Set("secret_data", secretData) - if *ritem.SecretType == "username_password" { - d.Set("username", secretData["username"].(string)) - d.Set("password", secretData["password"].(string)) - } else if *ritem.SecretType == "arbitrary" { - d.Set("payload", secretData["payload"].(string)) - } - } - if ritem.NextRotationDate != nil { - d.Set("next_rotation_date", (*ritem.NextRotationDate).String()) - } - if ritem.TTL != nil { - d.Set("ttl", fmt.Sprintf("%v", ritem.TTL)) - } - if ritem.AccessGroups != nil { - d.Set("access_groups", ritem.AccessGroups) - } - if ritem.APIKey != nil { - d.Set("api_key", *ritem.APIKey) - } - if ritem.ServiceID != nil { - d.Set("service_id", *ritem.ServiceID) - } - if ritem.ReuseAPIKey != nil { - d.Set("reuse_api_key", *ritem.ReuseAPIKey) - } - } - } - } - - return nil -} - -// dataSourceIBMSecretsManagerSecretID returns a reasonable ID for the list. -func dataSourceIBMSecretsManagerSecretID(d *schema.ResourceData) string { - return time.Now().UTC().String() -} - -func dataSourceGetSecretFlattenMetadata(result secretsmanagerv1.CollectionMetadata) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceGetSecretMetadataToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceGetSecretMetadataToMap(metadataItem secretsmanagerv1.CollectionMetadata) (metadataMap map[string]interface{}) { - metadataMap = map[string]interface{}{} - - if metadataItem.CollectionType != nil { - metadataMap["collection_type"] = metadataItem.CollectionType - } - if metadataItem.CollectionTotal != nil { - metadataMap["collection_total"] = metadataItem.CollectionTotal - } - - return metadataMap -} - -func dataSourceGetSecretResourcesVersionsToMap(versionsItem map[string]interface{}) (versionsMap map[string]interface{}) { - versionsMap = map[string]interface{}{} - - if id, ok := versionsItem["id"]; ok { - versionsMap["id"] = id - } - if creation_date, ok := versionsItem["creation_date"]; ok { - versionsMap["creation_date"] = creation_date - } - if created_by, ok := versionsItem["created_by"]; ok { - versionsMap["created_by"] = created_by - } - if rotated, ok := versionsItem["auto_rotated"]; ok { - versionsMap["auto_rotated"] = rotated - } - - return versionsMap -} diff --git a/ibm/service/secretsmanager/data_source_ibm_secrets_manager_secret_test.go b/ibm/service/secretsmanager/data_source_ibm_secrets_manager_secret_test.go deleted file mode 100644 index d5cbd1b566..0000000000 --- a/ibm/service/secretsmanager/data_source_ibm_secrets_manager_secret_test.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package secretsmanager_test - -import ( - "fmt" - "testing" - - acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMSecretsManagerSecretDataSourceBasic(t *testing.T) { - resource.Test(t, resource.TestCase{ - PreCheck: func() { acc.TestAccPreCheck(t) }, - Providers: acc.TestAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMSecretsManagerSecretDataSourceConfigBasic(), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_secrets_manager_secret.secrets_manager_secret", "secret_type", acc.SecretsManagerSecretType), - resource.TestCheckResourceAttrSet("data.ibm_secrets_manager_secret.secrets_manager_secret", "id"), - resource.TestCheckResourceAttrSet("data.ibm_secrets_manager_secret.secrets_manager_secret", "secret_type"), - resource.TestCheckResourceAttrSet("data.ibm_secrets_manager_secret.secrets_manager_secret", "secret_id"), - resource.TestCheckResourceAttrSet("data.ibm_secrets_manager_secret.secrets_manager_secret", "metadata.#"), - ), - }, - }, - }) -} - -func testAccCheckIBMSecretsManagerSecretDataSourceConfigBasic() string { - return fmt.Sprintf(` - data "ibm_secrets_manager_secret" "secrets_manager_secret" { - instance_id = "%s" - secret_type = "%s" - secret_id = "%s" - } - `, acc.SecretsManagerInstanceID, acc.SecretsManagerSecretType, acc.SecretsManagerSecretID) -} diff --git a/ibm/service/secretsmanager/data_source_ibm_secrets_manager_secrets.go b/ibm/service/secretsmanager/data_source_ibm_secrets_manager_secrets.go deleted file mode 100644 index 17c7f09f8a..0000000000 --- a/ibm/service/secretsmanager/data_source_ibm_secrets_manager_secrets.go +++ /dev/null @@ -1,499 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package secretsmanager - -import ( - "context" - "fmt" - "log" - "strings" - "time" - - "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" - "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" - "github.com/IBM/secrets-manager-go-sdk/v2/secretsmanagerv1" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func DataSourceIBMSecretsManagerSecrets() *schema.Resource { - return &schema.Resource{ - ReadContext: func(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - return diag.Errorf("Data Source Removal: Data Source ibm_secrets_manager_secrets is removed. Use ibm_sm_secrets for listing secrets") - }, - DeprecationMessage: "Data Source Removal: Data Source ibm_secrets_manager_secrets is removed. Use ibm_sm_secrets for listing secrets", - Schema: map[string]*schema.Schema{ - "instance_id": { - Type: schema.TypeString, - Required: true, - Description: "Secrets Manager instance GUID", - }, - "secret_type": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validate.InvokeDataSourceValidator("ibm_secrets_manager_secrets", "secret_type"), - Description: "The secret type. Supported options include: arbitrary, iam_credentials, username_password.", - }, - "endpoint_type": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validate.InvokeDataSourceValidator("ibm_secrets_manager_secrets", "endpoint_type"), - Description: "Endpoint Type. 'public' or 'private'", - Default: "public", - }, - "metadata": { - Type: schema.TypeList, - Computed: true, - Description: "The metadata that describes the resource array.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "collection_type": { - Type: schema.TypeString, - Computed: true, - Description: "The type of resources in the resource array.", - }, - "collection_total": { - Type: schema.TypeInt, - Computed: true, - Description: "The number of elements in the resource array.", - }, - }, - }, - }, - "secrets": { - Type: schema.TypeList, - Computed: true, - Description: "A collection of secret resources.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "type": { - Type: schema.TypeString, - Computed: true, - Description: "The MIME type that represents the secret.", - }, - "secret_id": { - Type: schema.TypeString, - Computed: true, - Description: "The v4 UUID that uniquely identifies the secret.", - }, - "name": { - Type: schema.TypeString, - Computed: true, - Description: "A human-readable alias to assign to your secret.To protect your privacy, do not use personal data, such as your name or location, as an alias for your secret.", - }, - "description": { - Type: schema.TypeString, - Computed: true, - Description: "An extended description of your secret.To protect your privacy, do not use personal data, such as your name or location, as a description for your secret.", - }, - "secret_group_id": { - Type: schema.TypeString, - Computed: true, - Description: "The v4 UUID that uniquely identifies the secret group to assign to this secret.If you omit this parameter, your secret is assigned to the `default` secret group.", - }, - "labels": { - Type: schema.TypeList, - Computed: true, - Description: "Labels that you can use to filter for secrets in your instance.Up to 30 labels can be created. Labels can be between 2-30 characters, including spaces. Special characters not permitted include the angled bracket, comma, colon, ampersand, and vertical pipe character (|).To protect your privacy, do not use personal data, such as your name or location, as a label for your secret.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "state": { - Type: schema.TypeInt, - Computed: true, - Description: "The secret state based on NIST SP 800-57. States are integers and correspond to the Pre-activation = 0, Active = 1, Suspended = 2, Deactivated = 3, and Destroyed = 5 values.", - }, - "state_description": { - Type: schema.TypeString, - Computed: true, - Description: "A text representation of the secret state.", - }, - "secret_type": { - Type: schema.TypeString, - Computed: true, - Description: "The secret type.", - }, - "crn": { - Type: schema.TypeString, - Computed: true, - Description: "The Cloud Resource Name (CRN) that uniquely identifies your Secrets Manager resource.", - }, - "creation_date": { - Type: schema.TypeString, - Computed: true, - Description: "The date the secret was created. The date format follows RFC 3339.", - }, - "created_by": { - Type: schema.TypeString, - Computed: true, - Description: "The unique identifier for the entity that created the secret.", - }, - "last_update_date": { - Type: schema.TypeString, - Computed: true, - Description: "Updates when the actual secret is modified. The date format follows RFC 3339.", - }, - "versions": { - Type: schema.TypeList, - Computed: true, - Description: "An array that contains metadata for each secret version.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - Description: "The ID of the secret version.", - }, - "creation_date": { - Type: schema.TypeString, - Computed: true, - Description: "The date that the version of the secret was created.", - }, - "created_by": { - Type: schema.TypeString, - Computed: true, - Description: "The unique identifier for the entity that created the secret.", - }, - "auto_rotated": { - Type: schema.TypeBool, - Computed: true, - Description: "Indicates whether the version of the secret was created by automatic rotation.", - }, - }, - }, - }, - "expiration_date": { - Type: schema.TypeString, - Computed: true, - Description: "The date the secret material expires. The date format follows RFC 3339.You can set an expiration date on supported secret types at their creation. If you create a secret without specifying an expiration date, the secret does not expire. The `expiration_date` field is supported for the following secret types:- `arbitrary`- `username_password`.", - }, - "payload": { - Type: schema.TypeString, - Computed: true, - Sensitive: true, - Description: "The new secret data to assign to an `arbitrary` secret.", - }, - "secret_data": { - Type: schema.TypeMap, - Sensitive: true, - Computed: true, - Description: "The secret data object", - }, - "username": { - Type: schema.TypeString, - Computed: true, - Sensitive: true, - Description: "The username to assign to this secret.", - }, - "password": { - Type: schema.TypeString, - Computed: true, - Sensitive: true, - Description: "The password to assign to this secret.", - }, - "next_rotation_date": { - Type: schema.TypeString, - Computed: true, - Description: "The date that the secret is scheduled for automatic rotation.The service automatically creates a new version of the secret on its next rotation date. This field exists only for secrets that can be auto-rotated and have an existing rotation policy.", - }, - "ttl": { - Type: schema.TypeString, - Computed: true, - Description: "The time-to-live (TTL) or lease duration to assign to generated credentials.For `iam_credentials` secrets, the TTL defines for how long each generated API key remains valid. The value can be either an integer that specifies the number of seconds, or the string representation of a duration, such as `120m` or `24h`.", - }, - "access_groups": { - Type: schema.TypeList, - Computed: true, - Description: "The access groups that define the capabilities of the service ID and API key that are generated for an`iam_credentials` secret.**Tip:** To find the ID of an access group, go to **Manage > Access (IAM) > Access groups** in the IBM Cloud console. Select the access group to inspect, and click **Details** to view its ID.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "api_key": { - Type: schema.TypeString, - Computed: true, - Sensitive: true, - Description: "The API key that is generated for this secret.After the secret reaches the end of its lease (see the `ttl` field), the API key is deleted automatically. If you want to continue to use the same API key for future read operations, see the `reuse_api_key` field.", - }, - "service_id": { - Type: schema.TypeString, - Computed: true, - Description: "The service ID under which the API key (see the `api_key` field) is created. This service ID is added to the access groups that you assign for this secret.", - }, - "reuse_api_key": { - Type: schema.TypeBool, - Computed: true, - Description: "(IAM credentials) Reuse the service ID and API key for future read operations.", - }, - }, - }, - }, - }, - } -} - -func DataSourceIBMSecretsManagerSecretsValidator() *validate.ResourceValidator { - - validateSchema := make([]validate.ValidateSchema, 0) - secretType := "arbitrary, iam_credentials, username_password" - endpointType := "public, private" - validateSchema = append(validateSchema, - validate.ValidateSchema{ - Identifier: "secret_type", - ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, - Type: validate.TypeString, - Optional: true, - AllowedValues: secretType}) - validateSchema = append(validateSchema, - validate.ValidateSchema{ - Identifier: "endpoint_type", - ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, - Type: validate.TypeString, - Optional: true, - AllowedValues: endpointType}) - - ibmSecretsManagerSecretsdatasourceValidator := validate.ResourceValidator{ResourceName: "ibm_secrets_manager_secrets", Schema: validateSchema} - return &ibmSecretsManagerSecretsdatasourceValidator -} - -func dataSourceIBMSecretsManagerSecretsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - bluemixSession, err := meta.(conns.ClientSession).BluemixSession() - if err != nil { - return diag.FromErr(err) - } - region := bluemixSession.Config.Region - - secretsManagerClient, err := meta.(conns.ClientSession).SecretsManagerV1() - if err != nil { - return diag.FromErr(err) - } - rContollerClient, err := meta.(conns.ClientSession).ResourceControllerAPIV2() - if err != nil { - return diag.FromErr(err) - } - - instanceID := d.Get("instance_id").(string) - endpointType := d.Get("endpoint_type").(string) - var smEndpointURL string - - rContollerAPI := rContollerClient.ResourceServiceInstanceV2() - - instanceData, err := rContollerAPI.GetInstance(instanceID) - if err != nil { - return diag.FromErr(err) - } - instanceCRN := instanceData.Crn.String() - - crnData := strings.Split(instanceCRN, ":") - - if crnData[4] == "secrets-manager" { - if endpointType == "private" { - smEndpointURL = "https://" + instanceID + ".private." + region + ".secrets-manager.appdomain.cloud" - } else { - smEndpointURL = "https://" + instanceID + "." + region + ".secrets-manager.appdomain.cloud" - } - smUrl := conns.EnvFallBack([]string{"IBMCLOUD_SECRETS_MANAGER_API_ENDPOINT"}, smEndpointURL) - secretsManagerClient.Service.Options.URL = smUrl - } else { - return diag.FromErr(fmt.Errorf("[ERROR] Invalid or unsupported service Instance")) - } - - listAllSecretsOptions := &secretsmanagerv1.ListAllSecretsOptions{} - - listSecrets, response, err := secretsManagerClient.ListAllSecretsWithContext(context, listAllSecretsOptions) - if err != nil { - log.Printf("[DEBUG] ListAllSecretsWithContext failed %s\n%s", err, response) - return diag.FromErr(err) - } - - // Use the provided filter argument and construct a new list with only the requested resource(s) - var matchResources []secretsmanagerv1.SecretResourceIntf - var secretType string - var suppliedFilter bool - - if v, ok := d.GetOk("secret_type"); ok { - secretType = v.(string) - suppliedFilter = true - for _, data := range listSecrets.Resources { - if rdata, ok := data.(*secretsmanagerv1.SecretResource); ok { - if *rdata.SecretType == secretType { - matchResources = append(matchResources, data) - } - } - } - } else { - matchResources = listSecrets.Resources - } - listSecrets.Resources = matchResources - - if len(listSecrets.Resources) == 0 { - return diag.FromErr(fmt.Errorf("no Resources found with secretType %s\nIf not specified, please specify more filters", secretType)) - } - - if suppliedFilter { - d.SetId(secretType) - } else { - d.SetId(dataSourceIBMSecretsManagerSecretsID(d)) - } - - if listSecrets.Metadata != nil { - err = d.Set("metadata", dataSourceListSecretsFlattenMetadata(*listSecrets.Metadata)) - if err != nil { - return diag.FromErr(fmt.Errorf("[ERROR] Error setting metadata %s", err)) - } - } - - if listSecrets.Resources != nil { - err = d.Set("secrets", dataSourceListSecretsFlattenResources(listSecrets.Resources)) - if err != nil { - return diag.FromErr(fmt.Errorf("[ERROR] Error setting resources %s", err)) - } - } - - return nil -} - -// dataSourceIBMSecretsManagerSecretsID returns a reasonable ID for the list. -func dataSourceIBMSecretsManagerSecretsID(d *schema.ResourceData) string { - return time.Now().UTC().String() -} - -func dataSourceListSecretsFlattenMetadata(result secretsmanagerv1.CollectionMetadata) (finalList []map[string]interface{}) { - finalList = []map[string]interface{}{} - finalMap := dataSourceListSecretsMetadataToMap(result) - finalList = append(finalList, finalMap) - - return finalList -} - -func dataSourceListSecretsMetadataToMap(metadataItem secretsmanagerv1.CollectionMetadata) (metadataMap map[string]interface{}) { - metadataMap = map[string]interface{}{} - - if metadataItem.CollectionType != nil { - metadataMap["collection_type"] = metadataItem.CollectionType - } - if metadataItem.CollectionTotal != nil { - metadataMap["collection_total"] = metadataItem.CollectionTotal - } - - return metadataMap -} - -func dataSourceListSecretsFlattenResources(result []secretsmanagerv1.SecretResourceIntf) (resources []map[string]interface{}) { - for _, resourcesItem := range result { - if ritem, ok := resourcesItem.(*secretsmanagerv1.SecretResource); ok { - resources = append(resources, dataSourceListSecretsResourcesToMap(*ritem)) - } - } - - return resources -} - -func dataSourceListSecretsResourcesToMap(resourcesItem secretsmanagerv1.SecretResource) (resourcesMap map[string]interface{}) { - resourcesMap = map[string]interface{}{} - - //if resourcesItem.Type != nil { - // resourcesMap["type"] = *resourcesItem.Type - //} - if resourcesItem.ID != nil { - resourcesMap["secret_id"] = *resourcesItem.ID - } - if resourcesItem.Name != nil { - resourcesMap["name"] = *resourcesItem.Name - } - if resourcesItem.Description != nil { - resourcesMap["description"] = *resourcesItem.Description - } - if resourcesItem.SecretGroupID != nil { - resourcesMap["secret_group_id"] = *resourcesItem.SecretGroupID - } - if resourcesItem.Labels != nil { - resourcesMap["labels"] = resourcesItem.Labels - } - if resourcesItem.State != nil { - resourcesMap["state"] = *resourcesItem.State - } - if resourcesItem.StateDescription != nil { - resourcesMap["state_description"] = *resourcesItem.StateDescription - } - if resourcesItem.SecretType != nil { - resourcesMap["secret_type"] = *resourcesItem.SecretType - } - if resourcesItem.CRN != nil { - resourcesMap["crn"] = *resourcesItem.CRN - } - if resourcesItem.CreationDate != nil { - resourcesMap["creation_date"] = (*resourcesItem.CreationDate).String() - } - if resourcesItem.CreatedBy != nil { - resourcesMap["created_by"] = *resourcesItem.CreatedBy - } - if resourcesItem.LastUpdateDate != nil { - resourcesMap["last_update_date"] = (*resourcesItem.LastUpdateDate).String() - } - if resourcesItem.Versions != nil { - versionsList := []map[string]interface{}{} - for _, versionsItem := range resourcesItem.Versions { - versionsList = append(versionsList, dataSourceListSecretsResourcesVersionsToMap(versionsItem)) - } - resourcesMap["versions"] = versionsList - } - if resourcesItem.ExpirationDate != nil { - resourcesMap["expiration_date"] = (*resourcesItem.ExpirationDate).String() - } - // Commented out because the response to list secrets shouldn't include payload - //if resourcesItem.Payload != nil { - // resourcesMap["payload"] = *resourcesItem.Payload - //} - if resourcesItem.SecretData != nil { - secretData := resourcesItem.SecretData - resourcesMap["secret_data"] = secretData - if *resourcesItem.SecretType == "username_password" { - resourcesMap["username"] = secretData["username"].(string) - resourcesMap["password"] = secretData["password"].(string) - } else if *resourcesItem.SecretType == "arbitrary" { - resourcesMap["payload"] = secretData["payload"].(string) - } - } - if resourcesItem.NextRotationDate != nil { - resourcesMap["next_rotation_date"] = (*resourcesItem.NextRotationDate).String() - } - if resourcesItem.TTL != nil { - resourcesMap["ttl"] = fmt.Sprintf("%v", resourcesItem.TTL) - } - if resourcesItem.AccessGroups != nil { - resourcesMap["access_groups"] = resourcesItem.AccessGroups - } - if resourcesItem.APIKey != nil { - resourcesMap["api_key"] = *resourcesItem.APIKey - } - if resourcesItem.ServiceID != nil { - resourcesMap["service_id"] = *resourcesItem.ServiceID - } - if resourcesItem.ReuseAPIKey != nil { - resourcesMap["reuse_api_key"] = *resourcesItem.ReuseAPIKey - } - - return resourcesMap -} - -func dataSourceListSecretsResourcesVersionsToMap(versionsItem map[string]interface{}) (versionsMap map[string]interface{}) { - versionsMap = map[string]interface{}{} - - if id, ok := versionsItem["id"]; ok { - versionsMap["id"] = id - } - if creation_date, ok := versionsItem["creation_date"]; ok { - versionsMap["creation_date"] = creation_date - } - if created_by, ok := versionsItem["created_by"]; ok { - versionsMap["created_by"] = created_by - } - if rotated, ok := versionsItem["auto_rotated"]; ok { - versionsMap["auto_rotated"] = rotated - } - - return versionsMap -} diff --git a/ibm/service/secretsmanager/data_source_ibm_secrets_manager_secrets_test.go b/ibm/service/secretsmanager/data_source_ibm_secrets_manager_secrets_test.go deleted file mode 100644 index 9849e835bc..0000000000 --- a/ibm/service/secretsmanager/data_source_ibm_secrets_manager_secrets_test.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package secretsmanager_test - -import ( - "fmt" - "testing" - - acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccIBMSecretsManagerSecretsDataSourceBasic(t *testing.T) { - resource.Test(t, resource.TestCase{ - PreCheck: func() { acc.TestAccPreCheck(t) }, - Providers: acc.TestAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMSecretsManagerSecretsDataSourceConfigBasic(), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.ibm_secrets_manager_secrets.secrets_manager_secrets", "secret_type", acc.SecretsManagerSecretType), - resource.TestCheckResourceAttrSet("data.ibm_secrets_manager_secrets.secrets_manager_secrets", "id"), - resource.TestCheckResourceAttrSet("data.ibm_secrets_manager_secrets.secrets_manager_secrets", "secret_type"), - resource.TestCheckResourceAttrSet("data.ibm_secrets_manager_secrets.secrets_manager_secrets", "metadata.#"), - resource.TestCheckResourceAttrSet("data.ibm_secrets_manager_secrets.secrets_manager_secrets", "secrets.#"), - ), - }, - }, - }) -} - -func testAccCheckIBMSecretsManagerSecretsDataSourceConfigBasic() string { - return fmt.Sprintf(` - data "ibm_secrets_manager_secrets" "secrets_manager_secrets" { - instance_id = "%s" - secret_type = "%s" - } - - output "WorkSpaceValues" { - value = data.ibm_secrets_manager_secrets.secrets_manager_secrets.secret_type - } - `, acc.SecretsManagerInstanceID, acc.SecretsManagerSecretType) -} diff --git a/ibm/service/secretsmanager/data_source_ibm_sm_service_credentials_secret.go b/ibm/service/secretsmanager/data_source_ibm_sm_service_credentials_secret.go index bc5c17a8c9..c9f1158134 100644 --- a/ibm/service/secretsmanager/data_source_ibm_sm_service_credentials_secret.go +++ b/ibm/service/secretsmanager/data_source_ibm_sm_service_credentials_secret.go @@ -415,7 +415,7 @@ func dataSourceIbmSmServiceCredentialsSecretRotationPolicyToMap(model *secretsma return modelMap, nil } -func dataSourceIbmSmServiceCredentialsSecretSourceServiceToMap(sourceService *secretsmanagerv2.ServiceCredentialsSecretSourceService) (map[string]interface{}, error) { +func dataSourceIbmSmServiceCredentialsSecretSourceServiceToMap(sourceService *secretsmanagerv2.ServiceCredentialsSecretSourceServiceRO) (map[string]interface{}, error) { mainModelMap := make(map[string]interface{}) if sourceService.Instance != nil { instanceMap := make(map[string]interface{}) diff --git a/ibm/service/secretsmanager/data_source_ibm_sm_service_credentials_secret_metadata.go b/ibm/service/secretsmanager/data_source_ibm_sm_service_credentials_secret_metadata.go index 141e0f9e6d..9b28662a5a 100644 --- a/ibm/service/secretsmanager/data_source_ibm_sm_service_credentials_secret_metadata.go +++ b/ibm/service/secretsmanager/data_source_ibm_sm_service_credentials_secret_metadata.go @@ -403,7 +403,7 @@ func dataSourceIbmSmServiceCredentialsSecretMetadataRotationPolicyToMap(model *s return modelMap, nil } -func dataSourceIbmSmServiceCredentialsSecretMetadataSourceServiceToMap(sourceService *secretsmanagerv2.ServiceCredentialsSecretSourceService) (map[string]interface{}, error) { +func dataSourceIbmSmServiceCredentialsSecretMetadataSourceServiceToMap(sourceService *secretsmanagerv2.ServiceCredentialsSecretSourceServiceRO) (map[string]interface{}, error) { mainModelMap := make(map[string]interface{}) if sourceService.Instance != nil { instanceMap := make(map[string]interface{}) diff --git a/ibm/service/secretsmanager/data_source_ibm_sm_username_password_secret.go b/ibm/service/secretsmanager/data_source_ibm_sm_username_password_secret.go index a1119f17e0..262b037ad5 100644 --- a/ibm/service/secretsmanager/data_source_ibm_sm_username_password_secret.go +++ b/ibm/service/secretsmanager/data_source_ibm_sm_username_password_secret.go @@ -115,6 +115,35 @@ func DataSourceIbmSmUsernamePasswordSecret() *schema.Resource { Computed: true, Description: "The number of versions of the secret.", }, + "password_generation_policy": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Policy for auto-generated passwords.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "length": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The length of auto-generated passwords.", + }, + "include_digits": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Include digits in auto-generated passwords.", + }, + "include_symbols": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Include symbols in auto-generated passwords.", + }, + "include_uppercase": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Include uppercase letters in auto-generated passwords.", + }, + }, + }, + }, "rotation": &schema.Schema{ Type: schema.TypeList, Computed: true, @@ -257,6 +286,18 @@ func dataSourceIbmSmUsernamePasswordSecretRead(context context.Context, d *schem return diag.FromErr(fmt.Errorf("Error setting rotation %s", err)) } + passwordPolicy := []map[string]interface{}{} + if usernamePasswordSecret.PasswordGenerationPolicy != nil { + modelMap, err := passwordGenerationPolicyToMap(usernamePasswordSecret.PasswordGenerationPolicy) + if err != nil { + return diag.FromErr(err) + } + passwordPolicy = append(passwordPolicy, modelMap) + } + if err = d.Set("password_generation_policy", passwordPolicy); err != nil { + return diag.FromErr(fmt.Errorf("Error setting password_generation_policy %s", err)) + } + if err = d.Set("expiration_date", DateTimeToRFC3339(usernamePasswordSecret.ExpirationDate)); err != nil { return diag.FromErr(fmt.Errorf("Error setting expiration_date: %s", err)) } diff --git a/ibm/service/secretsmanager/data_source_ibm_sm_username_password_secret_metadata.go b/ibm/service/secretsmanager/data_source_ibm_sm_username_password_secret_metadata.go index 6eada6eb8b..cc6756f00c 100644 --- a/ibm/service/secretsmanager/data_source_ibm_sm_username_password_secret_metadata.go +++ b/ibm/service/secretsmanager/data_source_ibm_sm_username_password_secret_metadata.go @@ -107,6 +107,35 @@ func DataSourceIbmSmUsernamePasswordSecretMetadata() *schema.Resource { Computed: true, Description: "The number of versions of the secret.", }, + "password_generation_policy": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Policy for auto-generated passwords.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "length": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The length of auto-generated passwords.", + }, + "include_digits": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Include digits in auto-generated passwords.", + }, + "include_symbols": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Include symbols in auto-generated passwords.", + }, + "include_uppercase": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Include uppercase letters in auto-generated passwords.", + }, + }, + }, + }, "rotation": &schema.Schema{ Type: schema.TypeList, Computed: true, @@ -251,6 +280,18 @@ func dataSourceIbmSmUsernamePasswordSecretMetadataRead(context context.Context, return diag.FromErr(fmt.Errorf("Error setting rotation %s", err)) } + passwordPolicy := []map[string]interface{}{} + if usernamePasswordSecretMetadata.PasswordGenerationPolicy != nil { + modelMap, err := passwordGenerationPolicyToMap(usernamePasswordSecretMetadata.PasswordGenerationPolicy) + if err != nil { + return diag.FromErr(err) + } + passwordPolicy = append(passwordPolicy, modelMap) + } + if err = d.Set("password_generation_policy", passwordPolicy); err != nil { + return diag.FromErr(fmt.Errorf("Error setting password_generation_policy %s", err)) + } + if err = d.Set("expiration_date", DateTimeToRFC3339(usernamePasswordSecretMetadata.ExpirationDate)); err != nil { return diag.FromErr(fmt.Errorf("Error setting expiration_date: %s", err)) } diff --git a/ibm/service/secretsmanager/data_source_ibm_sm_username_password_secret_metadata_test.go b/ibm/service/secretsmanager/data_source_ibm_sm_username_password_secret_metadata_test.go index dff01d9be9..2cfc9639df 100644 --- a/ibm/service/secretsmanager/data_source_ibm_sm_username_password_secret_metadata_test.go +++ b/ibm/service/secretsmanager/data_source_ibm_sm_username_password_secret_metadata_test.go @@ -30,6 +30,7 @@ func TestAccIbmSmUsernamePasswordSecretMetadataDataSourceBasic(t *testing.T) { resource.TestCheckResourceAttrSet("data.ibm_sm_username_password_secret_metadata.sm_username_password_secret_metadata", "updated_at"), resource.TestCheckResourceAttrSet("data.ibm_sm_username_password_secret_metadata.sm_username_password_secret_metadata", "versions_total"), resource.TestCheckResourceAttrSet("data.ibm_sm_username_password_secret_metadata.sm_username_password_secret_metadata", "rotation.#"), + resource.TestCheckResourceAttrSet("data.ibm_sm_username_password_secret_metadata.sm_username_password_secret_metadata", "password_generation_policy.#"), ), }, }, diff --git a/ibm/service/secretsmanager/data_source_ibm_sm_username_password_secret_test.go b/ibm/service/secretsmanager/data_source_ibm_sm_username_password_secret_test.go index 57c04216e8..0a59be3abd 100644 --- a/ibm/service/secretsmanager/data_source_ibm_sm_username_password_secret_test.go +++ b/ibm/service/secretsmanager/data_source_ibm_sm_username_password_secret_test.go @@ -30,6 +30,7 @@ func TestAccIbmSmUsernamePasswordSecretDataSourceBasic(t *testing.T) { resource.TestCheckResourceAttrSet("data.ibm_sm_username_password_secret.sm_username_password_secret", "updated_at"), resource.TestCheckResourceAttrSet("data.ibm_sm_username_password_secret.sm_username_password_secret", "versions_total"), resource.TestCheckResourceAttrSet("data.ibm_sm_username_password_secret.sm_username_password_secret", "rotation.#"), + resource.TestCheckResourceAttrSet("data.ibm_sm_username_password_secret.sm_username_password_secret", "password_generation_policy.#"), resource.TestCheckResourceAttrSet("data.ibm_sm_username_password_secret.sm_username_password_secret", "username"), resource.TestCheckResourceAttrSet("data.ibm_sm_username_password_secret.sm_username_password_secret", "password"), resource.TestCheckResourceAttrSet("data.ibm_sm_username_password_secret.sm_username_password_secret_by_name", "name"), diff --git a/ibm/service/secretsmanager/resource_ibm_sm_public_certificate.go b/ibm/service/secretsmanager/resource_ibm_sm_public_certificate.go index 61b5575d97..8cbd049687 100644 --- a/ibm/service/secretsmanager/resource_ibm_sm_public_certificate.go +++ b/ibm/service/secretsmanager/resource_ibm_sm_public_certificate.go @@ -635,21 +635,24 @@ func resourceIbmSmPublicCertificateRead(context context.Context, d *schema.Resou if err = d.Set("private_key", secret.PrivateKey); err != nil { return diag.FromErr(fmt.Errorf("Error setting private_key: %s", err)) } - // Call get version metadata API to get the current version_custom_metadata - getVersionMetdataOptions := &secretsmanagerv2.GetSecretVersionMetadataOptions{} - getVersionMetdataOptions.SetSecretID(secretId) - getVersionMetdataOptions.SetID("current") - versionMetadataIntf, response, err := secretsManagerClient.GetSecretVersionMetadataWithContext(context, getVersionMetdataOptions) - if err != nil { - log.Printf("[DEBUG] GetSecretVersionMetadataWithContext failed %s\n%s", err, response) - return diag.FromErr(fmt.Errorf("GetSecretVersionMetadataWithContext failed %s\n%s", err, response)) - } + if *secret.StateDescription == "active" { + // Call get version metadata API to get the current version_custom_metadata + getVersionMetdataOptions := &secretsmanagerv2.GetSecretVersionMetadataOptions{} + getVersionMetdataOptions.SetSecretID(secretId) + getVersionMetdataOptions.SetID("current") + + versionMetadataIntf, response, err := secretsManagerClient.GetSecretVersionMetadataWithContext(context, getVersionMetdataOptions) + if err != nil { + log.Printf("[DEBUG] GetSecretVersionMetadataWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetSecretVersionMetadataWithContext failed %s\n%s", err, response)) + } - versionMetadata := versionMetadataIntf.(*secretsmanagerv2.PublicCertificateVersionMetadata) - if versionMetadata.VersionCustomMetadata != nil { - if err = d.Set("version_custom_metadata", versionMetadata.VersionCustomMetadata); err != nil { - return diag.FromErr(fmt.Errorf("Error setting version_custom_metadata: %s", err)) + versionMetadata := versionMetadataIntf.(*secretsmanagerv2.PublicCertificateVersionMetadata) + if versionMetadata.VersionCustomMetadata != nil { + if err = d.Set("version_custom_metadata", versionMetadata.VersionCustomMetadata); err != nil { + return diag.FromErr(fmt.Errorf("Error setting version_custom_metadata: %s", err)) + } } } diff --git a/ibm/service/secretsmanager/resource_ibm_sm_service_credentials_secret.go b/ibm/service/secretsmanager/resource_ibm_sm_service_credentials_secret.go index 8beb6980d2..a48a3d2636 100644 --- a/ibm/service/secretsmanager/resource_ibm_sm_service_credentials_secret.go +++ b/ibm/service/secretsmanager/resource_ibm_sm_service_credentials_secret.go @@ -698,7 +698,7 @@ func resourceIbmSmServiceCredentialsSecretRotationPolicyToMap(modelIntf secretsm return modelMap, nil } -func resourceIbmSmServiceCredentialsSecretSourceServiceToMap(sourceService *secretsmanagerv2.ServiceCredentialsSecretSourceService) (map[string]interface{}, error) { +func resourceIbmSmServiceCredentialsSecretSourceServiceToMap(sourceService *secretsmanagerv2.ServiceCredentialsSecretSourceServiceRO) (map[string]interface{}, error) { mainModelMap := make(map[string]interface{}) if sourceService.Instance != nil { instanceMap := make(map[string]interface{}) diff --git a/ibm/service/secretsmanager/resource_ibm_sm_username_password_secret.go b/ibm/service/secretsmanager/resource_ibm_sm_username_password_secret.go index 5975f94dac..2a21a8935f 100644 --- a/ibm/service/secretsmanager/resource_ibm_sm_username_password_secret.go +++ b/ibm/service/secretsmanager/resource_ibm_sm_username_password_secret.go @@ -122,10 +122,46 @@ func ResourceIbmSmUsernamePasswordSecret() *schema.Resource { }, "password": &schema.Schema{ Type: schema.TypeString, - Required: true, + Optional: true, + Computed: true, Sensitive: true, Description: "The password that is assigned to the secret.", }, + "password_generation_policy": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "Policy for auto-generated passwords.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "length": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Default: 32, + Description: "The length of auto-generated passwords.", + }, + "include_digits": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: "Include digits in auto-generated passwords.", + }, + "include_symbols": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: "Include symbols in auto-generated passwords.", + }, + "include_uppercase": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: "Include uppercase letters in auto-generated passwords.", + }, + }, + }, + }, "created_by": &schema.Schema{ Type: schema.TypeString, Computed: true, @@ -354,6 +390,14 @@ func resourceIbmSmUsernamePasswordSecretRead(context context.Context, d *schema. return diag.FromErr(fmt.Errorf("Error setting password: %s", err)) } + passwordPolicyMap, err := passwordGenerationPolicyToMap(secret.PasswordGenerationPolicy) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("password_generation_policy", []map[string]interface{}{passwordPolicyMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting password generation policy: %s", err)) + } + // Call get version metadata API to get the current version_custom_metadata getVersionMetdataOptions := &secretsmanagerv2.GetSecretVersionMetadataOptions{} getVersionMetdataOptions.SetSecretID(secretId) @@ -441,6 +485,16 @@ func resourceIbmSmUsernamePasswordSecretUpdate(context context.Context, d *schem } } + if d.HasChange("password_generation_policy") { + passwordPolicyModel, err := mapToPasswordGenerationPolicyPatch(d.Get("password_generation_policy").([]interface{})[0].(map[string]interface{})) + if err != nil { + log.Printf("[DEBUG] UpdateSecretMetadataWithContext failed: Reading password_generation_policy parameter failed: %s", err) + return diag.FromErr(fmt.Errorf("UpdateSecretMetadataWithContext failed: Reading password_generation_policy parameter failed: %s", err)) + } + patchVals.PasswordGenerationPolicy = passwordPolicyModel + hasChange = true + } + if hasChange { updateSecretMetadataOptions.SecretMetadataPatch, _ = patchVals.AsPatch() _, response, err := secretsManagerClient.UpdateSecretMetadataWithContext(context, updateSecretMetadataOptions) @@ -574,6 +628,13 @@ func resourceIbmSmUsernamePasswordSecretMapToSecretPrototype(d *schema.ResourceD } model.Rotation = RotationModel } + if _, ok := d.GetOk("password_generation_policy"); ok { + passwordPolicyModel, err := mapToPasswordGenerationPolicy(d.Get("password_generation_policy").([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.PasswordGenerationPolicy = passwordPolicyModel + } return model, nil } @@ -635,3 +696,58 @@ func rotationAttributesDiffSuppress(key, oldValue, newValue string, d *schema.Re return oldValue == newValue } + +func passwordGenerationPolicyToMap(model *secretsmanagerv2.PasswordGenerationPolicyRO) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Length != nil { + modelMap["length"] = model.Length + } + if model.IncludeDigits != nil { + modelMap["include_digits"] = model.IncludeDigits + } + if model.IncludeSymbols != nil { + modelMap["include_symbols"] = model.IncludeSymbols + } + if model.IncludeUppercase != nil { + modelMap["include_uppercase"] = model.IncludeUppercase + } + return modelMap, nil +} + +func mapToPasswordGenerationPolicy(modelMap map[string]interface{}) (*secretsmanagerv2.PasswordGenerationPolicy, error) { + model := &secretsmanagerv2.PasswordGenerationPolicy{} + if modelMap["length"].(int) == 0 { + model.Length = nil + } else { + model.Length = core.Int64Ptr(int64(modelMap["length"].(int))) + } + if modelMap["include_digits"] != nil { + model.IncludeDigits = core.BoolPtr(modelMap["include_digits"].(bool)) + } + if modelMap["include_symbols"] != nil { + model.IncludeSymbols = core.BoolPtr(modelMap["include_symbols"].(bool)) + } + if modelMap["include_uppercase"] != nil { + model.IncludeUppercase = core.BoolPtr(modelMap["include_uppercase"].(bool)) + } + return model, nil +} + +func mapToPasswordGenerationPolicyPatch(modelMap map[string]interface{}) (*secretsmanagerv2.PasswordGenerationPolicyPatch, error) { + model := &secretsmanagerv2.PasswordGenerationPolicyPatch{} + if modelMap["length"].(int) == 0 { + model.Length = nil + } else { + model.Length = core.Int64Ptr(int64(modelMap["length"].(int))) + } + if modelMap["include_digits"] != nil { + model.IncludeDigits = core.BoolPtr(modelMap["include_digits"].(bool)) + } + if modelMap["include_symbols"] != nil { + model.IncludeSymbols = core.BoolPtr(modelMap["include_symbols"].(bool)) + } + if modelMap["include_uppercase"] != nil { + model.IncludeUppercase = core.BoolPtr(modelMap["include_uppercase"].(bool)) + } + return model, nil +} diff --git a/ibm/service/secretsmanager/resource_ibm_sm_username_password_secret_test.go b/ibm/service/secretsmanager/resource_ibm_sm_username_password_secret_test.go index e7fbfada20..2a3a9de876 100644 --- a/ibm/service/secretsmanager/resource_ibm_sm_username_password_secret_test.go +++ b/ibm/service/secretsmanager/resource_ibm_sm_username_password_secret_test.go @@ -4,6 +4,7 @@ package secretsmanager_test import ( + "encoding/json" "fmt" "strings" "testing" @@ -22,6 +23,21 @@ var password = "password" var modifiedPassword = "modified_password" var usernamePasswordSecretName = "terraform-test-username-secret" var modifiedUsernamePasswordSecretName = "modified-terraform-test-username-secret" +var passwordGenerationPolicy = `{ + length = 17 + include_digits = false + include_symbols = false + include_uppercase = true + }` +var passwordGenerationPolicyJSON = "{\"length\":17,\"include_digits\":false,\"include_symbols\":false,\"include_uppercase\":true}" + +var modifiedPasswordGenerationPolicy = `{ + length = 26 + include_digits = true + include_symbols = true + include_uppercase = false + }` +var modifiedPasswordGenerationPolicyJSON = "{\"length\":26,\"include_digits\":true,\"include_symbols\":true,\"include_uppercase\":false}" func TestAccIbmSmUsernamePasswordSecretBasic(t *testing.T) { resourceName := "ibm_sm_username_password_secret.sm_username_password_secret_basic" @@ -113,6 +129,7 @@ var usernamePasswordSecretFullConfigFormat = ` custom_metadata = %s secret_group_id = "default" rotation %s + password_generation_policy %s }` func usernamePasswordSecretConfigBasic() string { @@ -122,13 +139,14 @@ func usernamePasswordSecretConfigBasic() string { func usernamePasswordSecretConfigAllArgs() string { return fmt.Sprintf(usernamePasswordSecretFullConfigFormat, acc.SecretsManagerInstanceID, acc.SecretsManagerInstanceRegion, - usernamePasswordSecretName, description, label, username, password, expirationDate, customMetadata, rotationPolicy) + usernamePasswordSecretName, description, label, username, password, expirationDate, customMetadata, rotationPolicy, + passwordGenerationPolicy) } func usernamePasswordSecretConfigUpdated() string { return fmt.Sprintf(usernamePasswordSecretFullConfigFormat, acc.SecretsManagerInstanceID, acc.SecretsManagerInstanceRegion, modifiedUsernamePasswordSecretName, modifiedDescription, modifiedLabel, modifiedUsername, modifiedPassword, - modifiedExpirationDate, modifiedCustomMetadata, modifiedRotationPolicy) + modifiedExpirationDate, modifiedCustomMetadata, modifiedRotationPolicy, modifiedPasswordGenerationPolicy) } func testAccCheckIbmSmUsernamePasswordSecretCreated(n string) resource.TestCheckFunc { @@ -166,6 +184,10 @@ func testAccCheckIbmSmUsernamePasswordSecretCreated(n string) resource.TestCheck if err := verifyAttr(getAutoRotate(secret.Rotation), "true", "auto_rotate"); err != nil { return err } + pwdPolicyJson, _ := json.Marshal(secret.PasswordGenerationPolicy) + if err := verifyAttr(string(pwdPolicyJson), passwordGenerationPolicyJSON, "password_generation_policy"); err != nil { + return err + } if err := verifyAttr(getRotationUnit(secret.Rotation), "day", "rotation unit"); err != nil { return err } @@ -217,6 +239,10 @@ func testAccCheckIbmSmUsernamePasswordSecretUpdated(n string) resource.TestCheck if err := verifyAttr(getRotationInterval(secret.Rotation), "2", "rotation interval after update"); err != nil { return err } + pwdPolicyJson, _ := json.Marshal(secret.PasswordGenerationPolicy) + if err := verifyAttr(string(pwdPolicyJson), modifiedPasswordGenerationPolicyJSON, "password_generation_policy"); err != nil { + return err + } return nil } } 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 949e730849..61bf02c0fb 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 @@ -194,9 +194,9 @@ func DataSourceIBMIsBareMetalServer() *schema.Resource { Computed: true, }, isBareMetalServerNicHref: { - Type: schema.TypeString, - Computed: true, - Deprecated: "This URL of the interface", + Type: schema.TypeString, + Computed: true, + Description: "This URL of the interface", }, isBareMetalServerNicSecurityGroups: { @@ -247,6 +247,145 @@ func DataSourceIBMIsBareMetalServer() *schema.Resource { }, }, + "primary_network_attachment": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The primary 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 network attachment.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this network attachment.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "primary_ip": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The primary IP address of the virtual network interface for the network attachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "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 reserved IP.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this reserved IP. The name is unique across all reserved IPs in a 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, + Description: "The subnet of the virtual network interface for the network attachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this subnet.", + }, + "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 subnet.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this subnet.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this subnet. The name is unique across all subnets in the VPC.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + }, + }, + }, + isBareMetalServerNetworkInterfaces: { Type: schema.TypeList, Computed: true, @@ -318,6 +457,145 @@ func DataSourceIBMIsBareMetalServer() *schema.Resource { }, }, + "network_attachments": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The network attachments for this bare metal server, including the primary 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 network attachment.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this network attachment.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "primary_ip": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The primary IP address of the virtual network interface for the network attachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "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 reserved IP.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this reserved IP. The name is unique across all reserved IPs in a 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, + Description: "The subnet of the virtual network interface for the network attachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this subnet.", + }, + "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 subnet.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this subnet.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this subnet. The name is unique across all subnets in the VPC.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + }, + }, + }, + isBareMetalServerKeys: { Type: schema.TypeSet, Computed: true, @@ -643,6 +921,18 @@ func dataSourceIBMISBareMetalServerRead(context context.Context, d *schema.Resou d.Set(isBareMetalServerPrimaryNetworkInterface, primaryNicList) } + primaryNetworkAttachment := []map[string]interface{}{} + if bms.PrimaryNetworkAttachment != nil { + modelMap, err := dataSourceIBMIsBareMetalServerBareMetalServerNetworkAttachmentReferenceToMap(bms.PrimaryNetworkAttachment) + if err != nil { + return diag.FromErr(err) + } + primaryNetworkAttachment = append(primaryNetworkAttachment, modelMap) + } + if err = d.Set("primary_network_attachment", primaryNetworkAttachment); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting primary_network_attachment %s", err)) + } + //ni interfacesList := make([]map[string]interface{}, 0) @@ -728,6 +1018,22 @@ func dataSourceIBMISBareMetalServerRead(context context.Context, d *schema.Resou } d.Set(isBareMetalServerNetworkInterfaces, interfacesList) + networkAttachments := []map[string]interface{}{} + if bms.NetworkAttachments != nil { + for _, modelItem := range bms.NetworkAttachments { + if *bms.PrimaryNetworkAttachment.ID != *modelItem.ID { + modelMap, err := dataSourceIBMIsBareMetalServerBareMetalServerNetworkAttachmentReferenceToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + networkAttachments = append(networkAttachments, modelMap) + } + } + } + if err = d.Set("network_attachments", networkAttachments); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting network_attachments %s", err)) + } + if err = d.Set(isBareMetalServerProfile, *bms.Profile.Name); err != nil { return diag.FromErr(fmt.Errorf("[ERROR] Error setting profile: %s", err)) } @@ -779,3 +1085,81 @@ func dataSourceIBMISBareMetalServerRead(context context.Context, d *schema.Resou return nil } + +func dataSourceIBMIsBareMetalServerBareMetalServerNetworkAttachmentReferenceToMap(model *vpcv1.BareMetalServerNetworkAttachmentReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Deleted != nil { + deletedMap, err := dataSourceIBMIsBareMetalServerBareMetalServerNetworkAttachmentReferenceDeletedToMap(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 := dataSourceIBMIsBareMetalServerReservedIPReferenceToMap(model.PrimaryIP) + if err != nil { + return modelMap, err + } + modelMap["primary_ip"] = []map[string]interface{}{primaryIPMap} + modelMap["resource_type"] = model.ResourceType + subnetMap, err := dataSourceIBMIsBareMetalServerSubnetReferenceToMap(model.Subnet) + if err != nil { + return modelMap, err + } + modelMap["subnet"] = []map[string]interface{}{subnetMap} + return modelMap, nil +} + +func dataSourceIBMIsBareMetalServerBareMetalServerNetworkAttachmentReferenceDeletedToMap(model *vpcv1.BareMetalServerNetworkAttachmentReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = model.MoreInfo + return modelMap, nil +} + +func dataSourceIBMIsBareMetalServerReservedIPReferenceToMap(model *vpcv1.ReservedIPReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["address"] = model.Address + if model.Deleted != nil { + deletedMap, err := dataSourceIBMIsBareMetalServerReservedIPReferenceDeletedToMap(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 dataSourceIBMIsBareMetalServerReservedIPReferenceDeletedToMap(model *vpcv1.ReservedIPReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = model.MoreInfo + return modelMap, nil +} + +func dataSourceIBMIsBareMetalServerSubnetReferenceToMap(model *vpcv1.SubnetReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = model.CRN + if model.Deleted != nil { + deletedMap, err := dataSourceIBMIsBareMetalServerSubnetReferenceDeletedToMap(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 dataSourceIBMIsBareMetalServerSubnetReferenceDeletedToMap(model *vpcv1.SubnetReferenceDeleted) (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_bare_metal_server_network_attachment.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_attachment.go new file mode 100644 index 0000000000..846656eb1e --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_attachment.go @@ -0,0 +1,386 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsBareMetalServerNetworkAttachment() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsBareMetalServerNetworkAttachmentRead, + + Schema: map[string]*schema.Schema{ + "bare_metal_server": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The bare metal server identifier.", + }, + "network_attachment": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The bare metal server network attachment identifier.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the bare metal server network attachment was created.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this bare metal server network attachment.", + }, + "bare_metal_server_network_attachment_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this bare metal server network attachment.", + }, + "interface_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The network attachment's interface type:- `hipersocket`: a virtual network device that provides high-speed TCP/IP connectivity within a `s390x` based system- `pci`: a physical PCI device which can only be created or deleted when the bare metal server is stopped - Has an `allowed_vlans` property which controls the VLANs that will be permitted to use the PCI attachment - Cannot directly use an IEEE 802.1q VLAN tag.- `vlan`: a virtual device, used through a `pci` device that has the `vlan` in its array of `allowed_vlans`. - Must use an IEEE 802.1q tag.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the bare metal server network attachment.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this bare metal server network attachment. The name is unique across all network attachments for the bare metal server.", + }, + "port_speed": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The port speed for this bare metal server network attachment in Mbps.", + }, + "primary_ip": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The primary IP address of the virtual network interface for the bare metal servernetwork attachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "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 reserved IP.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this reserved IP. The name is unique across all reserved IPs in a 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, + Description: "The subnet of the virtual network interface for the bare metal server networkattachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this subnet.", + }, + "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 subnet.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this subnet.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this subnet. The name is unique across all subnets in the VPC.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The bare metal server network attachment type.", + }, + "virtual_network_interface": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The virtual network interface for this bare metal server network attachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this virtual network interface.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this virtual network interface.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this virtual network interface.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this virtual network interface. The name is unique across all virtual network interfaces in the VPC.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "allowed_vlans": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeInt, + }, + }, + "allow_to_float": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates if the bare metal server network attachment can automatically float to any other server within the same `resource_group`. The bare metal server network attachment will float automatically if the network detects a GARP or RARP on another bare metal server in the resource group. Applies only to bare metal server network attachments with `vlan` interface type.", + }, + "vlan": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Indicates the 802.1Q VLAN ID tag that must be used for all traffic on this attachment.", + }, + }, + } +} + +func dataSourceIBMIsBareMetalServerNetworkAttachmentRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + getBareMetalServerNetworkAttachmentOptions := &vpcv1.GetBareMetalServerNetworkAttachmentOptions{} + + getBareMetalServerNetworkAttachmentOptions.SetBareMetalServerID(d.Get("bare_metal_server").(string)) + getBareMetalServerNetworkAttachmentOptions.SetID(d.Get("network_attachment").(string)) + + bareMetalServerNetworkAttachmentIntf, response, err := vpcClient.GetBareMetalServerNetworkAttachmentWithContext(context, getBareMetalServerNetworkAttachmentOptions) + if err != nil { + log.Printf("[DEBUG] GetBareMetalServerNetworkAttachmentWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetBareMetalServerNetworkAttachmentWithContext failed %s\n%s", err, response)) + } + bareMetalServerNetworkAttachment := bareMetalServerNetworkAttachmentIntf.(*vpcv1.BareMetalServerNetworkAttachment) + + d.SetId(fmt.Sprintf("%s/%s", *getBareMetalServerNetworkAttachmentOptions.BareMetalServerID, *getBareMetalServerNetworkAttachmentOptions.ID)) + + if err = d.Set("created_at", flex.DateTimeToString(bareMetalServerNetworkAttachment.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + + if err = d.Set("href", bareMetalServerNetworkAttachment.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + if err = d.Set("bare_metal_server_network_attachment_id", bareMetalServerNetworkAttachment.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting bare_metal_server_network_attachment_id: %s", err)) + } + + if err = d.Set("interface_type", bareMetalServerNetworkAttachment.InterfaceType); err != nil { + return diag.FromErr(fmt.Errorf("Error setting interface_type: %s", err)) + } + + if err = d.Set("lifecycle_state", bareMetalServerNetworkAttachment.LifecycleState); err != nil { + return diag.FromErr(fmt.Errorf("Error setting lifecycle_state: %s", err)) + } + + if err = d.Set("name", bareMetalServerNetworkAttachment.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + if err = d.Set("port_speed", flex.IntValue(bareMetalServerNetworkAttachment.PortSpeed)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting port_speed: %s", err)) + } + + primaryIP := []map[string]interface{}{} + if bareMetalServerNetworkAttachment.PrimaryIP != nil { + modelMap, err := dataSourceIBMIsBareMetalServerNetworkAttachmentReservedIPReferenceToMap(bareMetalServerNetworkAttachment.PrimaryIP) + if err != nil { + return diag.FromErr(err) + } + primaryIP = append(primaryIP, modelMap) + } + if err = d.Set("primary_ip", primaryIP); err != nil { + return diag.FromErr(fmt.Errorf("Error setting primary_ip %s", err)) + } + + if err = d.Set("resource_type", bareMetalServerNetworkAttachment.ResourceType); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_type: %s", err)) + } + + subnet := []map[string]interface{}{} + if bareMetalServerNetworkAttachment.Subnet != nil { + modelMap, err := dataSourceIBMIsBareMetalServerNetworkAttachmentSubnetReferenceToMap(bareMetalServerNetworkAttachment.Subnet) + if err != nil { + return diag.FromErr(err) + } + subnet = append(subnet, modelMap) + } + if err = d.Set("subnet", subnet); err != nil { + return diag.FromErr(fmt.Errorf("Error setting subnet %s", err)) + } + + if err = d.Set("type", bareMetalServerNetworkAttachment.Type); err != nil { + return diag.FromErr(fmt.Errorf("Error setting type: %s", err)) + } + + virtualNetworkInterface := []map[string]interface{}{} + if bareMetalServerNetworkAttachment.VirtualNetworkInterface != nil { + modelMap, err := dataSourceIBMIsBareMetalServerNetworkAttachmentVirtualNetworkInterfaceReferenceAttachmentContextToMap(bareMetalServerNetworkAttachment.VirtualNetworkInterface) + if err != nil { + return diag.FromErr(err) + } + virtualNetworkInterface = append(virtualNetworkInterface, modelMap) + } + if err = d.Set("virtual_network_interface", virtualNetworkInterface); err != nil { + return diag.FromErr(fmt.Errorf("Error setting virtual_network_interface %s", err)) + } + + if err = d.Set("allow_to_float", bareMetalServerNetworkAttachment.AllowToFloat); err != nil { + return diag.FromErr(fmt.Errorf("Error setting allow_to_float: %s", err)) + } + + if err = d.Set("vlan", flex.IntValue(bareMetalServerNetworkAttachment.Vlan)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting vlan: %s", err)) + } + + return nil +} + +func dataSourceIBMIsBareMetalServerNetworkAttachmentReservedIPReferenceToMap(model *vpcv1.ReservedIPReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["address"] = model.Address + if model.Deleted != nil { + deletedMap, err := dataSourceIBMIsBareMetalServerNetworkAttachmentReservedIPReferenceDeletedToMap(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 dataSourceIBMIsBareMetalServerNetworkAttachmentReservedIPReferenceDeletedToMap(model *vpcv1.ReservedIPReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = model.MoreInfo + return modelMap, nil +} + +func dataSourceIBMIsBareMetalServerNetworkAttachmentSubnetReferenceToMap(model *vpcv1.SubnetReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = model.CRN + if model.Deleted != nil { + deletedMap, err := dataSourceIBMIsBareMetalServerNetworkAttachmentSubnetReferenceDeletedToMap(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 dataSourceIBMIsBareMetalServerNetworkAttachmentSubnetReferenceDeletedToMap(model *vpcv1.SubnetReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = model.MoreInfo + return modelMap, nil +} + +func dataSourceIBMIsBareMetalServerNetworkAttachmentVirtualNetworkInterfaceReferenceAttachmentContextToMap(model *vpcv1.VirtualNetworkInterfaceReferenceAttachmentContext) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = model.CRN + 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_bare_metal_server_network_attachment_test.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_attachment_test.go new file mode 100644 index 0000000000..03eff15ffe --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_attachment_test.go @@ -0,0 +1,63 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIBMIsBareMetalServerNetworkAttachmentDataSourceBasic(t *testing.T) { + 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)) + vniname := fmt.Sprintf("tf-vni-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsBareMetalServerNetworkAttachmentDataSourceConfigBasic(vpcname, subnetname, sshname, publicKey, vniname, name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "bare_metal_server"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "network_attachment"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "bare_metal_server_network_attachment_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "interface_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "port_speed"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "primary_ip.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "subnet.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "type"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "virtual_network_interface.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsBareMetalServerNetworkAttachmentDataSourceConfigBasic(vpcname, subnetname, sshname, publicKey, vniname, name string) string { + return testAccCheckIBMIsBareMetalServerNetworkAttachmentConfigVlan(vpcname, subnetname, sshname, publicKey, vniname, name) + fmt.Sprintf(` + data "ibm_is_bare_metal_server_network_attachment" "is_bare_metal_server_network_attachment" { + bare_metal_server = ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment.bare_metal_server + network_attachment = ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment.network_attachment + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_attachments.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_attachments.go new file mode 100644 index 0000000000..074e7f8af8 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_attachments.go @@ -0,0 +1,453 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsBareMetalServerNetworkAttachments() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsBareMetalServerNetworkAttachmentsRead, + + Schema: map[string]*schema.Schema{ + "bare_metal_server": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The bare metal server identifier.", + }, + "network_attachments": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Collection of bare metal server network attachments.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the bare metal server network attachment was created.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this bare metal server network attachment.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this bare metal server network attachment.", + }, + "interface_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The network attachment's interface type:- `hipersocket`: a virtual network device that provides high-speed TCP/IP connectivity within a `s390x` based system- `pci`: a physical PCI device which can only be created or deleted when the bare metal server is stopped - Has an `allowed_vlans` property which controls the VLANs that will be permitted to use the PCI attachment - Cannot directly use an IEEE 802.1q VLAN tag.- `vlan`: a virtual device, used through a `pci` device that has the `vlan` in its array of `allowed_vlans`. - Must use an IEEE 802.1q tag.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the bare metal server network attachment.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this bare metal server network attachment. The name is unique across all network attachments for the bare metal server.", + }, + "port_speed": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The port speed for this bare metal server network attachment in Mbps.", + }, + "primary_ip": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The primary IP address of the virtual network interface for the bare metal servernetwork attachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "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 reserved IP.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this reserved IP. The name is unique across all reserved IPs in a 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, + Description: "The subnet of the virtual network interface for the bare metal server networkattachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this subnet.", + }, + "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 subnet.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this subnet.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this subnet. The name is unique across all subnets in the VPC.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The bare metal server network attachment type.", + }, + "virtual_network_interface": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The virtual network interface for this bare metal server network attachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this virtual network interface.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this virtual network interface.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this virtual network interface.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this virtual network interface. The name is unique across all virtual network interfaces in the VPC.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "allowed_vlans": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeInt, + }, + }, + "allow_to_float": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates if the bare metal server network attachment can automatically float to any other server within the same `resource_group`. The bare metal server network attachment will float automatically if the network detects a GARP or RARP on another bare metal server in the resource group. Applies only to bare metal server network attachments with `vlan` interface type.", + }, + "vlan": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "Indicates the 802.1Q VLAN ID tag that must be used for all traffic on this attachment.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsBareMetalServerNetworkAttachmentsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + listBareMetalServerNetworkAttachmentsOptions := &vpcv1.ListBareMetalServerNetworkAttachmentsOptions{} + + listBareMetalServerNetworkAttachmentsOptions.SetBareMetalServerID(d.Get("bare_metal_server").(string)) + + var pager *vpcv1.BareMetalServerNetworkAttachmentsPager + pager, err = vpcClient.NewBareMetalServerNetworkAttachmentsPager(listBareMetalServerNetworkAttachmentsOptions) + if err != nil { + return diag.FromErr(err) + } + + allItems, err := pager.GetAll() + if err != nil { + log.Printf("[DEBUG] BareMetalServerNetworkAttachmentsPager.GetAll() failed %s", err) + return diag.FromErr(fmt.Errorf("BareMetalServerNetworkAttachmentsPager.GetAll() failed %s", err)) + } + + d.SetId(dataSourceIBMIsBareMetalServerNetworkAttachmentsID(d)) + + mapSlice := []map[string]interface{}{} + for _, modelItem := range allItems { + modelMap, err := dataSourceIBMIsBareMetalServerNetworkAttachmentsBareMetalServerNetworkAttachmentToMap(modelItem) + if err != nil { + return diag.FromErr(err) + } + mapSlice = append(mapSlice, modelMap) + } + + if err = d.Set("network_attachments", mapSlice); err != nil { + return diag.FromErr(fmt.Errorf("Error setting network_attachments %s", err)) + } + + return nil +} + +// dataSourceIBMIsBareMetalServerNetworkAttachmentsID returns a reasonable ID for the list. +func dataSourceIBMIsBareMetalServerNetworkAttachmentsID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceIBMIsBareMetalServerNetworkAttachmentsBareMetalServerNetworkAttachmentCollectionFirstToMap(model *vpcv1.BareMetalServerNetworkAttachmentCollectionFirst) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = model.Href + return modelMap, nil +} + +func dataSourceIBMIsBareMetalServerNetworkAttachmentsBareMetalServerNetworkAttachmentToMap(model vpcv1.BareMetalServerNetworkAttachmentIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.BareMetalServerNetworkAttachmentByPci); ok { + return dataSourceIBMIsBareMetalServerNetworkAttachmentsBareMetalServerNetworkAttachmentByPciToMap(model.(*vpcv1.BareMetalServerNetworkAttachmentByPci)) + } else if _, ok := model.(*vpcv1.BareMetalServerNetworkAttachmentByVlan); ok { + return dataSourceIBMIsBareMetalServerNetworkAttachmentsBareMetalServerNetworkAttachmentByVlanToMap(model.(*vpcv1.BareMetalServerNetworkAttachmentByVlan)) + } else if _, ok := model.(*vpcv1.BareMetalServerNetworkAttachment); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.BareMetalServerNetworkAttachment) + modelMap["created_at"] = model.CreatedAt.String() + modelMap["href"] = model.Href + modelMap["id"] = model.ID + modelMap["interface_type"] = model.InterfaceType + modelMap["lifecycle_state"] = model.LifecycleState + modelMap["name"] = model.Name + modelMap["port_speed"] = flex.IntValue(model.PortSpeed) + primaryIPMap, err := dataSourceIBMIsBareMetalServerNetworkAttachmentsReservedIPReferenceToMap(model.PrimaryIP) + if err != nil { + return modelMap, err + } + modelMap["primary_ip"] = []map[string]interface{}{primaryIPMap} + modelMap["resource_type"] = model.ResourceType + subnetMap, err := dataSourceIBMIsBareMetalServerNetworkAttachmentsSubnetReferenceToMap(model.Subnet) + if err != nil { + return modelMap, err + } + modelMap["subnet"] = []map[string]interface{}{subnetMap} + modelMap["type"] = model.Type + virtualNetworkInterfaceMap, err := dataSourceIBMIsBareMetalServerNetworkAttachmentsVirtualNetworkInterfaceReferenceAttachmentContextToMap(model.VirtualNetworkInterface) + if err != nil { + return modelMap, err + } + modelMap["virtual_network_interface"] = []map[string]interface{}{virtualNetworkInterfaceMap} + if model.AllowedVlans != nil { + modelMap["allowed_vlans"] = model.AllowedVlans + } + if model.AllowToFloat != nil { + modelMap["allow_to_float"] = model.AllowToFloat + } + if model.Vlan != nil { + modelMap["vlan"] = flex.IntValue(model.Vlan) + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.BareMetalServerNetworkAttachmentIntf subtype encountered") + } +} + +func dataSourceIBMIsBareMetalServerNetworkAttachmentsReservedIPReferenceToMap(model *vpcv1.ReservedIPReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["address"] = model.Address + if model.Deleted != nil { + deletedMap, err := dataSourceIBMIsBareMetalServerNetworkAttachmentsReservedIPReferenceDeletedToMap(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 dataSourceIBMIsBareMetalServerNetworkAttachmentsReservedIPReferenceDeletedToMap(model *vpcv1.ReservedIPReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = model.MoreInfo + return modelMap, nil +} + +func dataSourceIBMIsBareMetalServerNetworkAttachmentsSubnetReferenceToMap(model *vpcv1.SubnetReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = model.CRN + if model.Deleted != nil { + deletedMap, err := dataSourceIBMIsBareMetalServerNetworkAttachmentsSubnetReferenceDeletedToMap(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 dataSourceIBMIsBareMetalServerNetworkAttachmentsSubnetReferenceDeletedToMap(model *vpcv1.SubnetReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = model.MoreInfo + return modelMap, nil +} + +func dataSourceIBMIsBareMetalServerNetworkAttachmentsVirtualNetworkInterfaceReferenceAttachmentContextToMap(model *vpcv1.VirtualNetworkInterfaceReferenceAttachmentContext) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = model.CRN + modelMap["href"] = model.Href + modelMap["id"] = model.ID + modelMap["name"] = model.Name + modelMap["resource_type"] = model.ResourceType + return modelMap, nil +} + +func dataSourceIBMIsBareMetalServerNetworkAttachmentsBareMetalServerNetworkAttachmentByVlanToMap(model *vpcv1.BareMetalServerNetworkAttachmentByVlan) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["created_at"] = model.CreatedAt.String() + modelMap["href"] = model.Href + modelMap["id"] = model.ID + modelMap["lifecycle_state"] = model.LifecycleState + modelMap["name"] = model.Name + modelMap["port_speed"] = flex.IntValue(model.PortSpeed) + primaryIPMap, err := dataSourceIBMIsBareMetalServerNetworkAttachmentsReservedIPReferenceToMap(model.PrimaryIP) + if err != nil { + return modelMap, err + } + modelMap["primary_ip"] = []map[string]interface{}{primaryIPMap} + modelMap["resource_type"] = model.ResourceType + subnetMap, err := dataSourceIBMIsBareMetalServerNetworkAttachmentsSubnetReferenceToMap(model.Subnet) + if err != nil { + return modelMap, err + } + modelMap["subnet"] = []map[string]interface{}{subnetMap} + modelMap["type"] = model.Type + virtualNetworkInterfaceMap, err := dataSourceIBMIsBareMetalServerNetworkAttachmentsVirtualNetworkInterfaceReferenceAttachmentContextToMap(model.VirtualNetworkInterface) + if err != nil { + return modelMap, err + } + modelMap["virtual_network_interface"] = []map[string]interface{}{virtualNetworkInterfaceMap} + modelMap["allow_to_float"] = model.AllowToFloat + modelMap["interface_type"] = model.InterfaceType + modelMap["vlan"] = flex.IntValue(model.Vlan) + return modelMap, nil +} + +func dataSourceIBMIsBareMetalServerNetworkAttachmentsBareMetalServerNetworkAttachmentByPciToMap(model *vpcv1.BareMetalServerNetworkAttachmentByPci) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["created_at"] = model.CreatedAt.String() + modelMap["href"] = model.Href + modelMap["id"] = model.ID + modelMap["lifecycle_state"] = model.LifecycleState + modelMap["name"] = model.Name + modelMap["port_speed"] = flex.IntValue(model.PortSpeed) + primaryIPMap, err := dataSourceIBMIsBareMetalServerNetworkAttachmentsReservedIPReferenceToMap(model.PrimaryIP) + if err != nil { + return modelMap, err + } + modelMap["primary_ip"] = []map[string]interface{}{primaryIPMap} + modelMap["resource_type"] = model.ResourceType + subnetMap, err := dataSourceIBMIsBareMetalServerNetworkAttachmentsSubnetReferenceToMap(model.Subnet) + if err != nil { + return modelMap, err + } + modelMap["subnet"] = []map[string]interface{}{subnetMap} + modelMap["type"] = model.Type + virtualNetworkInterfaceMap, err := dataSourceIBMIsBareMetalServerNetworkAttachmentsVirtualNetworkInterfaceReferenceAttachmentContextToMap(model.VirtualNetworkInterface) + if err != nil { + return modelMap, err + } + modelMap["virtual_network_interface"] = []map[string]interface{}{virtualNetworkInterfaceMap} + modelMap["allowed_vlans"] = model.AllowedVlans + modelMap["interface_type"] = model.InterfaceType + return modelMap, nil +} + +func dataSourceIBMIsBareMetalServerNetworkAttachmentsBareMetalServerNetworkAttachmentCollectionNextToMap(model *vpcv1.BareMetalServerNetworkAttachmentCollectionNext) (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_bare_metal_server_network_attachments_test.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_attachments_test.go new file mode 100644 index 0000000000..53a5d01853 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_network_attachments_test.go @@ -0,0 +1,60 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIBMIsBareMetalServerNetworkAttachmentsDataSourceBasic(t *testing.T) { + 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)) + vniname := fmt.Sprintf("tf-vni-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsBareMetalServerNetworkAttachmentsDataSourceConfigBasic(vpcname, subnetname, sshname, publicKey, vniname, name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server_network_attachments.is_bare_metal_server_network_attachments", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server_network_attachments.is_bare_metal_server_network_attachments", "bare_metal_server"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server_network_attachments.is_bare_metal_server_network_attachments", "network_attachments.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server_network_attachments.is_bare_metal_server_network_attachments", "network_attachments.0.created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server_network_attachments.is_bare_metal_server_network_attachments", "network_attachments.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server_network_attachments.is_bare_metal_server_network_attachments", "network_attachments.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server_network_attachments.is_bare_metal_server_network_attachments", "network_attachments.0.interface_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server_network_attachments.is_bare_metal_server_network_attachments", "network_attachments.0.lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server_network_attachments.is_bare_metal_server_network_attachments", "network_attachments.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server_network_attachments.is_bare_metal_server_network_attachments", "network_attachments.0.port_speed"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server_network_attachments.is_bare_metal_server_network_attachments", "network_attachments.0.primary_ip.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server_network_attachments.is_bare_metal_server_network_attachments", "network_attachments.0.resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server_network_attachments.is_bare_metal_server_network_attachments", "network_attachments.0.subnet.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server_network_attachments.is_bare_metal_server_network_attachments", "network_attachments.0.type"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server_network_attachments.is_bare_metal_server_network_attachments", "network_attachments.0.virtual_network_interface.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsBareMetalServerNetworkAttachmentsDataSourceConfigBasic(vpcname, subnetname, sshname, publicKey, vniname, name string) string { + return testAccCheckIBMIsBareMetalServerNetworkAttachmentConfigVlan(vpcname, subnetname, sshname, publicKey, vniname, name) + fmt.Sprintf(` + data "ibm_is_bare_metal_server_network_attachments" "is_bare_metal_server_network_attachments" { + bare_metal_server = "0717-1193c3f7-b23c-4e35-9e65-01f3a8741085" + } + `) +} 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 c514aa706f..4c044c4279 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 @@ -48,6 +48,51 @@ func DataSourceIBMIsBareMetalServerProfile() *schema.Resource { Description: "The name for this bare metal server profile", }, + // vni + + "virtual_network_interfaces_supported": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Indicates whether this profile supports virtual network interfaces.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field.", + }, + "value": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "The value for this profile field.", + }, + }, + }, + }, + "network_attachment_count": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "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.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field.", + }, + }, + }, + }, + isBareMetalServerProfileFamily: { Type: schema.TypeString, Computed: true, @@ -75,6 +120,34 @@ func DataSourceIBMIsBareMetalServerProfile() *schema.Resource { Computed: true, Description: "The value for this profile field", }, + "default": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The default value for this profile field.", + }, + "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, + Description: "The increment step value for this profile field.", + }, + "values": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The permitted values for this profile field.", + Elem: &schema.Schema{ + Type: schema.TypeInt, + }, + }, }, }, }, @@ -359,9 +432,27 @@ func dataSourceIBMISBMSProfileRead(context context.Context, d *schema.ResourceDa if bmsProfile.Bandwidth != nil { bwList := make([]map[string]interface{}, 0) bw := bmsProfile.Bandwidth.(*vpcv1.BareMetalServerProfileBandwidth) - bandwidth := map[string]interface{}{ - isBareMetalServerProfileType: *bw.Type, - isBareMetalServerProfileValue: *bw.Value, + bandwidth := map[string]interface{}{} + if bw.Type != nil { + bandwidth[isBareMetalServerProfileType] = *bw.Type + } + if bw.Value != nil { + bandwidth[isBareMetalServerProfileValue] = *bw.Value + } + if bw.Values != nil && len(bw.Values) > 0 { + bandwidth[isBareMetalServerProfileValues] = bw.Values + } + if bw.Default != nil { + bandwidth["default"] = flex.IntValue(bw.Default) + } + if bw.Max != nil { + bandwidth["max"] = flex.IntValue(bw.Max) + } + if bw.Min != nil { + bandwidth["min"] = flex.IntValue(bw.Min) + } + if bw.Step != nil { + bandwidth["step"] = flex.IntValue(bw.Step) } bwList = append(bwList, bandwidth) d.Set(isBareMetalServerProfileBandwidth, bwList) @@ -495,6 +586,30 @@ func dataSourceIBMISBMSProfileRead(context context.Context, d *schema.ResourceDa list = append(list, sz) } d.Set(isBareMetalServerProfileDisks, list) + + // vni + virtualNetworkInterfacesSupported := []map[string]interface{}{} + if bmsProfile.VirtualNetworkInterfacesSupported != nil { + modelMap, err := dataSourceIBMIsBareMetalServerProfileBareMetalServerProfileVirtualNetworkInterfacesSupportedToMap(bmsProfile.VirtualNetworkInterfacesSupported) + if err != nil { + return diag.FromErr(err) + } + virtualNetworkInterfacesSupported = append(virtualNetworkInterfacesSupported, modelMap) + } + if err = d.Set("virtual_network_interfaces_supported", virtualNetworkInterfacesSupported); err != nil { + return diag.FromErr(fmt.Errorf("Error setting virtual_network_interfaces_supported %s", err)) + } + networkAttachmentCount := []map[string]interface{}{} + if bmsProfile.NetworkAttachmentCount != nil { + modelMap, err := dataSourceIBMIsBareMetalServerProfileBareMetalServerProfileNetworkAttachmentCountToMap(bmsProfile.NetworkAttachmentCount) + if err != nil { + return diag.FromErr(err) + } + networkAttachmentCount = append(networkAttachmentCount, modelMap) + } + if err = d.Set("network_attachment_count", networkAttachmentCount); err != nil { + return diag.FromErr(fmt.Errorf("Error setting network_attachment_count %s", err)) + } } return nil @@ -547,3 +662,51 @@ func dataSourceIBMIsBareMetalServerProfileBareMetalServerProfileNetworkInterface modelMap["type"] = model.Type return modelMap, nil } + +func dataSourceIBMIsBareMetalServerProfileBareMetalServerProfileVirtualNetworkInterfacesSupportedToMap(model *vpcv1.BareMetalServerProfileVirtualNetworkInterfacesSupported) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["type"] = model.Type + modelMap["value"] = model.Value + return modelMap, nil +} + +func dataSourceIBMIsBareMetalServerProfileBareMetalServerProfileNetworkAttachmentCountToMap(model vpcv1.BareMetalServerProfileNetworkAttachmentCountIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.BareMetalServerProfileNetworkAttachmentCountRange); ok { + return dataSourceIBMIsBareMetalServerProfileBareMetalServerProfileNetworkAttachmentCountRangeToMap(model.(*vpcv1.BareMetalServerProfileNetworkAttachmentCountRange)) + } else if _, ok := model.(*vpcv1.BareMetalServerProfileNetworkAttachmentCountDependent); ok { + return dataSourceIBMIsBareMetalServerProfileBareMetalServerProfileNetworkAttachmentCountDependentToMap(model.(*vpcv1.BareMetalServerProfileNetworkAttachmentCountDependent)) + } else if _, ok := model.(*vpcv1.BareMetalServerProfileNetworkAttachmentCount); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.BareMetalServerProfileNetworkAttachmentCount) + if model.Max != nil { + modelMap["max"] = flex.IntValue(model.Max) + } + if model.Min != nil { + modelMap["min"] = flex.IntValue(model.Min) + } + if model.Type != nil { + modelMap["type"] = model.Type + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.BareMetalServerProfileNetworkAttachmentCountIntf subtype encountered") + } +} + +func dataSourceIBMIsBareMetalServerProfileBareMetalServerProfileNetworkAttachmentCountRangeToMap(model *vpcv1.BareMetalServerProfileNetworkAttachmentCountRange) (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) + } + modelMap["type"] = model.Type + return modelMap, nil +} + +func dataSourceIBMIsBareMetalServerProfileBareMetalServerProfileNetworkAttachmentCountDependentToMap(model *vpcv1.BareMetalServerProfileNetworkAttachmentCountDependent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["type"] = model.Type + return modelMap, nil +} 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 87b372c28e..0c0990b2d7 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 @@ -47,6 +47,50 @@ func TestAccIBMISBMSProfileDataSource_basic(t *testing.T) { }, }) } +func TestAccIBMISBMSProfileDataSource_vni(t *testing.T) { + resName := "data.ibm_is_bare_metal_server_profile.test1" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMISBMSProfileDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(resName, "name"), + resource.TestCheckResourceAttrSet(resName, "bandwidth.0.default"), + resource.TestCheckResourceAttrSet(resName, "bandwidth.0.values.#"), + resource.TestCheckResourceAttrSet(resName, "bandwidth.#"), + resource.TestCheckResourceAttrSet(resName, "console_types.#"), + resource.TestCheckResourceAttrSet(resName, "console_types.0.type"), + resource.TestCheckResourceAttrSet(resName, "console_types.0.values.#"), + resource.TestCheckResourceAttrSet(resName, "cpu_architecture.#"), + resource.TestCheckResourceAttrSet(resName, "cpu_core_count.#"), + resource.TestCheckResourceAttrSet(resName, "cpu_socket_count.#"), + resource.TestCheckResourceAttrSet(resName, "disks.#"), + resource.TestCheckResourceAttrSet(resName, "family"), + resource.TestCheckResourceAttrSet(resName, "href"), + resource.TestCheckResourceAttrSet(resName, "id"), + resource.TestCheckResourceAttrSet(resName, "memory.#"), + resource.TestCheckResourceAttrSet(resName, "network_interface_count.#"), + resource.TestCheckResourceAttrSet(resName, "network_interface_count.0.max"), + resource.TestCheckResourceAttrSet(resName, "network_interface_count.0.min"), + resource.TestCheckResourceAttrSet(resName, "network_interface_count.0.type"), + resource.TestCheckResourceAttrSet(resName, "network_attachment_count.#"), + resource.TestCheckResourceAttrSet(resName, "network_attachment_count.0.max"), + resource.TestCheckResourceAttrSet(resName, "network_attachment_count.0.min"), + resource.TestCheckResourceAttrSet(resName, "network_attachment_count.0.type"), + resource.TestCheckResourceAttrSet(resName, "virtual_network_interfaces_supported.#"), + resource.TestCheckResourceAttrSet(resName, "virtual_network_interfaces_supported.0.type"), + resource.TestCheckResourceAttrSet(resName, "virtual_network_interfaces_supported.0.value"), + resource.TestCheckResourceAttrSet(resName, "os_architecture.#"), + resource.TestCheckResourceAttrSet(resName, "resource_type"), + resource.TestCheckResourceAttrSet(resName, "supported_trusted_platform_module_modes.#"), + ), + }, + }, + }) +} func testAccCheckIBMISBMSProfileDataSourceConfig() string { // status filter defaults to empty diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_profiles.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_profiles.go index 8685bd1391..88503f3aa3 100644 --- a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_profiles.go +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_profiles.go @@ -43,6 +43,50 @@ func DataSourceIBMIsBareMetalServerProfiles() *schema.Resource { Description: "The name for this bare metal server profile", }, + // vni + "virtual_network_interfaces_supported": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Indicates whether this profile supports virtual network interfaces.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field.", + }, + "value": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "The value for this profile field.", + }, + }, + }, + }, + "network_attachment_count": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "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.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field.", + }, + }, + }, + }, + isBareMetalServerProfileFamily: { Type: schema.TypeString, Computed: true, @@ -115,6 +159,34 @@ func DataSourceIBMIsBareMetalServerProfiles() *schema.Resource { Computed: true, Description: "The value for this profile field", }, + "default": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The default value for this profile field.", + }, + "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, + Description: "The increment step value for this profile field.", + }, + "values": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The permitted values for this profile field.", + Elem: &schema.Schema{ + Type: schema.TypeInt, + }, + }, }, }, }, @@ -373,9 +445,27 @@ func dataSourceIBMIsBareMetalServerProfilesRead(context context.Context, d *sche if profile.Bandwidth != nil { bwList := make([]map[string]interface{}, 0) bw := profile.Bandwidth.(*vpcv1.BareMetalServerProfileBandwidth) - bandwidth := map[string]interface{}{ - isBareMetalServerProfileType: *bw.Type, - isBareMetalServerProfileValue: *bw.Value, + bandwidth := map[string]interface{}{} + if bw.Type != nil { + bandwidth[isBareMetalServerProfileType] = *bw.Type + } + if bw.Value != nil { + bandwidth[isBareMetalServerProfileValue] = *bw.Value + } + if bw.Values != nil && len(bw.Values) > 0 { + bandwidth[isBareMetalServerProfileValues] = bw.Values + } + if bw.Default != nil { + bandwidth["default"] = flex.IntValue(bw.Default) + } + if bw.Max != nil { + bandwidth["max"] = flex.IntValue(bw.Max) + } + if bw.Min != nil { + bandwidth["min"] = flex.IntValue(bw.Min) + } + if bw.Step != nil { + bandwidth["step"] = flex.IntValue(bw.Step) } bwList = append(bwList, bandwidth) l[isBareMetalServerProfileBandwidth] = bwList @@ -431,6 +521,26 @@ func dataSourceIBMIsBareMetalServerProfilesRead(context context.Context, d *sche l[isBareMetalServerProfileCPUSocketCount] = scList } + // vni + virtualNetworkInterfacesSupported := []map[string]interface{}{} + if profile.VirtualNetworkInterfacesSupported != nil { + modelMap, err := dataSourceIBMIsBareMetalServerProfileBareMetalServerProfileVirtualNetworkInterfacesSupportedToMap(profile.VirtualNetworkInterfacesSupported) + if err != nil { + return diag.FromErr(err) + } + virtualNetworkInterfacesSupported = append(virtualNetworkInterfacesSupported, modelMap) + } + l["virtual_network_interfaces_supported"] = virtualNetworkInterfacesSupported + networkAttachmentCount := []map[string]interface{}{} + if profile.NetworkAttachmentCount != nil { + modelMap, err := dataSourceIBMIsBareMetalServerProfileBareMetalServerProfileNetworkAttachmentCountToMap(profile.NetworkAttachmentCount) + if err != nil { + return diag.FromErr(err) + } + networkAttachmentCount = append(networkAttachmentCount, modelMap) + } + l["network_attachment_count"] = networkAttachmentCount + if profile.Memory != nil { memList := make([]map[string]interface{}, 0) mem := profile.Memory.(*vpcv1.BareMetalServerProfileMemory) diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_profiles_test.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_profiles_test.go index d749255606..7025af9f03 100644 --- a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_profiles_test.go +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_profiles_test.go @@ -47,6 +47,51 @@ func TestAccIBMISBMSProfilesDataSource_basic(t *testing.T) { }, }) } +func TestAccIBMISBMSProfilesDataSource_vni(t *testing.T) { + resName := "data.ibm_is_bare_metal_server_profiles.test1" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISBMSProfilesDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(resName, "profiles.0.name"), + resource.TestCheckResourceAttrSet(resName, "profiles.0.id"), + resource.TestCheckResourceAttrSet(resName, "profiles.0.family"), + resource.TestCheckResourceAttrSet(resName, "profiles.0.bandwidth.#"), + resource.TestCheckResourceAttrSet(resName, "profiles.0.bandwidth.0.default"), + resource.TestCheckResourceAttrSet(resName, "profiles.0.bandwidth.0.type"), + resource.TestCheckResourceAttrSet(resName, "profiles.0.bandwidth.0.values.#"), + resource.TestCheckResourceAttrSet(resName, "profiles.0.console_types.#"), + resource.TestCheckResourceAttrSet(resName, "profiles.0.console_types.0.type"), + resource.TestCheckResourceAttrSet(resName, "profiles.0.console_types.0.values.#"), + resource.TestCheckResourceAttrSet(resName, "profiles.0.cpu_architecture.#"), + resource.TestCheckResourceAttrSet(resName, "profiles.0.cpu_core_count.#"), + resource.TestCheckResourceAttrSet(resName, "profiles.0.cpu_socket_count.#"), + resource.TestCheckResourceAttrSet(resName, "profiles.0.disks.#"), + resource.TestCheckResourceAttrSet(resName, "profiles.0.href"), + resource.TestCheckResourceAttrSet(resName, "profiles.0.memory.#"), + resource.TestCheckResourceAttrSet(resName, "profiles.0.network_interface_count.#"), + resource.TestCheckResourceAttrSet(resName, "profiles.0.network_interface_count.0.max"), + resource.TestCheckResourceAttrSet(resName, "profiles.0.network_interface_count.0.min"), + resource.TestCheckResourceAttrSet(resName, "profiles.0.network_interface_count.0.type"), + resource.TestCheckResourceAttrSet(resName, "profiles.0.network_attachment_count.#"), + resource.TestCheckResourceAttrSet(resName, "profiles.0.network_attachment_count.0.max"), + resource.TestCheckResourceAttrSet(resName, "profiles.0.network_attachment_count.0.min"), + resource.TestCheckResourceAttrSet(resName, "profiles.0.network_attachment_count.0.type"), + resource.TestCheckResourceAttrSet(resName, "profiles.0.virtual_network_interfaces_supported.#"), + resource.TestCheckResourceAttrSet(resName, "profiles.0.virtual_network_interfaces_supported.0.type"), + resource.TestCheckResourceAttrSet(resName, "profiles.0.virtual_network_interfaces_supported.0.value"), + resource.TestCheckResourceAttrSet(resName, "profiles.0.os_architecture.#"), + resource.TestCheckResourceAttrSet(resName, "profiles.0.resource_type"), + resource.TestCheckResourceAttrSet(resName, "profiles.0.supported_trusted_platform_module_modes.#"), + ), + }, + }, + }) +} func testAccCheckIBMISBMSProfilesDataSourceConfig() string { // status filter defaults to empty diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_test.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_test.go index 3424358fe3..6b7ae253ce 100644 --- a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_test.go +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_test.go @@ -50,6 +50,50 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE }, }) } +func TestAccIBMISBMSDataSourceVNI_basic(t *testing.T) { + var server string + resName := "data.ibm_is_bare_metal_server.test1" + 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)) + vniname := fmt.Sprintf("tf-vni-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMISBMSDataSourceVniConfig(vpcname, subnetname, sshname, publicKey, vniname, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISBareMetalServerExists("ibm_is_bare_metal_server.testacc_bms", server), + resource.TestCheckResourceAttr( + resName, "name", name), + resource.TestCheckResourceAttr( + "data.ibm_is_bare_metal_server.test1", "zone", acc.ISZoneName), + resource.TestCheckResourceAttr( + "data.ibm_is_bare_metal_server.test1", "profile", acc.IsBareMetalServerProfileName), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server.test1", "primary_network_interface.0.primary_ip.0.address"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server.test1", "primary_network_interface.0.primary_ip.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server.test1", "primary_network_interface.0.primary_ip.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server.test1", "primary_network_interface.0.primary_ip.0.reserved_ip"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server.test1", "primary_network_interface.0.primary_ip.0.resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server.test1", "primary_network_interface.0.port_speed"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server.test1", "primary_network_attachment.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server.test1", "primary_network_attachment.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server.test1", "primary_network_attachment.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server.test1", "primary_network_attachment.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server.test1", "primary_network_attachment.0.primary_ip.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server.test1", "primary_network_attachment.0.resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_bare_metal_server.test1", "primary_network_attachment.0.subnet.#"), + ), + }, + }, + }) +} func testAccCheckIBMISBMSDataSourceConfig(vpcname, subnetname, sshname, publicKey, name string) string { // status filter defaults to empty @@ -58,3 +102,11 @@ func testAccCheckIBMISBMSDataSourceConfig(vpcname, subnetname, sshname, publicKe name = "%s" }`, name) } +func testAccCheckIBMISBMSDataSourceVniConfig(vpcname, subnetname, sshname, publicKey, vniname, name string) string { + // status filter defaults to empty + return testAccCheckIBMISBareMetalServerVNIConfig(vpcname, subnetname, sshname, publicKey, vniname, name) + fmt.Sprintf(` + data "ibm_is_bare_metal_server" "test1" { + depends_on = [ ibm_is_bare_metal_server.testacc_bms ] + name = "%s" + }`, name) +} 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 aa4c12f339..7847f5b48c 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 @@ -237,9 +237,9 @@ func DataSourceIBMIsBareMetalServers() *schema.Resource { Computed: true, }, isBareMetalServerNicHref: { - Type: schema.TypeString, - Computed: true, - Deprecated: "This URL of the interface", + Type: schema.TypeString, + Computed: true, + Description: "This URL of the interface", }, isBareMetalServerNicSecurityGroups: { @@ -290,6 +290,284 @@ func DataSourceIBMIsBareMetalServers() *schema.Resource { }, }, + "primary_network_attachment": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The primary 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 network attachment.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this network attachment.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "primary_ip": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The primary IP address of the virtual network interface for the network attachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "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 reserved IP.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this reserved IP. The name is unique across all reserved IPs in a 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, + Description: "The subnet of the virtual network interface for the network attachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this subnet.", + }, + "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 subnet.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this subnet.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this subnet. The name is unique across all subnets in the VPC.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + }, + }, + }, + + "network_attachments": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The network attachments for this bare metal server, including the primary 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 network attachment.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this network attachment.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "primary_ip": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The primary IP address of the virtual network interface for the network attachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "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 reserved IP.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this reserved IP. The name is unique across all reserved IPs in a 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, + Description: "The subnet of the virtual network interface for the network attachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this subnet.", + }, + "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 subnet.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this subnet.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this subnet. The name is unique across all subnets in the VPC.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + }, + }, + }, + isBareMetalServerNetworkInterfaces: { Type: schema.TypeList, Computed: true, @@ -660,6 +938,16 @@ func dataSourceIBMISBareMetalServersRead(context context.Context, d *schema.Reso l[isBareMetalServerPrimaryNetworkInterface] = primaryNicList } + primaryNetworkAttachment := []map[string]interface{}{} + if bms.PrimaryNetworkAttachment != nil { + modelMap, err := dataSourceIBMIsBareMetalServerBareMetalServerNetworkAttachmentReferenceToMap(bms.PrimaryNetworkAttachment) + if err != nil { + return diag.FromErr(err) + } + primaryNetworkAttachment = append(primaryNetworkAttachment, modelMap) + } + l["primary_network_attachment"] = primaryNetworkAttachment + //ni interfacesList := make([]map[string]interface{}, 0) @@ -742,6 +1030,21 @@ func dataSourceIBMISBareMetalServersRead(context context.Context, d *schema.Reso } } l[isBareMetalServerNetworkInterfaces] = interfacesList + + networkAttachments := []map[string]interface{}{} + if bms.NetworkAttachments != nil { + for _, modelItem := range bms.NetworkAttachments { + if *modelItem.ID != *bms.PrimaryNetworkAttachment.ID { + modelMap, err := dataSourceIBMIsBareMetalServerBareMetalServerNetworkAttachmentReferenceToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + networkAttachments = append(networkAttachments, modelMap) + } + } + } + l["network_attachments"] = networkAttachments + l[isBareMetalServerCreatedAt] = bms.CreatedAt.String() //disks diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_servers_test.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_servers_test.go index 96979a9b09..c3315d12f2 100644 --- a/ibm/service/vpc/data_source_ibm_is_bare_metal_servers_test.go +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_servers_test.go @@ -54,3 +54,52 @@ func testAccCheckIBMISBMSsDataSourceConfig(vpcname, subnetname, sshname, publicK data "ibm_is_bare_metal_servers" "test1" { }`) } +func TestAccIBMISBMSsDataSourceVNI_basic(t *testing.T) { + resName := "data.ibm_is_bare_metal_servers.test1" + 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)) + vniname := fmt.Sprintf("tf-vni-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISBMSsDataSourceVNIConfig(vpcname, subnetname, sshname, publicKey, vniname, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISBareMetalServerExists("ibm_is_bare_metal_server.testacc_bms", server), + resource.TestCheckResourceAttrSet(resName, "servers.0.name"), + resource.TestCheckResourceAttrSet(resName, "servers.0.id"), + resource.TestCheckResourceAttrSet(resName, "servers.0.memory"), + resource.TestCheckResourceAttrSet(resName, "servers.0.primary_network_interface.0.primary_ip.0.address"), + resource.TestCheckResourceAttrSet(resName, "servers.0.primary_network_interface.0.primary_ip.0.name"), + resource.TestCheckResourceAttrSet(resName, "servers.0.primary_network_interface.0.primary_ip.0.href"), + resource.TestCheckResourceAttrSet(resName, "servers.0.primary_network_interface.0.primary_ip.0.reserved_ip"), + resource.TestCheckResourceAttrSet(resName, "servers.0.primary_network_interface.0.primary_ip.0.resource_type"), + resource.TestCheckResourceAttrSet(resName, "servers.0.primary_network_interface.0.port_speed"), + resource.TestCheckResourceAttrSet(resName, "servers.0.primary_network_attachment.#"), + resource.TestCheckResourceAttrSet(resName, "servers.0.primary_network_attachment.0.href"), + resource.TestCheckResourceAttrSet(resName, "servers.0.primary_network_attachment.0.id"), + resource.TestCheckResourceAttrSet(resName, "servers.0.primary_network_attachment.0.name"), + resource.TestCheckResourceAttrSet(resName, "servers.0.primary_network_attachment.0.primary_ip.#"), + resource.TestCheckResourceAttrSet(resName, "servers.0.primary_network_attachment.0.resource_type"), + resource.TestCheckResourceAttrSet(resName, "servers.0.primary_network_attachment.0.subnet.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMISBMSsDataSourceVNIConfig(vpcname, subnetname, sshname, publicKey, vniname, name string) string { + // status filter defaults to empty + return testAccCheckIBMISBareMetalServerVNIConfig(vpcname, subnetname, sshname, publicKey, vniname, name) + fmt.Sprintf(` + data "ibm_is_bare_metal_servers" "test1" { + depends_on = [ ibm_is_bare_metal_server.testacc_bms ] + }`) +} diff --git a/ibm/service/vpc/data_source_ibm_is_instance.go b/ibm/service/vpc/data_source_ibm_is_instance.go index 42cae79e89..e378bed998 100644 --- a/ibm/service/vpc/data_source_ibm_is_instance.go +++ b/ibm/service/vpc/data_source_ibm_is_instance.go @@ -5,6 +5,7 @@ package vpc import ( "bytes" + "context" "crypto/rand" "crypto/rsa" "crypto/x509" @@ -18,6 +19,7 @@ import ( "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/ScaleFT/sshkeys" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "golang.org/x/crypto/ssh" ) @@ -34,11 +36,18 @@ const ( isInstanceNicReservedIpName = "name" isInstanceNicReservedIpId = "reserved_ip" isInstanceNicReservedIpResourceType = "resource_type" + + isInstanceReservation = "reservation" + isReservationDeleted = "deleted" + isReservationDeletedMoreInfo = "more_info" + isReservationAffinity = "reservation_affinity" + isReservationAffinityPool = "pool" + isReservationAffinityPolicyResp = "policy" ) func DataSourceIBMISInstance() *schema.Resource { return &schema.Resource{ - Read: dataSourceIBMISInstanceRead, + ReadContext: dataSourceIBMISInstanceRead, Schema: map[string]*schema.Schema{ @@ -378,6 +387,145 @@ func DataSourceIBMISInstance() *schema.Resource { }, }, + "primary_network_attachment": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The primary network attachment for this virtual server instance.", + 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 network attachment.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this network attachment.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "primary_ip": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The primary IP address of the virtual network interface for the network attachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "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 reserved IP.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this reserved IP. The name is unique across all reserved IPs in a 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, + Description: "The subnet of the virtual network interface for the network attachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this subnet.", + }, + "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 subnet.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this subnet.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this subnet. The name is unique across all subnets in the VPC.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + }, + }, + }, + isInstanceNetworkInterfaces: { Type: schema.TypeList, Computed: true, @@ -449,6 +597,145 @@ func DataSourceIBMISInstance() *schema.Resource { }, }, + "network_attachments": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The network attachments for this virtual server instance, including the primary 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 network attachment.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this network attachment.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "primary_ip": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The primary IP address of the virtual network interface for the network attachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "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 reserved IP.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this reserved IP. The name is unique across all reserved IPs in a 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, + Description: "The subnet of the virtual network interface for the network attachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this subnet.", + }, + "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 subnet.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this subnet.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this subnet. The name is unique across all subnets in the VPC.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + }, + }, + }, + isInstanceImage: { Type: schema.TypeString, Computed: true, @@ -697,17 +984,126 @@ func DataSourceIBMISInstance() *schema.Resource { }, }, }, + isInstanceReservation: { + Type: schema.TypeList, + Computed: true, + Description: "The reservation used by this virtual server instance", + 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 virtual server instance.", + }, + isReservationAffinityPool: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The pool of reservations available for use by this virtual server instance.", + 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.", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, }, } } -func dataSourceIBMISInstanceRead(d *schema.ResourceData, meta interface{}) error { +func dataSourceIBMISInstanceRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { name := d.Get(isInstanceName).(string) err := instanceGetByName(d, meta, name) if err != nil { - return err + return diag.FromErr(err) } return nil } @@ -866,6 +1262,17 @@ func instanceGetByName(d *schema.ResourceData, meta interface{}, name string) er primaryNicList = append(primaryNicList, currentPrimNic) d.Set(isInstancePrimaryNetworkInterface, primaryNicList) } + primaryNetworkAttachment := []map[string]interface{}{} + if instance.PrimaryNetworkAttachment != nil { + modelMap, err := dataSourceIBMIsInstanceInstanceNetworkAttachmentReferenceToMap(instance.PrimaryNetworkAttachment) + if err != nil { + return err + } + primaryNetworkAttachment = append(primaryNetworkAttachment, modelMap) + } + if err = d.Set("primary_network_attachment", primaryNetworkAttachment); err != nil { + return fmt.Errorf("Error setting primary_network_attachment %s", err) + } if instance.NetworkInterfaces != nil { interfacesList := make([]map[string]interface{}, 0) @@ -920,6 +1327,19 @@ func instanceGetByName(d *schema.ResourceData, meta interface{}, name string) er d.Set(isInstanceNetworkInterfaces, interfacesList) } + networkAttachments := []map[string]interface{}{} + if instance.NetworkAttachments != nil { + for _, modelItem := range instance.NetworkAttachments { + modelMap, err := dataSourceIBMIsInstanceInstanceNetworkAttachmentReferenceToMap(&modelItem) + if err != nil { + return err + } + networkAttachments = append(networkAttachments, modelMap) + } + } + if err = d.Set("network_attachments", networkAttachments); err != nil { + return fmt.Errorf("Error setting network_attachments %s", err) + } var rsaKey *rsa.PrivateKey if instance.Image != nil { @@ -1112,10 +1532,66 @@ 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.ReservationAffinity != nil { + reservationAffinity := []map[string]interface{}{} + reservationAffinityMap := map[string]interface{}{} + + reservationAffinityMap[isReservationAffinityPolicyResp] = instance.ReservationAffinity.Policy + if instance.ReservationAffinity.Pool != nil { + poolList := make([]map[string]interface{}, 0) + for _, pool := range instance.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 := dataSourceInstanceReservationDeletedToMap(*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 instance.Reservation != nil { + resList := make([]map[string]interface{}, 0) + res := map[string]interface{}{} + + res[isReservationId] = *instance.Reservation.ID + res[isReservationHref] = *instance.Reservation.Href + res[isReservationName] = *instance.Reservation.Name + res[isReservationCrn] = *instance.Reservation.CRN + res[isReservationResourceType] = *instance.Reservation.ResourceType + if instance.Reservation.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceInstanceReservationDeletedToMap(*instance.Reservation.Deleted) + deletedList = append(deletedList, deletedMap) + res[isReservationDeleted] = deletedList + } + resList = append(resList, res) + d.Set(isInstanceReservation, resList) + } return nil } +func dataSourceInstanceReservationDeletedToMap(deletedItem vpcv1.ReservationReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + const opensshv1Magic = "openssh-key-v1" type opensshPrivateKey struct { @@ -1196,3 +1672,77 @@ func dataSourceInstanceFlattenLifecycleReasons(lifecycleReasons []vpcv1.Instance } return lifecycleReasonsList } + +func dataSourceIBMIsInstanceInstanceNetworkAttachmentReferenceToMap(model *vpcv1.InstanceNetworkAttachmentReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Deleted != nil { + deletedMap, err := dataSourceIBMIsInstanceInstanceNetworkAttachmentReferenceDeletedToMap(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 := dataSourceIBMIsInstanceReservedIPReferenceToMap(model.PrimaryIP) + if err != nil { + return modelMap, err + } + modelMap["primary_ip"] = []map[string]interface{}{primaryIPMap} + modelMap["resource_type"] = model.ResourceType + subnetMap, err := dataSourceIBMIsInstanceSubnetReferenceToMap(model.Subnet) + if err != nil { + return modelMap, err + } + modelMap["subnet"] = []map[string]interface{}{subnetMap} + return modelMap, nil +} +func dataSourceIBMIsInstanceInstanceNetworkAttachmentReferenceDeletedToMap(model *vpcv1.InstanceNetworkAttachmentReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = model.MoreInfo + return modelMap, nil +} +func dataSourceIBMIsInstanceReservedIPReferenceToMap(model *vpcv1.ReservedIPReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["address"] = model.Address + if model.Deleted != nil { + deletedMap, err := dataSourceIBMIsInstanceReservedIPReferenceDeletedToMap(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 dataSourceIBMIsInstanceSubnetReferenceToMap(model *vpcv1.SubnetReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = model.CRN + if model.Deleted != nil { + deletedMap, err := dataSourceIBMIsInstanceSubnetReferenceDeletedToMap(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 dataSourceIBMIsInstanceSubnetReferenceDeletedToMap(model *vpcv1.SubnetReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = model.MoreInfo + return modelMap, nil +} + +func dataSourceIBMIsInstanceReservedIPReferenceDeletedToMap(model *vpcv1.ReservedIPReferenceDeleted) (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_network_attachment.go b/ibm/service/vpc/data_source_ibm_is_instance_network_attachment.go new file mode 100644 index 0000000000..3764651581 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_instance_network_attachment.go @@ -0,0 +1,342 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsInstanceNetworkAttachment() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsInstanceNetworkAttachmentRead, + + Schema: map[string]*schema.Schema{ + "instance": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The virtual server instance identifier.", + }, + "network_attachment": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The instance network attachment identifier.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the instance network attachment was created.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this instance network attachment.", + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the instance network attachment.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this instance network attachment. The name is unique across all network attachments for the instance.", + }, + "port_speed": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The port speed for this instance network attachment in Mbps.", + }, + "primary_ip": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The primary IP address of the virtual network interface for the instance networkattachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "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 reserved IP.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this reserved IP. The name is unique across all reserved IPs in a 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, + Description: "The subnet of the virtual network interface for the instance network attachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this subnet.", + }, + "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 subnet.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this subnet.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this subnet. The name is unique across all subnets in the VPC.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The instance network attachment type.", + }, + "virtual_network_interface": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The virtual network interface for this instance network attachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this virtual network interface.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this virtual network interface.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this virtual network interface.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this virtual network interface. The name is unique across all virtual network interfaces in the VPC.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsInstanceNetworkAttachmentRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + getInstanceNetworkAttachmentOptions := &vpcv1.GetInstanceNetworkAttachmentOptions{} + + getInstanceNetworkAttachmentOptions.SetInstanceID(d.Get("instance").(string)) + getInstanceNetworkAttachmentOptions.SetID(d.Get("network_attachment").(string)) + + instanceByNetworkAttachment, response, err := vpcClient.GetInstanceNetworkAttachmentWithContext(context, getInstanceNetworkAttachmentOptions) + if err != nil { + log.Printf("[DEBUG] GetInstanceNetworkAttachmentWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetInstanceNetworkAttachmentWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *getInstanceNetworkAttachmentOptions.InstanceID, *getInstanceNetworkAttachmentOptions.ID)) + + if err = d.Set("created_at", flex.DateTimeToString(instanceByNetworkAttachment.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + + if err = d.Set("href", instanceByNetworkAttachment.Href); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting href: %s", err)) + } + + if err = d.Set("lifecycle_state", instanceByNetworkAttachment.LifecycleState); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting lifecycle_state: %s", err)) + } + + if err = d.Set("name", instanceByNetworkAttachment.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + + if err = d.Set("port_speed", flex.IntValue(instanceByNetworkAttachment.PortSpeed)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting port_speed: %s", err)) + } + + primaryIP := []map[string]interface{}{} + if instanceByNetworkAttachment.PrimaryIP != nil { + modelMap, err := dataSourceIBMIsInstanceNetworkAttachmentReservedIPReferenceToMap(instanceByNetworkAttachment.PrimaryIP) + if err != nil { + return diag.FromErr(err) + } + primaryIP = append(primaryIP, modelMap) + } + if err = d.Set("primary_ip", primaryIP); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting primary_ip %s", err)) + } + + if err = d.Set("resource_type", instanceByNetworkAttachment.ResourceType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_type: %s", err)) + } + + subnet := []map[string]interface{}{} + if instanceByNetworkAttachment.Subnet != nil { + modelMap, err := dataSourceIBMIsInstanceNetworkAttachmentSubnetReferenceToMap(instanceByNetworkAttachment.Subnet) + if err != nil { + return diag.FromErr(err) + } + subnet = append(subnet, modelMap) + } + if err = d.Set("subnet", subnet); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting subnet %s", err)) + } + + if err = d.Set("type", instanceByNetworkAttachment.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) + } + + virtualNetworkInterface := []map[string]interface{}{} + if instanceByNetworkAttachment.VirtualNetworkInterface != nil { + modelMap, err := dataSourceIBMIsInstanceNetworkAttachmentVirtualNetworkInterfaceReferenceAttachmentContextToMap(instanceByNetworkAttachment.VirtualNetworkInterface) + if err != nil { + return diag.FromErr(err) + } + virtualNetworkInterface = append(virtualNetworkInterface, modelMap) + } + if err = d.Set("virtual_network_interface", virtualNetworkInterface); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting virtual_network_interface %s", err)) + } + + return nil +} + +func dataSourceIBMIsInstanceNetworkAttachmentReservedIPReferenceToMap(model *vpcv1.ReservedIPReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["address"] = model.Address + if model.Deleted != nil { + deletedMap, err := dataSourceIBMIsInstanceNetworkAttachmentReservedIPReferenceDeletedToMap(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 dataSourceIBMIsInstanceNetworkAttachmentReservedIPReferenceDeletedToMap(model *vpcv1.ReservedIPReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = model.MoreInfo + return modelMap, nil +} + +func dataSourceIBMIsInstanceNetworkAttachmentSubnetReferenceToMap(model *vpcv1.SubnetReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = model.CRN + if model.Deleted != nil { + deletedMap, err := dataSourceIBMIsInstanceNetworkAttachmentSubnetReferenceDeletedToMap(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 dataSourceIBMIsInstanceNetworkAttachmentSubnetReferenceDeletedToMap(model *vpcv1.SubnetReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = model.MoreInfo + return modelMap, nil +} + +func dataSourceIBMIsInstanceNetworkAttachmentVirtualNetworkInterfaceReferenceAttachmentContextToMap(model *vpcv1.VirtualNetworkInterfaceReferenceAttachmentContext) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = model.CRN + 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_instance_network_attachment_test.go b/ibm/service/vpc/data_source_ibm_is_instance_network_attachment_test.go new file mode 100644 index 0000000000..73848b93bb --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_instance_network_attachment_test.go @@ -0,0 +1,61 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIBMIsInstanceNetworkAttachmentDataSourceBasic(t *testing.T) { + 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`) + vniname := fmt.Sprintf("tf-vni-%d", acctest.RandIntRange(10, 100)) + 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, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsInstanceNetworkAttachmentDataSourceConfigBasic(vpcname, subnetname, sshname, publicKey, name, vniname, userData1), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_attachment.is_instance_network_attachment", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_attachment.is_instance_network_attachment", "instance"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_attachment.is_instance_network_attachment", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_attachment.is_instance_network_attachment", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_attachment.is_instance_network_attachment", "network_attachment"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_attachment.is_instance_network_attachment", "lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_attachment.is_instance_network_attachment", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_attachment.is_instance_network_attachment", "port_speed"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_attachment.is_instance_network_attachment", "primary_ip.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_attachment.is_instance_network_attachment", "resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_attachment.is_instance_network_attachment", "subnet.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_attachment.is_instance_network_attachment", "type"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.0.crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.0.id"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsInstanceNetworkAttachmentDataSourceConfigBasic(vpcname, subnetname, sshname, publicKey, name, vniname, userData1 string) string { + return testAccCheckIBMISInstanceVniConfig(vpcname, subnetname, sshname, publicKey, name, vniname, userData1) + fmt.Sprintf(` + data "ibm_is_instance_network_attachment" "is_instance_network_attachment" { + instance = ibm_is_instance.testacc_instance.id + network_attachment = ibm_is_instance.testacc_instance.primary_network_attachment.0.id + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_instance_network_attachments.go b/ibm/service/vpc/data_source_ibm_is_instance_network_attachments.go new file mode 100644 index 0000000000..d530da4e44 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_instance_network_attachments.go @@ -0,0 +1,334 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsInstanceNetworkAttachments() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsInstanceNetworkAttachmentsRead, + + Schema: map[string]*schema.Schema{ + "instance": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The virtual server instance identifier.", + }, + "network_attachments": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Collection of instance network attachments.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the instance network attachment was created.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this instance network attachment.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this instance network attachment.", + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the instance network attachment.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this instance network attachment. The name is unique across all network attachments for the instance.", + }, + "port_speed": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The port speed for this instance network attachment in Mbps.", + }, + "primary_ip": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The primary IP address of the virtual network interface for the instance networkattachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "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 reserved IP.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this reserved IP. The name is unique across all reserved IPs in a 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, + Description: "The subnet of the virtual network interface for the instance network attachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this subnet.", + }, + "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 subnet.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this subnet.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this subnet. The name is unique across all subnets in the VPC.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The instance network attachment type.", + }, + "virtual_network_interface": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The virtual network interface for this instance network attachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this virtual network interface.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this virtual network interface.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this virtual network interface.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this virtual network interface. The name is unique across all virtual network interfaces in the VPC.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsInstanceNetworkAttachmentsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + listInstanceNetworkAttachmentsOptions := &vpcv1.ListInstanceNetworkAttachmentsOptions{} + + listInstanceNetworkAttachmentsOptions.SetInstanceID(d.Get("instance").(string)) + + instanceNetworkAttachmentCollection, response, err := vpcClient.ListInstanceNetworkAttachmentsWithContext(context, listInstanceNetworkAttachmentsOptions) + if err != nil { + log.Printf("[DEBUG] ListInstanceNetworkAttachmentsWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ListInstanceNetworkAttachmentsWithContext failed %s\n%s", err, response)) + } + + d.SetId(dataSourceIBMIsInstanceNetworkAttachmentsID(d)) + + networkAttachments := []map[string]interface{}{} + if instanceNetworkAttachmentCollection.NetworkAttachments != nil { + for _, modelItem := range instanceNetworkAttachmentCollection.NetworkAttachments { + modelMap, err := dataSourceIBMIsInstanceNetworkAttachmentsInstanceNetworkAttachmentToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + networkAttachments = append(networkAttachments, modelMap) + } + } + if err = d.Set("network_attachments", networkAttachments); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting network_attachments %s", err)) + } + + return nil +} + +// dataSourceIBMIsInstanceNetworkAttachmentsID returns a reasonable ID for the list. +func dataSourceIBMIsInstanceNetworkAttachmentsID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceIBMIsInstanceNetworkAttachmentsInstanceNetworkAttachmentToMap(model *vpcv1.InstanceNetworkAttachment) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["created_at"] = model.CreatedAt.String() + modelMap["href"] = model.Href + modelMap["id"] = model.ID + modelMap["lifecycle_state"] = model.LifecycleState + modelMap["name"] = model.Name + modelMap["port_speed"] = flex.IntValue(model.PortSpeed) + primaryIPMap, err := dataSourceIBMIsInstanceNetworkAttachmentsReservedIPReferenceToMap(model.PrimaryIP) + if err != nil { + return modelMap, err + } + modelMap["primary_ip"] = []map[string]interface{}{primaryIPMap} + modelMap["resource_type"] = model.ResourceType + subnetMap, err := dataSourceIBMIsInstanceNetworkAttachmentsSubnetReferenceToMap(model.Subnet) + if err != nil { + return modelMap, err + } + modelMap["subnet"] = []map[string]interface{}{subnetMap} + modelMap["type"] = model.Type + virtualNetworkInterfaceMap, err := dataSourceIBMIsInstanceNetworkAttachmentsVirtualNetworkInterfaceReferenceAttachmentContextToMap(model.VirtualNetworkInterface) + if err != nil { + return modelMap, err + } + modelMap["virtual_network_interface"] = []map[string]interface{}{virtualNetworkInterfaceMap} + return modelMap, nil +} + +func dataSourceIBMIsInstanceNetworkAttachmentsReservedIPReferenceToMap(model *vpcv1.ReservedIPReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["address"] = model.Address + if model.Deleted != nil { + deletedMap, err := dataSourceIBMIsInstanceNetworkAttachmentsReservedIPReferenceDeletedToMap(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 dataSourceIBMIsInstanceNetworkAttachmentsReservedIPReferenceDeletedToMap(model *vpcv1.ReservedIPReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = model.MoreInfo + return modelMap, nil +} + +func dataSourceIBMIsInstanceNetworkAttachmentsSubnetReferenceToMap(model *vpcv1.SubnetReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = model.CRN + if model.Deleted != nil { + deletedMap, err := dataSourceIBMIsInstanceNetworkAttachmentsSubnetReferenceDeletedToMap(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 dataSourceIBMIsInstanceNetworkAttachmentsSubnetReferenceDeletedToMap(model *vpcv1.SubnetReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = model.MoreInfo + return modelMap, nil +} + +func dataSourceIBMIsInstanceNetworkAttachmentsVirtualNetworkInterfaceReferenceAttachmentContextToMap(model *vpcv1.VirtualNetworkInterfaceReferenceAttachmentContext) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = model.CRN + 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_instance_network_attachments_test.go b/ibm/service/vpc/data_source_ibm_is_instance_network_attachments_test.go new file mode 100644 index 0000000000..11b77a288f --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_instance_network_attachments_test.go @@ -0,0 +1,62 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIBMIsInstanceNetworkAttachmentsDataSourceBasic(t *testing.T) { + 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`) + vniname := fmt.Sprintf("tf-vni-%d", acctest.RandIntRange(10, 100)) + 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, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsInstanceNetworkAttachmentsDataSourceConfigBasic(vpcname, subnetname, sshname, publicKey, name, vniname, userData1), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_attachments.is_instance_network_attachments", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_attachments.is_instance_network_attachments", "instance"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_attachments.is_instance_network_attachments", "network_attachments.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_attachments.is_instance_network_attachments", "network_attachments.0.created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_attachments.is_instance_network_attachments", "network_attachments.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_attachments.is_instance_network_attachments", "network_attachments.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_attachments.is_instance_network_attachments", "network_attachments.0.lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_attachments.is_instance_network_attachments", "network_attachments.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_attachments.is_instance_network_attachments", "network_attachments.0.port_speed"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_attachments.is_instance_network_attachments", "network_attachments.0.port_speed"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_attachments.is_instance_network_attachments", "network_attachments.0.primary_ip.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_attachments.is_instance_network_attachments", "network_attachments.0.resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_attachments.is_instance_network_attachments", "network_attachments.0.subnet.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_attachments.is_instance_network_attachments", "network_attachments.0.type"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_attachments.is_instance_network_attachments", "network_attachments.0.virtual_network_interface.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_attachments.is_instance_network_attachments", "network_attachments.0.virtual_network_interface.0.crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_network_attachments.is_instance_network_attachments", "network_attachments.0.virtual_network_interface.0.id"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsInstanceNetworkAttachmentsDataSourceConfigBasic(vpcname, subnetname, sshname, publicKey, name, vniname, userData1 string) string { + return testAccCheckIBMISInstanceVniConfig(vpcname, subnetname, sshname, publicKey, name, vniname, userData1) + fmt.Sprintf(` + data "ibm_is_instance_network_attachments" "is_instance_network_attachments" { + instance = ibm_is_instance.testacc_instance.id + } + `) +} 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 2eee0d374a..bb0842ed1c 100644 --- a/ibm/service/vpc/data_source_ibm_is_instance_profile.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_profile.go @@ -238,6 +238,28 @@ func DataSourceIBMISInstanceProfile() *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, + }, + }, + }, + }, + }, "total_volume_bandwidth": { Type: schema.TypeList, Computed: true, @@ -486,6 +508,29 @@ func DataSourceIBMISInstanceProfile() *schema.Resource { }, }, }, + "network_attachment_count": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "max": { + Type: schema.TypeInt, + Computed: true, + Description: "The maximum value for this profile field", + }, + "min": { + Type: schema.TypeInt, + Computed: true, + Description: "The minimum value for this profile field", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field.", + }, + }, + }, + }, "numa_count": { Type: schema.TypeList, Computed: true, @@ -694,6 +739,12 @@ func instanceProfileGet(d *schema.ResourceData, meta interface{}, name string) e return err } } + if profile.ReservationTerms != nil { + err = d.Set("reservation_terms", dataSourceInstanceProfileFlattenReservationTerms(*profile.ReservationTerms)) + if err != nil { + return err + } + } if profile.TotalVolumeBandwidth != nil { err = d.Set("total_volume_bandwidth", dataSourceInstanceProfileFlattenTotalVolumeBandwidth(*profile.TotalVolumeBandwidth.(*vpcv1.InstanceProfileVolumeBandwidth))) if err != nil { @@ -722,6 +773,12 @@ func instanceProfileGet(d *schema.ResourceData, meta interface{}, name string) e return err } } + if profile.NetworkAttachmentCount != nil { + err = d.Set("network_attachment_count", dataSourceInstanceProfileFlattenNetworkAttachmentCount(*profile.NetworkAttachmentCount.(*vpcv1.InstanceProfileNetworkAttachmentCount))) + if err != nil { + return err + } + } if profile.NumaCount != nil { err = d.Set("numa_count", dataSourceInstanceProfileFlattenNumaCount(*profile.NumaCount.(*vpcv1.InstanceProfileNumaCount))) if err != nil { @@ -873,6 +930,27 @@ func dataSourceInstanceProfileGPUModelToMap(bandwidthItem vpcv1.InstanceProfileG return gpuModelMap } +func dataSourceInstanceProfileFlattenReservationTerms(result vpcv1.InstanceProfileReservationTerms) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceInstanceProfileReservationTermsToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceInstanceProfileReservationTermsToMap(resTermItem vpcv1.InstanceProfileReservationTerms) 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 dataSourceInstanceProfileFlattenGPUMemory(result vpcv1.InstanceProfileGpuMemory) (finalList []map[string]interface{}) { finalList = []map[string]interface{}{} finalMap := dataSourceInstanceProfileGPUMemoryToMap(result) @@ -952,6 +1030,28 @@ func dataSourceInstanceProfileFlattenNetworkInterfaceCount(result vpcv1.Instance return finalList } +func dataSourceInstanceProfileFlattenNetworkAttachmentCount(result vpcv1.InstanceProfileNetworkAttachmentCount) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceInstanceProfileNetworkAttachmentCount(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceInstanceProfileNetworkAttachmentCount(networkAttachmentCountItem vpcv1.InstanceProfileNetworkAttachmentCount) (networkAttachmentCountMap map[string]interface{}) { + networkAttachmentCountMap = map[string]interface{}{} + + if networkAttachmentCountItem.Max != nil { + networkAttachmentCountMap["max"] = networkAttachmentCountItem.Max + } + if networkAttachmentCountItem.Min != nil { + networkAttachmentCountMap["min"] = networkAttachmentCountItem.Min + } + if networkAttachmentCountItem.Type != nil { + networkAttachmentCountMap["type"] = networkAttachmentCountItem.Type + } + return networkAttachmentCountMap +} func dataSourceInstanceProfileNetworkInterfaceCount(networkInterfaceCountItem vpcv1.InstanceProfileNetworkInterfaceCount) (networkInterfaceCountMap map[string]interface{}) { networkInterfaceCountMap = map[string]interface{}{} 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 21fa13546e..8b4bc49548 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 @@ -36,6 +36,11 @@ func TestAccIBMISInstanceProfileDataSource_basic(t *testing.T) { resource.TestCheckResourceAttrSet("data.ibm_is_instance_profile.test1", "vcpu_manufacturer.0.type"), resource.TestCheckResourceAttrSet("data.ibm_is_instance_profile.test1", "vcpu_manufacturer.0.value"), resource.TestCheckResourceAttrSet("data.ibm_is_instance_profile.test1", "network_interface_count.0.type"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profile.test1", "network_attachment_count.0.type"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profile.test1", "network_attachment_count.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profile.test1", "reservation_terms.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profile.test1", "reservation_terms.0.type"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profile.test1", "reservation_terms.0.values"), ), }, }, 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 83b7788780..45c4a05ca2 100644 --- a/ibm/service/vpc/data_source_ibm_is_instance_profiles.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_profiles.go @@ -239,6 +239,28 @@ func DataSourceIBMISInstanceProfiles() *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, + }, + }, + }, + }, + }, "total_volume_bandwidth": { Type: schema.TypeList, Computed: true, @@ -464,6 +486,29 @@ func DataSourceIBMISInstanceProfiles() *schema.Resource { }, }, }, + "network_attachment_count": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "max": { + Type: schema.TypeInt, + Computed: true, + Description: "The maximum value for this profile field", + }, + "min": { + Type: schema.TypeInt, + Computed: true, + Description: "The minimum value for this profile field", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field.", + }, + }, + }, + }, "network_interface_count": { Type: schema.TypeList, Computed: true, @@ -689,6 +734,10 @@ func instanceProfilesList(d *schema.ResourceData, meta interface{}) error { l["gpu_model"] = dataSourceInstanceProfileFlattenGPUModel(*profile.GpuModel) } + if profile.ReservationTerms != nil { + l["reservation_terms"] = dataSourceInstanceProfileFlattenReservationTerms(*profile.ReservationTerms) + } + if profile.TotalVolumeBandwidth != nil { l["total_volume_bandwidth"] = dataSourceInstanceProfileFlattenTotalVolumeBandwidth(*profile.TotalVolumeBandwidth.(*vpcv1.InstanceProfileVolumeBandwidth)) } @@ -715,6 +764,12 @@ func instanceProfilesList(d *schema.ResourceData, meta interface{}) error { networkInterfaceCountList = append(networkInterfaceCountList, networkInterfaceCountMap) l["network_interface_count"] = networkInterfaceCountList } + if profile.NetworkAttachmentCount != nil { + networkAttachmentCountList := []map[string]interface{}{} + networkAttachmentCountMap := dataSourceInstanceProfileNetworkAttachmentCount(*profile.NetworkAttachmentCount.(*vpcv1.InstanceProfileNetworkAttachmentCount)) + networkAttachmentCountList = append(networkAttachmentCountList, networkAttachmentCountMap) + l["network_attachment_count"] = networkAttachmentCountList + } if profile.NumaCount != nil { numaCountList := []map[string]interface{}{} numaCountMap := dataSourceInstanceProfileNumaCountToMap(*profile.NumaCount.(*vpcv1.InstanceProfileNumaCount)) 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 5984669fbb..a59fd95d79 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 @@ -34,9 +34,14 @@ func TestAccIBMISInstanceProfilesDataSource_basic(t *testing.T) { 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"), ), }, }, 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 7a683ccfc2..bcdb731cbc 100644 --- a/ibm/service/vpc/data_source_ibm_is_instance_template.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_template.go @@ -326,6 +326,383 @@ func DataSourceIBMISInstanceTemplate() *schema.Resource { }, }, }, + + "network_attachments": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The additional network attachments to create for the virtual server instance.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this network attachment. Names must be unique within the instance the network attachment resides in. If unspecified, the name will be a hyphenated list of randomly-selected words.", + }, + "virtual_network_interface": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "A virtual network interface for the instance network attachment. This can be specifiedusing an existing virtual network interface, or a prototype object for a new virtualnetwork interface.If an existing virtual network interface is specified, `enable_infrastructure_nat` must be`false`.", + 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 interface. If `false`, source IP spoofing is prevented on this interface. If `true`, source IP spoofing is allowed on this interface.", + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether this virtual network interface will be automatically deleted when`target` is deleted.", + }, + "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.- `allow_ip_spoofing` must be `false`.- If the virtual network interface is attached: - The target `resource_type` must be `bare_metal_server_network_attachment`. - The target `interface_type` must not be `hipersocket`.", + }, + "ips": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Additional IP addresses to bind to the virtual network interface. Each item may be either a reserved IP identity, or as a reserved IP prototype object which will be used to create a new reserved IP. All IP addresses must be in the same subnet as the primary IP.If reserved IP identities are provided, the specified reserved IPs must be unbound.If reserved IP prototype objects with addresses are provided, the addresses must be available on the virtual network interface's subnet. For any prototype objects that do not specify an address, an available address on the subnet will 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 reserved IP.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this 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 reserved IP member will be automatically deleted when either`target` is deleted, or the reserved IP is unbound.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this reserved IP. The name must not be used by another reserved IP in the 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.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this virtual network interface. The name must not be used by another virtual network interface in the VPC. If unspecified, the name will be a hyphenated list of randomly-selected words. Names beginning with `ibm-` are reserved for provider-owned resources, and are not allowed.", + }, + "primary_ip": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The primary IP address to bind to the virtual network interface. May be either areserved IP identity, or a reserved IP prototype object which will be used to create anew reserved IP.If a reserved IP identity is provided, the specified reserved IP must be unbound.If a reserved IP prototype object with an address is provided, the address must beavailable on the virtual network interface's subnet. If no address is specified,an available address on the subnet will 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 reserved IP.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this 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 reserved IP member will be automatically deleted when either`target` is deleted, or the reserved IP is unbound.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this reserved IP. The name must not be used by another reserved IP in the 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.", + }, + }, + }, + }, + "resource_group": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The resource group to use for this virtual network interface. If unspecified, thevirtual server instance's resource group will be used.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this resource group.", + }, + }, + }, + }, + "security_groups": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The security groups to use for this virtual network interface. If unspecified, the default security group of the VPC for the subnet is used.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this security group.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The security group's CRN.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The security group's canonical URL.", + }, + }, + }, + }, + "subnet": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The associated subnet. Required if `primary_ip` does not specify a reserved IP.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this subnet.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this subnet.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this subnet.", + }, + }, + }, + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this virtual network interface.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this virtual network interface.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this virtual network interface.", + }, + }, + }, + }, + }, + }, + }, + "primary_network_attachment": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The primary network attachment to create for the virtual server instance.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this network attachment. Names must be unique within the instance the network attachment resides in. If unspecified, the name will be a hyphenated list of randomly-selected words.", + }, + "virtual_network_interface": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "A virtual network interface for the instance network attachment. This can be specifiedusing an existing virtual network interface, or a prototype object for a new virtualnetwork interface.If an existing virtual network interface is specified, `enable_infrastructure_nat` must be`false`.", + 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 interface. If `false`, source IP spoofing is prevented on this interface. If `true`, source IP spoofing is allowed on this interface.", + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether this virtual network interface will be automatically deleted when`target` is deleted.", + }, + "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.- `allow_ip_spoofing` must be `false`.- If the virtual network interface is attached: - The target `resource_type` must be `bare_metal_server_network_attachment`. - The target `interface_type` must not be `hipersocket`.", + }, + "ips": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Additional IP addresses to bind to the virtual network interface. Each item may be either a reserved IP identity, or as a reserved IP prototype object which will be used to create a new reserved IP. All IP addresses must be in the same subnet as the primary IP.If reserved IP identities are provided, the specified reserved IPs must be unbound.If reserved IP prototype objects with addresses are provided, the addresses must be available on the virtual network interface's subnet. For any prototype objects that do not specify an address, an available address on the subnet will 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 reserved IP.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this 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 reserved IP member will be automatically deleted when either`target` is deleted, or the reserved IP is unbound.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this reserved IP. The name must not be used by another reserved IP in the 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.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this virtual network interface. The name must not be used by another virtual network interface in the VPC. If unspecified, the name will be a hyphenated list of randomly-selected words. Names beginning with `ibm-` are reserved for provider-owned resources, and are not allowed.", + }, + "primary_ip": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The primary IP address to bind to the virtual network interface. May be either areserved IP identity, or a reserved IP prototype object which will be used to create anew reserved IP.If a reserved IP identity is provided, the specified reserved IP must be unbound.If a reserved IP prototype object with an address is provided, the address must beavailable on the virtual network interface's subnet. If no address is specified,an available address on the subnet will 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 reserved IP.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this 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 reserved IP member will be automatically deleted when either`target` is deleted, or the reserved IP is unbound.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this reserved IP. The name must not be used by another reserved IP in the 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.", + }, + }, + }, + }, + "resource_group": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The resource group to use for this virtual network interface. If unspecified, thevirtual server instance's resource group will be used.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this resource group.", + }, + }, + }, + }, + "security_groups": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The security groups to use for this virtual network interface. If unspecified, the default security group of the VPC for the subnet is used.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this security group.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The security group's CRN.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The security group's canonical URL.", + }, + }, + }, + }, + "subnet": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The associated subnet. Required if `primary_ip` does not specify a reserved IP.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this subnet.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this subnet.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this subnet.", + }, + }, + }, + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this virtual network interface.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this virtual network interface.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this virtual network interface.", + }, + }, + }, + }, + }, + }, + }, isInstanceTemplateUserData: { Type: schema.TypeString, Computed: true, @@ -397,6 +774,24 @@ func DataSourceIBMISInstanceTemplate() *schema.Resource { }, }, }, + 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 virtual server instance.", + }, + isReservationAffinityPool: { + Type: schema.TypeString, + Computed: true, + Description: "The reservation associated with this template.", + }, + }, + }, + }, }, } } @@ -421,6 +816,33 @@ func dataSourceIBMISInstanceTemplateRead(context context.Context, d *schema.Reso d.Set(isInstanceTemplateCrn, instance.CRN) d.Set(isInstanceTemplateName, instance.Name) d.Set(isInstanceTemplateUserData, instance.UserData) + // vni + + networkAttachments := []map[string]interface{}{} + if instance.NetworkAttachments != nil { + for _, modelItem := range instance.NetworkAttachments { + modelMap, err := dataSourceIBMIsInstanceTemplateInstanceNetworkAttachmentPrototypeToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + networkAttachments = append(networkAttachments, modelMap) + } + } + if err = d.Set("network_attachments", networkAttachments); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting network_attachments %s", err)) + } + + primaryNetworkAttachment := []map[string]interface{}{} + if instance.PrimaryNetworkAttachment != nil { + modelMap, err := dataSourceIBMIsInstanceTemplateInstanceNetworkAttachmentPrototypeToMap(instance.PrimaryNetworkAttachment) + if err != nil { + return diag.FromErr(err) + } + primaryNetworkAttachment = append(primaryNetworkAttachment, modelMap) + } + if err = d.Set("primary_network_attachment", primaryNetworkAttachment); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting primary_network_attachment %s", err)) + } if instance.DefaultTrustedProfile != nil { if instance.DefaultTrustedProfile.AutoLink != nil { @@ -503,6 +925,27 @@ func dataSourceIBMISInstanceTemplateRead(context context.Context, d *schema.Reso d.Set("placement_target", placementTargetList) } + if instance.ReservationAffinity != nil { + reservationAffinity := []map[string]interface{}{} + reservationAffinityMap := map[string]interface{}{} + + reservationAffinityMap[isReservationAffinityPolicyResp] = instance.ReservationAffinity.Policy + if instance.ReservationAffinity.Pool != nil && len(instance.ReservationAffinity.Pool) > 0 { + pool := instance.ReservationAffinity.Pool[0] + res := "" + if idPool, ok := pool.(*vpcv1.ReservationIdentityByID); ok { + res = *idPool.ID + } else if crnPool, ok := pool.(*vpcv1.ReservationIdentityByCRN); ok { + res = *crnPool.CRN + } else if hrefPool, ok := pool.(*vpcv1.ReservationIdentityByHref); ok { + res = *hrefPool.Href + } + reservationAffinityMap[isReservationAffinityPool] = res + } + reservationAffinity = append(reservationAffinity, reservationAffinityMap) + d.Set(isReservationAffinity, reservationAffinity) + } + if instance.TotalVolumeBandwidth != nil { d.Set(isInstanceTotalVolumeBandwidth, int(*instance.TotalVolumeBandwidth)) } @@ -738,6 +1181,34 @@ func dataSourceIBMISInstanceTemplateRead(context context.Context, d *schema.Reso d.Set(isInstanceTemplateCatalogOffering, catOfferingList) } + // vni + + networkAttachments := []map[string]interface{}{} + if instance.NetworkAttachments != nil { + for _, modelItem := range instance.NetworkAttachments { + modelMap, err := dataSourceIBMIsInstanceTemplateInstanceNetworkAttachmentPrototypeToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + networkAttachments = append(networkAttachments, modelMap) + } + } + if err = d.Set("network_attachments", networkAttachments); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting network_attachments %s", err)) + } + + primaryNetworkAttachment := []map[string]interface{}{} + if instance.PrimaryNetworkAttachment != nil { + modelMap, err := dataSourceIBMIsInstanceTemplateInstanceNetworkAttachmentPrototypeToMap(instance.PrimaryNetworkAttachment) + if err != nil { + return diag.FromErr(err) + } + primaryNetworkAttachment = append(primaryNetworkAttachment, modelMap) + } + if err = d.Set("primary_network_attachment", primaryNetworkAttachment); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting primary_network_attachment %s", err)) + } + if instance.DefaultTrustedProfile != nil { if instance.DefaultTrustedProfile.AutoLink != nil { d.Set(isInstanceDefaultTrustedProfileAutoLink, instance.DefaultTrustedProfile.AutoLink) @@ -1009,3 +1480,644 @@ func dataSourceInstanceTemplateCollectionTemplatePlacementTargetToMap(placementT return placementTargetMap } + +func dataSourceIBMIsInstanceTemplateInstanceNetworkAttachmentPrototypeToMap(model *vpcv1.InstanceNetworkAttachmentPrototype) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = model.Name + } + virtualNetworkInterfaceMap, err := dataSourceIBMIsInstanceTemplateInstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceToMap(model.VirtualNetworkInterface) + if err != nil { + return modelMap, err + } + modelMap["virtual_network_interface"] = []map[string]interface{}{virtualNetworkInterfaceMap} + return modelMap, nil +} + +func dataSourceIBMIsInstanceTemplateVirtualNetworkInterfaceIPPrototypeReservedIPIdentityVirtualNetworkInterfaceIPsContextByIDToMap(model *vpcv1.VirtualNetworkInterfaceIPPrototypeReservedIPIdentityVirtualNetworkInterfaceIPsContextByID) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["id"] = model.ID + return modelMap, nil +} + +func dataSourceIBMIsInstanceTemplateVirtualNetworkInterfaceIPPrototypeReservedIPIdentityVirtualNetworkInterfaceIPsContextByHrefToMap(model *vpcv1.VirtualNetworkInterfaceIPPrototypeReservedIPIdentityVirtualNetworkInterfaceIPsContextByHref) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = model.Href + return modelMap, nil +} +func dataSourceIBMIsInstanceTemplateVirtualNetworkInterfaceIPPrototypeReservedIPIdentityVirtualNetworkInterfaceIPsContextToMap(model vpcv1.VirtualNetworkInterfaceIPPrototypeReservedIPIdentityVirtualNetworkInterfaceIPsContextIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.VirtualNetworkInterfaceIPPrototypeReservedIPIdentityVirtualNetworkInterfaceIPsContextByID); ok { + return dataSourceIBMIsInstanceTemplateVirtualNetworkInterfaceIPPrototypeReservedIPIdentityVirtualNetworkInterfaceIPsContextByIDToMap(model.(*vpcv1.VirtualNetworkInterfaceIPPrototypeReservedIPIdentityVirtualNetworkInterfaceIPsContextByID)) + } else if _, ok := model.(*vpcv1.VirtualNetworkInterfaceIPPrototypeReservedIPIdentityVirtualNetworkInterfaceIPsContextByHref); ok { + return dataSourceIBMIsInstanceTemplateVirtualNetworkInterfaceIPPrototypeReservedIPIdentityVirtualNetworkInterfaceIPsContextByHrefToMap(model.(*vpcv1.VirtualNetworkInterfaceIPPrototypeReservedIPIdentityVirtualNetworkInterfaceIPsContextByHref)) + } else if _, ok := model.(*vpcv1.VirtualNetworkInterfaceIPPrototypeReservedIPIdentityVirtualNetworkInterfaceIPsContext); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.VirtualNetworkInterfaceIPPrototypeReservedIPIdentityVirtualNetworkInterfaceIPsContext) + 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.VirtualNetworkInterfaceIPPrototypeReservedIPIdentityVirtualNetworkInterfaceIPsContextIntf subtype encountered") + } +} +func dataSourceIBMIsInstanceTemplateVirtualNetworkInterfaceIPPrototypeReservedIPPrototypeVirtualNetworkInterfaceIPsContextToMap(model *vpcv1.VirtualNetworkInterfaceIPPrototypeReservedIPPrototypeVirtualNetworkInterfaceIPsContext) (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 dataSourceIBMIsInstanceTemplateVirtualNetworkInterfaceIPPrototypeToMap(model vpcv1.VirtualNetworkInterfaceIPPrototypeIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.VirtualNetworkInterfaceIPPrototypeReservedIPIdentityVirtualNetworkInterfaceIPsContext); ok { + return dataSourceIBMIsInstanceTemplateVirtualNetworkInterfaceIPPrototypeReservedIPIdentityVirtualNetworkInterfaceIPsContextToMap(model.(*vpcv1.VirtualNetworkInterfaceIPPrototypeReservedIPIdentityVirtualNetworkInterfaceIPsContext)) + } else if _, ok := model.(*vpcv1.VirtualNetworkInterfaceIPPrototypeReservedIPPrototypeVirtualNetworkInterfaceIPsContext); ok { + return dataSourceIBMIsInstanceTemplateVirtualNetworkInterfaceIPPrototypeReservedIPPrototypeVirtualNetworkInterfaceIPsContextToMap(model.(*vpcv1.VirtualNetworkInterfaceIPPrototypeReservedIPPrototypeVirtualNetworkInterfaceIPsContext)) + } else if _, ok := model.(*vpcv1.VirtualNetworkInterfaceIPPrototype); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.VirtualNetworkInterfaceIPPrototype) + 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.VirtualNetworkInterfaceIPPrototypeIntf subtype encountered") + } +} +func dataSourceIBMIsInstanceTemplateVirtualNetworkInterfacePrimaryIPPrototypeReservedIPIdentityVirtualNetworkInterfacePrimaryIPContextToMap(model vpcv1.VirtualNetworkInterfacePrimaryIPPrototypeReservedIPIdentityVirtualNetworkInterfacePrimaryIPContextIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.VirtualNetworkInterfacePrimaryIPPrototypeReservedIPIdentityVirtualNetworkInterfacePrimaryIPContextByID); ok { + return dataSourceIBMIsInstanceTemplateVirtualNetworkInterfacePrimaryIPPrototypeReservedIPIdentityVirtualNetworkInterfacePrimaryIPContextByIDToMap(model.(*vpcv1.VirtualNetworkInterfacePrimaryIPPrototypeReservedIPIdentityVirtualNetworkInterfacePrimaryIPContextByID)) + } else if _, ok := model.(*vpcv1.VirtualNetworkInterfacePrimaryIPPrototypeReservedIPIdentityVirtualNetworkInterfacePrimaryIPContextByHref); ok { + return dataSourceIBMIsInstanceTemplateVirtualNetworkInterfacePrimaryIPPrototypeReservedIPIdentityVirtualNetworkInterfacePrimaryIPContextByHrefToMap(model.(*vpcv1.VirtualNetworkInterfacePrimaryIPPrototypeReservedIPIdentityVirtualNetworkInterfacePrimaryIPContextByHref)) + } else if _, ok := model.(*vpcv1.VirtualNetworkInterfacePrimaryIPPrototypeReservedIPIdentityVirtualNetworkInterfacePrimaryIPContext); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.VirtualNetworkInterfacePrimaryIPPrototypeReservedIPIdentityVirtualNetworkInterfacePrimaryIPContext) + 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.VirtualNetworkInterfacePrimaryIPPrototypeReservedIPIdentityVirtualNetworkInterfacePrimaryIPContextIntf subtype encountered") + } +} +func dataSourceIBMIsInstanceTemplateVirtualNetworkInterfacePrimaryIPPrototypeReservedIPIdentityVirtualNetworkInterfacePrimaryIPContextByIDToMap(model *vpcv1.VirtualNetworkInterfacePrimaryIPPrototypeReservedIPIdentityVirtualNetworkInterfacePrimaryIPContextByID) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["id"] = model.ID + return modelMap, nil +} + +func dataSourceIBMIsInstanceTemplateVirtualNetworkInterfacePrimaryIPPrototypeReservedIPIdentityVirtualNetworkInterfacePrimaryIPContextByHrefToMap(model *vpcv1.VirtualNetworkInterfacePrimaryIPPrototypeReservedIPIdentityVirtualNetworkInterfacePrimaryIPContextByHref) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = model.Href + return modelMap, nil +} +func dataSourceIBMIsInstanceTemplateVirtualNetworkInterfacePrimaryIPPrototypeReservedIPPrototypeVirtualNetworkInterfacePrimaryIPContextToMap(model *vpcv1.VirtualNetworkInterfacePrimaryIPPrototypeReservedIPPrototypeVirtualNetworkInterfacePrimaryIPContext) (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 dataSourceIBMIsInstanceTemplateVirtualNetworkInterfacePrimaryIPPrototypeToMap(model vpcv1.VirtualNetworkInterfacePrimaryIPPrototypeIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.VirtualNetworkInterfacePrimaryIPPrototypeReservedIPIdentityVirtualNetworkInterfacePrimaryIPContext); ok { + return dataSourceIBMIsInstanceTemplateVirtualNetworkInterfacePrimaryIPPrototypeReservedIPIdentityVirtualNetworkInterfacePrimaryIPContextToMap(model.(*vpcv1.VirtualNetworkInterfacePrimaryIPPrototypeReservedIPIdentityVirtualNetworkInterfacePrimaryIPContext)) + } else if _, ok := model.(*vpcv1.VirtualNetworkInterfacePrimaryIPPrototypeReservedIPPrototypeVirtualNetworkInterfacePrimaryIPContext); ok { + return dataSourceIBMIsInstanceTemplateVirtualNetworkInterfacePrimaryIPPrototypeReservedIPPrototypeVirtualNetworkInterfacePrimaryIPContextToMap(model.(*vpcv1.VirtualNetworkInterfacePrimaryIPPrototypeReservedIPPrototypeVirtualNetworkInterfacePrimaryIPContext)) + } else if _, ok := model.(*vpcv1.VirtualNetworkInterfacePrimaryIPPrototype); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.VirtualNetworkInterfacePrimaryIPPrototype) + 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.VirtualNetworkInterfacePrimaryIPPrototypeIntf subtype encountered") + } +} + +func dataSourceIBMIsInstanceTemplateResourceGroupIdentityByIDToMap(model *vpcv1.ResourceGroupIdentityByID) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["id"] = model.ID + return modelMap, nil +} +func dataSourceIBMIsInstanceTemplateResourceGroupIdentityToMap(model vpcv1.ResourceGroupIdentityIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.ResourceGroupIdentityByID); ok { + return dataSourceIBMIsInstanceTemplateResourceGroupIdentityByIDToMap(model.(*vpcv1.ResourceGroupIdentityByID)) + } else if _, ok := model.(*vpcv1.ResourceGroupIdentity); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.ResourceGroupIdentity) + if model.ID != nil { + modelMap["id"] = model.ID + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.ResourceGroupIdentityIntf subtype encountered") + } +} + +func dataSourceIBMIsInstanceTemplateSecurityGroupIdentityToMap(model vpcv1.SecurityGroupIdentityIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.SecurityGroupIdentityByID); ok { + return dataSourceIBMIsInstanceTemplateSecurityGroupIdentityByIDToMap(model.(*vpcv1.SecurityGroupIdentityByID)) + } else if _, ok := model.(*vpcv1.SecurityGroupIdentityByCRN); ok { + return dataSourceIBMIsInstanceTemplateSecurityGroupIdentityByCRNToMap(model.(*vpcv1.SecurityGroupIdentityByCRN)) + } else if _, ok := model.(*vpcv1.SecurityGroupIdentityByHref); ok { + return dataSourceIBMIsInstanceTemplateSecurityGroupIdentityByHrefToMap(model.(*vpcv1.SecurityGroupIdentityByHref)) + } else if _, ok := model.(*vpcv1.SecurityGroupIdentity); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.SecurityGroupIdentity) + if model.ID != nil { + modelMap["id"] = model.ID + } + if model.CRN != nil { + modelMap["crn"] = model.CRN + } + if model.Href != nil { + modelMap["href"] = model.Href + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.SecurityGroupIdentityIntf subtype encountered") + } +} + +func dataSourceIBMIsInstanceTemplateSecurityGroupIdentityByIDToMap(model *vpcv1.SecurityGroupIdentityByID) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["id"] = model.ID + return modelMap, nil +} + +func dataSourceIBMIsInstanceTemplateSecurityGroupIdentityByCRNToMap(model *vpcv1.SecurityGroupIdentityByCRN) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = model.CRN + return modelMap, nil +} + +func dataSourceIBMIsInstanceTemplateSecurityGroupIdentityByHrefToMap(model *vpcv1.SecurityGroupIdentityByHref) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = model.Href + return modelMap, nil +} + +func dataSourceIBMIsInstanceTemplateSubnetIdentityToMap(model vpcv1.SubnetIdentityIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.SubnetIdentityByID); ok { + return dataSourceIBMIsInstanceTemplateSubnetIdentityByIDToMap(model.(*vpcv1.SubnetIdentityByID)) + } else if _, ok := model.(*vpcv1.SubnetIdentityByCRN); ok { + return dataSourceIBMIsInstanceTemplateSubnetIdentityByCRNToMap(model.(*vpcv1.SubnetIdentityByCRN)) + } else if _, ok := model.(*vpcv1.SubnetIdentityByHref); ok { + return dataSourceIBMIsInstanceTemplateSubnetIdentityByHrefToMap(model.(*vpcv1.SubnetIdentityByHref)) + } else if _, ok := model.(*vpcv1.SubnetIdentity); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.SubnetIdentity) + if model.ID != nil { + modelMap["id"] = model.ID + } + if model.CRN != nil { + modelMap["crn"] = model.CRN + } + if model.Href != nil { + modelMap["href"] = model.Href + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.SubnetIdentityIntf subtype encountered") + } +} + +func dataSourceIBMIsInstanceTemplateSubnetIdentityByIDToMap(model *vpcv1.SubnetIdentityByID) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["id"] = model.ID + return modelMap, nil +} + +func dataSourceIBMIsInstanceTemplateSubnetIdentityByCRNToMap(model *vpcv1.SubnetIdentityByCRN) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = model.CRN + return modelMap, nil +} + +func dataSourceIBMIsInstanceTemplateSubnetIdentityByHrefToMap(model *vpcv1.SubnetIdentityByHref) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = model.Href + return modelMap, nil +} + +func dataSourceIBMIsInstanceTemplateInstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceToMap(model vpcv1.InstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.InstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceVirtualNetworkInterfacePrototypeInstanceNetworkAttachmentContext); ok { + return dataSourceIBMIsInstanceTemplateInstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceVirtualNetworkInterfacePrototypeInstanceNetworkAttachmentContextToMap(model.(*vpcv1.InstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceVirtualNetworkInterfacePrototypeInstanceNetworkAttachmentContext)) + } else if _, ok := model.(*vpcv1.InstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceVirtualNetworkInterfaceIdentity); ok { + return dataSourceIBMIsInstanceTemplateInstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceVirtualNetworkInterfaceIdentityToMap(model.(*vpcv1.InstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceVirtualNetworkInterfaceIdentity)) + } else if _, ok := model.(*vpcv1.InstanceNetworkAttachmentPrototypeVirtualNetworkInterface); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.InstanceNetworkAttachmentPrototypeVirtualNetworkInterface) + if model.AllowIPSpoofing != nil { + modelMap["allow_ip_spoofing"] = model.AllowIPSpoofing + } + if model.AutoDelete != nil { + modelMap["auto_delete"] = model.AutoDelete + } + if model.EnableInfrastructureNat != nil { + modelMap["enable_infrastructure_nat"] = model.EnableInfrastructureNat + } + if model.Ips != nil { + ips := []map[string]interface{}{} + for _, ipsItem := range model.Ips { + ipsItemMap, err := dataSourceIBMIsInstanceTemplateVirtualNetworkInterfaceIPPrototypeToMap(ipsItem) + if err != nil { + return modelMap, err + } + ips = append(ips, ipsItemMap) + } + modelMap["ips"] = ips + } + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.PrimaryIP != nil { + primaryIPMap, err := dataSourceIBMIsInstanceTemplateVirtualNetworkInterfacePrimaryIPPrototypeToMap(model.PrimaryIP) + if err != nil { + return modelMap, err + } + modelMap["primary_ip"] = []map[string]interface{}{primaryIPMap} + } + if model.ResourceGroup != nil { + resourceGroupMap, err := dataSourceIBMIsInstanceTemplateResourceGroupIdentityToMap(model.ResourceGroup) + if err != nil { + return modelMap, err + } + modelMap["resource_group"] = []map[string]interface{}{resourceGroupMap} + } + if model.SecurityGroups != nil { + securityGroups := []map[string]interface{}{} + for _, securityGroupsItem := range model.SecurityGroups { + securityGroupsItemMap, err := dataSourceIBMIsInstanceTemplateSecurityGroupIdentityToMap(securityGroupsItem) + if err != nil { + return modelMap, err + } + securityGroups = append(securityGroups, securityGroupsItemMap) + } + modelMap["security_groups"] = securityGroups + } + if model.Subnet != nil { + subnetMap, err := dataSourceIBMIsInstanceTemplateSubnetIdentityToMap(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 + } + if model.CRN != nil { + modelMap["crn"] = model.CRN + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.InstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceIntf subtype encountered") + } +} +func dataSourceIBMIsInstanceTemplateInstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceVirtualNetworkInterfacePrototypeInstanceNetworkAttachmentContextToMap(model *vpcv1.InstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceVirtualNetworkInterfacePrototypeInstanceNetworkAttachmentContext) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.AllowIPSpoofing != nil { + modelMap["allow_ip_spoofing"] = model.AllowIPSpoofing + } + if model.AutoDelete != nil { + modelMap["auto_delete"] = model.AutoDelete + } + if model.EnableInfrastructureNat != nil { + modelMap["enable_infrastructure_nat"] = model.EnableInfrastructureNat + } + if model.Ips != nil { + ips := []map[string]interface{}{} + for _, ipsItem := range model.Ips { + ipsItemMap, err := dataSourceIBMIsInstanceTemplateVirtualNetworkInterfaceIPPrototypeToMap(ipsItem) + if err != nil { + return modelMap, err + } + ips = append(ips, ipsItemMap) + } + modelMap["ips"] = ips + } + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.PrimaryIP != nil { + primaryIPMap, err := dataSourceIBMIsInstanceTemplateVirtualNetworkInterfacePrimaryIPPrototypeToMap(model.PrimaryIP) + if err != nil { + return modelMap, err + } + modelMap["primary_ip"] = []map[string]interface{}{primaryIPMap} + } + if model.ResourceGroup != nil { + resourceGroupMap, err := dataSourceIBMIsInstanceTemplateResourceGroupIdentityToMap(model.ResourceGroup) + if err != nil { + return modelMap, err + } + modelMap["resource_group"] = []map[string]interface{}{resourceGroupMap} + } + if model.SecurityGroups != nil { + securityGroups := []map[string]interface{}{} + for _, securityGroupsItem := range model.SecurityGroups { + securityGroupsItemMap, err := dataSourceIBMIsInstanceTemplateSecurityGroupIdentityToMap(securityGroupsItem) + if err != nil { + return modelMap, err + } + securityGroups = append(securityGroups, securityGroupsItemMap) + } + modelMap["security_groups"] = securityGroups + } + if model.Subnet != nil { + subnetMap, err := dataSourceIBMIsInstanceTemplateSubnetIdentityToMap(model.Subnet) + if err != nil { + return modelMap, err + } + modelMap["subnet"] = []map[string]interface{}{subnetMap} + } + return modelMap, nil +} + +func dataSourceIBMIsInstanceTemplateInstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceVirtualNetworkInterfaceIdentityToMap(model vpcv1.InstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceVirtualNetworkInterfaceIdentityIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.InstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceVirtualNetworkInterfaceIdentityVirtualNetworkInterfaceIdentityByID); ok { + return dataSourceIBMIsInstanceTemplateInstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceVirtualNetworkInterfaceIdentityVirtualNetworkInterfaceIdentityByIDToMap(model.(*vpcv1.InstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceVirtualNetworkInterfaceIdentityVirtualNetworkInterfaceIdentityByID)) + } else if _, ok := model.(*vpcv1.InstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceVirtualNetworkInterfaceIdentityVirtualNetworkInterfaceIdentityByHref); ok { + return dataSourceIBMIsInstanceTemplateInstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceVirtualNetworkInterfaceIdentityVirtualNetworkInterfaceIdentityByHrefToMap(model.(*vpcv1.InstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceVirtualNetworkInterfaceIdentityVirtualNetworkInterfaceIdentityByHref)) + } else if _, ok := model.(*vpcv1.InstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceVirtualNetworkInterfaceIdentityVirtualNetworkInterfaceIdentityByCRN); ok { + return dataSourceIBMIsInstanceTemplateInstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceVirtualNetworkInterfaceIdentityVirtualNetworkInterfaceIdentityByCRNToMap(model.(*vpcv1.InstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceVirtualNetworkInterfaceIdentityVirtualNetworkInterfaceIdentityByCRN)) + } else if _, ok := model.(*vpcv1.InstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceVirtualNetworkInterfaceIdentity); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.InstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceVirtualNetworkInterfaceIdentity) + if model.ID != nil { + modelMap["id"] = model.ID + } + if model.Href != nil { + modelMap["href"] = model.Href + } + if model.CRN != nil { + modelMap["crn"] = model.CRN + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.InstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceVirtualNetworkInterfaceIdentityIntf subtype encountered") + } +} + +func dataSourceIBMIsInstanceTemplateInstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceVirtualNetworkInterfaceIdentityVirtualNetworkInterfaceIdentityByIDToMap(model *vpcv1.InstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceVirtualNetworkInterfaceIdentityVirtualNetworkInterfaceIdentityByID) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["id"] = model.ID + return modelMap, nil +} + +func dataSourceIBMIsInstanceTemplateInstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceVirtualNetworkInterfaceIdentityVirtualNetworkInterfaceIdentityByHrefToMap(model *vpcv1.InstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceVirtualNetworkInterfaceIdentityVirtualNetworkInterfaceIdentityByHref) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = model.Href + return modelMap, nil +} + +func dataSourceIBMIsInstanceTemplateInstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceVirtualNetworkInterfaceIdentityVirtualNetworkInterfaceIdentityByCRNToMap(model *vpcv1.InstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceVirtualNetworkInterfaceIdentityVirtualNetworkInterfaceIdentityByCRN) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = model.CRN + return modelMap, nil +} + +func dataSourceIBMIsInstanceTemplateNetworkInterfacePrototypeToMap(model *vpcv1.NetworkInterfacePrototype) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.AllowIPSpoofing != nil { + modelMap["allow_ip_spoofing"] = model.AllowIPSpoofing + } + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.PrimaryIP != nil { + primaryIPMap, err := dataSourceIBMIsInstanceTemplateNetworkInterfaceIPPrototypeToMap(model.PrimaryIP) + if err != nil { + return modelMap, err + } + modelMap["primary_ip"] = []map[string]interface{}{primaryIPMap} + } + if model.SecurityGroups != nil { + securityGroups := []map[string]interface{}{} + for _, securityGroupsItem := range model.SecurityGroups { + securityGroupsItemMap, err := dataSourceIBMIsInstanceTemplateSecurityGroupIdentityToMap(securityGroupsItem) + if err != nil { + return modelMap, err + } + securityGroups = append(securityGroups, securityGroupsItemMap) + } + modelMap["security_groups"] = securityGroups + } + subnetMap, err := dataSourceIBMIsInstanceTemplateSubnetIdentityToMap(model.Subnet) + if err != nil { + return modelMap, err + } + modelMap["subnet"] = []map[string]interface{}{subnetMap} + return modelMap, nil +} + +func dataSourceIBMIsInstanceTemplateNetworkInterfaceIPPrototypeToMap(model vpcv1.NetworkInterfaceIPPrototypeIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity); ok { + return dataSourceIBMIsInstanceTemplateNetworkInterfaceIPPrototypeReservedIPIdentityToMap(model.(*vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity)) + } else if _, ok := model.(*vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext); ok { + return dataSourceIBMIsInstanceTemplateNetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContextToMap(model.(*vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext)) + } else if _, ok := model.(*vpcv1.NetworkInterfaceIPPrototype); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.NetworkInterfaceIPPrototype) + 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.NetworkInterfaceIPPrototypeIntf subtype encountered") + } +} + +func dataSourceIBMIsInstanceTemplateNetworkInterfaceIPPrototypeReservedIPIdentityToMap(model vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentityIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentityByID); ok { + return dataSourceIBMIsInstanceTemplateNetworkInterfaceIPPrototypeReservedIPIdentityByIDToMap(model.(*vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentityByID)) + } else if _, ok := model.(*vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentityByHref); ok { + return dataSourceIBMIsInstanceTemplateNetworkInterfaceIPPrototypeReservedIPIdentityByHrefToMap(model.(*vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentityByHref)) + } else if _, ok := model.(*vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity) + 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.NetworkInterfaceIPPrototypeReservedIPIdentityIntf subtype encountered") + } +} + +func dataSourceIBMIsInstanceTemplateNetworkInterfaceIPPrototypeReservedIPIdentityByIDToMap(model *vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentityByID) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["id"] = model.ID + return modelMap, nil +} + +func dataSourceIBMIsInstanceTemplateNetworkInterfaceIPPrototypeReservedIPIdentityByHrefToMap(model *vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentityByHref) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = model.Href + return modelMap, nil +} + +func dataSourceIBMIsInstanceTemplateNetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContextToMap(model *vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext) (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 dataSourceIBMIsInstanceTemplateInstanceCatalogOfferingPrototypeToMap(model vpcv1.InstanceCatalogOfferingPrototypeIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.InstanceCatalogOfferingPrototypeCatalogOfferingByOffering); ok { + return dataSourceIBMIsInstanceTemplateInstanceCatalogOfferingPrototypeCatalogOfferingByOfferingToMap(model.(*vpcv1.InstanceCatalogOfferingPrototypeCatalogOfferingByOffering)) + } else if _, ok := model.(*vpcv1.InstanceCatalogOfferingPrototypeCatalogOfferingByVersion); ok { + return dataSourceIBMIsInstanceTemplateInstanceCatalogOfferingPrototypeCatalogOfferingByVersionToMap(model.(*vpcv1.InstanceCatalogOfferingPrototypeCatalogOfferingByVersion)) + } else if _, ok := model.(*vpcv1.InstanceCatalogOfferingPrototype); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.InstanceCatalogOfferingPrototype) + if model.Offering != nil { + offeringMap, err := dataSourceIBMIsInstanceTemplateCatalogOfferingIdentityToMap(model.Offering) + if err != nil { + return modelMap, err + } + modelMap["offering"] = []map[string]interface{}{offeringMap} + } + if model.Version != nil { + versionMap, err := dataSourceIBMIsInstanceTemplateCatalogOfferingVersionIdentityToMap(model.Version) + if err != nil { + return modelMap, err + } + modelMap["version"] = []map[string]interface{}{versionMap} + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.InstanceCatalogOfferingPrototypeIntf subtype encountered") + } +} + +func dataSourceIBMIsInstanceTemplateCatalogOfferingIdentityToMap(model vpcv1.CatalogOfferingIdentityIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.CatalogOfferingIdentityCatalogOfferingByCRN); ok { + return dataSourceIBMIsInstanceTemplateCatalogOfferingIdentityCatalogOfferingByCRNToMap(model.(*vpcv1.CatalogOfferingIdentityCatalogOfferingByCRN)) + } else if _, ok := model.(*vpcv1.CatalogOfferingIdentity); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.CatalogOfferingIdentity) + if model.CRN != nil { + modelMap["crn"] = model.CRN + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.CatalogOfferingIdentityIntf subtype encountered") + } +} + +func dataSourceIBMIsInstanceTemplateCatalogOfferingIdentityCatalogOfferingByCRNToMap(model *vpcv1.CatalogOfferingIdentityCatalogOfferingByCRN) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = model.CRN + return modelMap, nil +} + +func dataSourceIBMIsInstanceTemplateCatalogOfferingVersionIdentityToMap(model vpcv1.CatalogOfferingVersionIdentityIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.CatalogOfferingVersionIdentityCatalogOfferingVersionByCRN); ok { + return dataSourceIBMIsInstanceTemplateCatalogOfferingVersionIdentityCatalogOfferingVersionByCRNToMap(model.(*vpcv1.CatalogOfferingVersionIdentityCatalogOfferingVersionByCRN)) + } else if _, ok := model.(*vpcv1.CatalogOfferingVersionIdentity); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.CatalogOfferingVersionIdentity) + if model.CRN != nil { + modelMap["crn"] = model.CRN + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.CatalogOfferingVersionIdentityIntf subtype encountered") + } +} + +func dataSourceIBMIsInstanceTemplateCatalogOfferingVersionIdentityCatalogOfferingVersionByCRNToMap(model *vpcv1.CatalogOfferingVersionIdentityCatalogOfferingVersionByCRN) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = model.CRN + return modelMap, nil +} + +func dataSourceIBMIsInstanceTemplateInstanceCatalogOfferingPrototypeCatalogOfferingByOfferingToMap(model *vpcv1.InstanceCatalogOfferingPrototypeCatalogOfferingByOffering) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + offeringMap, err := dataSourceIBMIsInstanceTemplateCatalogOfferingIdentityToMap(model.Offering) + if err != nil { + return modelMap, err + } + modelMap["offering"] = []map[string]interface{}{offeringMap} + return modelMap, nil +} + +func dataSourceIBMIsInstanceTemplateInstanceCatalogOfferingPrototypeCatalogOfferingByVersionToMap(model *vpcv1.InstanceCatalogOfferingPrototypeCatalogOfferingByVersion) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + versionMap, err := dataSourceIBMIsInstanceTemplateCatalogOfferingVersionIdentityToMap(model.Version) + if err != nil { + return modelMap, err + } + modelMap["version"] = []map[string]interface{}{versionMap} + 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 6f315ced6a..648dc6c35a 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,62 @@ func TestAccIBMISInstanceTemplate_dataBasic(t *testing.T) { }, }) } +func TestAccIBMISInstanceTemplate_dataVni(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: testAccCheckIBMISInstanceTemplateDVniConfig(vpcName, subnetName, sshKeyName, publicKey, templateName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "data.ibm_is_instance_template.instance_template_data", "name", templateName), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data", "network_attachments.#"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data", "network_attachments.#"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data", "network_attachments.#"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data", "network_attachments.#"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data", "network_attachments.#"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data", "primary_network_attachment.#"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data", "primary_network_attachment.0.name"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data", "primary_network_attachment.0.virtual_network_interface.#"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data", "primary_network_attachment.0.virtual_network_interface.0.allow_ip_spoofing"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data", "primary_network_attachment.0.virtual_network_interface.0.auto_delete"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data", "primary_network_attachment.0.virtual_network_interface.0.enable_infrastructure_nat"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data", "primary_network_attachment.0.virtual_network_interface.0.ips.#"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data", "primary_network_attachment.0.virtual_network_interface.0.name"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data", "primary_network_attachment.0.virtual_network_interface.0.primary_ip.#"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data", "primary_network_attachment.0.virtual_network_interface.0.security_groups.#"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data", "primary_network_attachment.0.virtual_network_interface.0.subnet.#"), + ), + }, + }, + }) +} func TestAccIBMISInstanceTemplate_data_catalog(t *testing.T) { randInt := acctest.RandIntRange(600, 700) publicKey := strings.TrimSpace(` @@ -104,6 +160,13 @@ func testAccCheckIBMISInstanceTemplateDConfig(vpcName, subnetName, sshKeyName, p } `) } +func testAccCheckIBMISInstanceTemplateDVniConfig(vpcName, subnetName, sshKeyName, publicKey, templateName string) string { + return testAccCheckIBMISInstanceTemplateVniConfig(vpcName, subnetName, sshKeyName, publicKey, templateName) + fmt.Sprintf(` + data "ibm_is_instance_template" "instance_template_data" { + name = ibm_is_instance_template.instancetemplate1.name + } + `) +} func testAccCheckIBMISInstanceTemplateDCatalogConfig(vpcName, subnetName, sshKeyName, publicKey, templateName string) string { return testAccCheckIBMISInstanceTemplateCatalogConfig(vpcName, subnetName, sshKeyName, publicKey, templateName) + 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 02db3fa65f..8b6fe49efb 100644 --- a/ibm/service/vpc/data_source_ibm_is_instance_templates.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_templates.go @@ -280,6 +280,383 @@ func DataSourceIBMISInstanceTemplates() *schema.Resource { }, }, + "network_attachments": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The additional network attachments to create for the virtual server instance.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this network attachment. Names must be unique within the instance the network attachment resides in. If unspecified, the name will be a hyphenated list of randomly-selected words.", + }, + "virtual_network_interface": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "A virtual network interface for the instance network attachment. This can be specifiedusing an existing virtual network interface, or a prototype object for a new virtualnetwork interface.If an existing virtual network interface is specified, `enable_infrastructure_nat` must be`false`.", + 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 interface. If `false`, source IP spoofing is prevented on this interface. If `true`, source IP spoofing is allowed on this interface.", + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether this virtual network interface will be automatically deleted when`target` is deleted.", + }, + "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.- `allow_ip_spoofing` must be `false`.- If the virtual network interface is attached: - The target `resource_type` must be `bare_metal_server_network_attachment`. - The target `interface_type` must not be `hipersocket`.", + }, + "ips": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Additional IP addresses to bind to the virtual network interface. Each item may be either a reserved IP identity, or as a reserved IP prototype object which will be used to create a new reserved IP. All IP addresses must be in the same subnet as the primary IP.If reserved IP identities are provided, the specified reserved IPs must be unbound.If reserved IP prototype objects with addresses are provided, the addresses must be available on the virtual network interface's subnet. For any prototype objects that do not specify an address, an available address on the subnet will 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 reserved IP.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this 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 reserved IP member will be automatically deleted when either`target` is deleted, or the reserved IP is unbound.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this reserved IP. The name must not be used by another reserved IP in the 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.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this virtual network interface. The name must not be used by another virtual network interface in the VPC. If unspecified, the name will be a hyphenated list of randomly-selected words. Names beginning with `ibm-` are reserved for provider-owned resources, and are not allowed.", + }, + "primary_ip": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The primary IP address to bind to the virtual network interface. May be either areserved IP identity, or a reserved IP prototype object which will be used to create anew reserved IP.If a reserved IP identity is provided, the specified reserved IP must be unbound.If a reserved IP prototype object with an address is provided, the address must beavailable on the virtual network interface's subnet. If no address is specified,an available address on the subnet will 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 reserved IP.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this 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 reserved IP member will be automatically deleted when either`target` is deleted, or the reserved IP is unbound.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this reserved IP. The name must not be used by another reserved IP in the 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.", + }, + }, + }, + }, + "resource_group": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The resource group to use for this virtual network interface. If unspecified, thevirtual server instance's resource group will be used.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this resource group.", + }, + }, + }, + }, + "security_groups": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The security groups to use for this virtual network interface. If unspecified, the default security group of the VPC for the subnet is used.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this security group.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The security group's CRN.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The security group's canonical URL.", + }, + }, + }, + }, + "subnet": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The associated subnet. Required if `primary_ip` does not specify a reserved IP.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this subnet.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this subnet.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this subnet.", + }, + }, + }, + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this virtual network interface.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this virtual network interface.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this virtual network interface.", + }, + }, + }, + }, + }, + }, + }, + "primary_network_attachment": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The primary network attachment to create for the virtual server instance.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this network attachment. Names must be unique within the instance the network attachment resides in. If unspecified, the name will be a hyphenated list of randomly-selected words.", + }, + "virtual_network_interface": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "A virtual network interface for the instance network attachment. This can be specifiedusing an existing virtual network interface, or a prototype object for a new virtualnetwork interface.If an existing virtual network interface is specified, `enable_infrastructure_nat` must be`false`.", + 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 interface. If `false`, source IP spoofing is prevented on this interface. If `true`, source IP spoofing is allowed on this interface.", + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether this virtual network interface will be automatically deleted when`target` is deleted.", + }, + "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.- `allow_ip_spoofing` must be `false`.- If the virtual network interface is attached: - The target `resource_type` must be `bare_metal_server_network_attachment`. - The target `interface_type` must not be `hipersocket`.", + }, + "ips": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Additional IP addresses to bind to the virtual network interface. Each item may be either a reserved IP identity, or as a reserved IP prototype object which will be used to create a new reserved IP. All IP addresses must be in the same subnet as the primary IP.If reserved IP identities are provided, the specified reserved IPs must be unbound.If reserved IP prototype objects with addresses are provided, the addresses must be available on the virtual network interface's subnet. For any prototype objects that do not specify an address, an available address on the subnet will 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 reserved IP.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this 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 reserved IP member will be automatically deleted when either`target` is deleted, or the reserved IP is unbound.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this reserved IP. The name must not be used by another reserved IP in the 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.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this virtual network interface. The name must not be used by another virtual network interface in the VPC. If unspecified, the name will be a hyphenated list of randomly-selected words. Names beginning with `ibm-` are reserved for provider-owned resources, and are not allowed.", + }, + "primary_ip": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The primary IP address to bind to the virtual network interface. May be either areserved IP identity, or a reserved IP prototype object which will be used to create anew reserved IP.If a reserved IP identity is provided, the specified reserved IP must be unbound.If a reserved IP prototype object with an address is provided, the address must beavailable on the virtual network interface's subnet. If no address is specified,an available address on the subnet will 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 reserved IP.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this 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 reserved IP member will be automatically deleted when either`target` is deleted, or the reserved IP is unbound.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this reserved IP. The name must not be used by another reserved IP in the 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.", + }, + }, + }, + }, + "resource_group": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The resource group to use for this virtual network interface. If unspecified, thevirtual server instance's resource group will be used.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this resource group.", + }, + }, + }, + }, + "security_groups": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The security groups to use for this virtual network interface. If unspecified, the default security group of the VPC for the subnet is used.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this security group.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The security group's CRN.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The security group's canonical URL.", + }, + }, + }, + }, + "subnet": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The associated subnet. Required if `primary_ip` does not specify a reserved IP.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this subnet.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this subnet.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this subnet.", + }, + }, + }, + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this virtual network interface.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this virtual network interface.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this virtual network interface.", + }, + }, + }, + }, + }, + }, + }, + isInstanceTemplatePrimaryNetworkInterface: { Type: schema.TypeList, Computed: true, @@ -428,6 +805,24 @@ func DataSourceIBMISInstanceTemplates() *schema.Resource { Type: schema.TypeString, Computed: true, }, + 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 virtual server instance.", + }, + isReservationAffinityPool: { + Type: schema.TypeString, + Computed: true, + Description: "The reservation associated with this template.", + }, + }, + }, + }, }, }, }, @@ -544,6 +939,30 @@ func dataSourceIBMISInstanceTemplatesRead(d *schema.ResourceData, meta interface template[isInstanceTotalVolumeBandwidth] = int(*instance.TotalVolumeBandwidth) } + // vni + + networkAttachments := []map[string]interface{}{} + if instance.NetworkAttachments != nil { + for _, modelItem := range instance.NetworkAttachments { + modelMap, err := dataSourceIBMIsInstanceTemplateInstanceNetworkAttachmentPrototypeToMap(&modelItem) + if err != nil { + return err + } + networkAttachments = append(networkAttachments, modelMap) + } + } + template["network_attachments"] = networkAttachments + + primaryNetworkAttachment := []map[string]interface{}{} + if instance.PrimaryNetworkAttachment != nil { + modelMap, err := dataSourceIBMIsInstanceTemplateInstanceNetworkAttachmentPrototypeToMap(instance.PrimaryNetworkAttachment) + if err != nil { + return err + } + primaryNetworkAttachment = append(primaryNetworkAttachment, modelMap) + } + template["primary_network_attachment"] = primaryNetworkAttachment + if instance.PrimaryNetworkInterface != nil { interfaceList := make([]map[string]interface{}, 0) currentPrimNic := map[string]interface{}{} @@ -725,6 +1144,26 @@ func dataSourceIBMISInstanceTemplatesRead(d *schema.ResourceData, meta interface bootVolList = append(bootVolList, bootVol) template[isInstanceTemplatesBootVolumeAttachment] = bootVolList } + if instance.ReservationAffinity != nil { + reservationAffinity := []map[string]interface{}{} + reservationAffinityMap := map[string]interface{}{} + + reservationAffinityMap[isReservationAffinityPolicyResp] = instance.ReservationAffinity.Policy + if instance.ReservationAffinity.Pool != nil && len(instance.ReservationAffinity.Pool) > 0 { + pool := instance.ReservationAffinity.Pool[0] + res := "" + if idPool, ok := pool.(*vpcv1.ReservationIdentityByID); ok { + res = *idPool.ID + } else if crnPool, ok := pool.(*vpcv1.ReservationIdentityByCRN); ok { + res = *crnPool.CRN + } else if hrefPool, ok := pool.(*vpcv1.ReservationIdentityByHref); ok { + res = *hrefPool.Href + } + reservationAffinityMap[isReservationAffinityPool] = res + } + reservationAffinity = append(reservationAffinity, reservationAffinityMap) + template[isReservationAffinity] = reservationAffinity + } if instance.ResourceGroup != nil { rg := instance.ResourceGroup 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 7771f5b328..c16600ed22 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,32 @@ func TestAccIBMISInstanceTemplates_dataBasic(t *testing.T) { }, }) } +func TestAccIBMISInstanceTemplates_dataVni(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: testAccCheckIBMISInstanceTemplatesDVniConfig(vpcName, subnetName, sshKeyName, publicKey, templateName), + Check: resource.ComposeTestCheckFunc( + 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.name"), + ), + }, + }, + }) +} func TestAccIBMISInstanceTemplates_dataCatalog(t *testing.T) { randInt := acctest.RandIntRange(600, 700) publicKey := strings.TrimSpace(` @@ -109,6 +135,14 @@ func testAccCheckIBMISInstanceTemplatesDConfig(vpcName, subnetName, sshKeyName, } `) } +func testAccCheckIBMISInstanceTemplatesDVniConfig(vpcName, subnetName, sshKeyName, publicKey, templateName string) string { + return testAccCheckIBMISInstanceTemplateVniConfig(vpcName, subnetName, sshKeyName, publicKey, templateName) + fmt.Sprintf(` + + data "ibm_is_instance_templates" "instance_templates_data" { + depends_on = [ibm_is_instance_template.instancetemplate1] + } + `) +} func testAccCheckIBMISInstanceTemplatesDCatalogConfig(vpcName, subnetName, sshKeyName, publicKey, templateName string) string { return testAccCheckIBMISInstanceTemplateCatalogConfig(vpcName, subnetName, sshKeyName, publicKey, templateName) + 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 fe42000ab0..389e0e92dc 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,51 @@ func TestAccIBMISInstanceDataSource_basic(t *testing.T) { }, }) } +func TestAccIBMISInstanceDataSource_vni(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)) + vniname := fmt.Sprintf("tfins-vni-%d", acctest.RandIntRange(10, 100)) + resName := "data.ibm_is_instance.ds_instance" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceVniDataSourceConfig(vpcname, subnetname, sshname, vniname, instanceName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + resName, "name", instanceName), + resource.TestCheckResourceAttrSet( + resName, "primary_network_interface.0.port_speed"), + resource.TestCheckResourceAttrSet( + resName, "availability_policy_host_failure"), + resource.TestCheckResourceAttrSet( + resName, "lifecycle_state"), + resource.TestCheckResourceAttr( + resName, "lifecycle_reasons.#", "0"), + resource.TestCheckResourceAttrSet( + resName, "vcpu.#"), + resource.TestCheckResourceAttrSet( + resName, "vcpu.0.manufacturer"), + resource.TestCheckResourceAttrSet( + resName, "primary_network_attachment.#"), + resource.TestCheckResourceAttrSet( + resName, "primary_network_attachment.0.id"), + resource.TestCheckResourceAttr( + resName, "primary_network_attachment.0.name", "test-vni"), + resource.TestCheckResourceAttrSet( + resName, "primary_network_attachment.0.primary_ip.#"), + resource.TestCheckResourceAttrSet( + resName, "primary_network_attachment.0.subnet.#"), + ), + }, + }, + }) +} func TestAccIBMISInstanceDataSource_PKCS8SSH(t *testing.T) { vpcname := fmt.Sprintf("tfins-vpc-%d", acctest.RandIntRange(10, 100)) @@ -165,6 +210,50 @@ data "ibm_is_instance" "ds_instance" { passphrase = "" }`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, instanceName, acc.IsWinImage, acc.InstanceProfileName, acc.ISZoneName) } +func testAccCheckIBMISInstanceVniDataSourceConfig(vpcname, subnetname, sshname, vniname, instanceName 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 = file("./test-fixtures/.ssh/id_rsa.pub") +} + +resource "ibm_is_virtual_network_interface" "testacc_vni"{ + name = "%s" + allow_ip_spoofing = true + subnet = ibm_is_subnet.testacc_subnet.id +} + +resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_attachment { + name = "test-vni" + virtual_network_interface { + id = ibm_is_virtual_network_interface.testacc_vni.id + } + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] +} +data "ibm_is_instance" "ds_instance" { + name = ibm_is_instance.testacc_instance.name + private_key = file("./test-fixtures/.ssh/id_rsa") + passphrase = "" +}`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, vniname, instanceName, acc.IsWinImage, acc.InstanceProfileName, acc.ISZoneName) +} func testAccCheckIBMISInstanceDataSourcePKCS8SSHConfig(vpcname, subnetname, sshname, instanceName string) string { return fmt.Sprintf(` resource "ibm_is_vpc" "testacc_vpc" { diff --git a/ibm/service/vpc/data_source_ibm_is_instances.go b/ibm/service/vpc/data_source_ibm_is_instances.go index cd6efdb9e7..b2ee215e27 100644 --- a/ibm/service/vpc/data_source_ibm_is_instances.go +++ b/ibm/service/vpc/data_source_ibm_is_instances.go @@ -407,6 +407,145 @@ func DataSourceIBMISInstances() *schema.Resource { }, }, }, + "primary_network_attachment": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The primary network attachment for this virtual server instance.", + 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 network attachment.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this network attachment.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "primary_ip": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The primary IP address of the virtual network interface for the network attachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "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 reserved IP.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this reserved IP. The name is unique across all reserved IPs in a 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, + Description: "The subnet of the virtual network interface for the network attachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this subnet.", + }, + "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 subnet.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this subnet.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this subnet. The name is unique across all subnets in the VPC.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + }, + }, + }, + "placement_target": { Type: schema.TypeList, Computed: true, @@ -525,6 +664,146 @@ func DataSourceIBMISInstances() *schema.Resource { }, }, }, + + "network_attachments": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The network attachments for this virtual server instance, including the primary 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 network attachment.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this network attachment.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "primary_ip": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The primary IP address of the virtual network interface for the network attachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "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 reserved IP.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this reserved IP. The name is unique across all reserved IPs in a 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, + Description: "The subnet of the virtual network interface for the network attachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this subnet.", + }, + "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 subnet.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this subnet.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this subnet. The name is unique across all subnets in the VPC.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + }, + }, + }, + "profile": { Type: schema.TypeString, Computed: true, @@ -657,6 +936,115 @@ func DataSourceIBMISInstances() *schema.Resource { }, }, }, + isInstanceReservation: { + Type: schema.TypeList, + Computed: true, + Description: "The reservation used by this virtual server instance", + 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 virtual server instance.", + }, + isReservationAffinityPool: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The pool of reservations available for use by this virtual server instance.", + 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.", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, }, }, }, @@ -1003,6 +1391,16 @@ func instancesList(d *schema.ResourceData, meta interface{}) error { l["primary_network_interface"] = primaryNicList } + primaryNetworkAttachment := []map[string]interface{}{} + if instance.PrimaryNetworkAttachment != nil { + modelMap, err := dataSourceIBMIsInstanceInstanceNetworkAttachmentReferenceToMap(instance.PrimaryNetworkAttachment) + if err != nil { + return err + } + primaryNetworkAttachment = append(primaryNetworkAttachment, modelMap) + } + l["primary_network_attachment"] = primaryNetworkAttachment + if instance.NetworkInterfaces != nil { interfacesList := make([]map[string]interface{}, 0) for _, intfc := range instance.NetworkInterfaces { @@ -1055,6 +1453,18 @@ func instancesList(d *schema.ResourceData, meta interface{}) error { l["network_interfaces"] = interfacesList } + networkAttachments := []map[string]interface{}{} + if instance.NetworkAttachments != nil { + for _, modelItem := range instance.NetworkAttachments { + modelMap, err := dataSourceIBMIsInstanceInstanceNetworkAttachmentReferenceToMap(&modelItem) + if err != nil { + return err + } + networkAttachments = append(networkAttachments, modelMap) + } + } + l["network_attachments"] = networkAttachments + l["profile"] = *instance.Profile.Name cpuList := make([]map[string]interface{}, 0) @@ -1094,6 +1504,52 @@ func instancesList(d *schema.ResourceData, meta interface{}) error { if instance.Disks != nil { l[isInstanceDisks] = dataSourceInstanceFlattenDisks(instance.Disks) } + if instance.ReservationAffinity != nil { + reservationAffinity := []map[string]interface{}{} + reservationAffinityMap := map[string]interface{}{} + + reservationAffinityMap[isReservationAffinityPolicyResp] = instance.ReservationAffinity.Policy + if instance.ReservationAffinity.Pool != nil { + poolList := make([]map[string]interface{}, 0) + for _, pool := range instance.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 := dataSourceInstanceReservationDeletedToMap(*pool.Deleted) + deletedList = append(deletedList, deletedMap) + res[isReservationDeleted] = deletedList + } + poolList = append(poolList, res) + } + reservationAffinityMap[isReservationAffinityPool] = poolList + } + reservationAffinity = append(reservationAffinity, reservationAffinityMap) + l[isReservationAffinity] = reservationAffinity + } + if instance.Reservation != nil { + resList := make([]map[string]interface{}, 0) + res := map[string]interface{}{} + + res[isReservationId] = *instance.Reservation.ID + res[isReservationHref] = *instance.Reservation.Href + res[isReservationName] = *instance.Reservation.Name + res[isReservationCrn] = *instance.Reservation.CRN + res[isReservationResourceType] = *instance.Reservation.ResourceType + if instance.Reservation.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceInstanceReservationDeletedToMap(*instance.Reservation.Deleted) + deletedList = append(deletedList, deletedMap) + res[isReservationDeleted] = deletedList + } + resList = append(resList, res) + l[isInstanceReservation] = resList + } instancesInfo = append(instancesInfo, l) } 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 feb540be9d..49b1b962cb 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,47 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE }, }) } +func TestAccIBMISInstancesDataSource_vni(t *testing.T) { + 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 +`) + vniname := fmt.Sprintf("tf-vni-%d", acctest.RandIntRange(10, 100)) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + userData1 := "a" + resName := "data.ibm_is_instances.ds_instances" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstancesVniDataSourceConfig(vpcname, subnetname, sshname, publicKey, name, vniname, userData1), + 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.primary_network_attachment.#"), + resource.TestCheckResourceAttr(resName, "instances.0.primary_network_attachment.#", "1"), + ), + }, + }, + }) +} func TestAccIBMISInstancesDataSource_ReservedIp(t *testing.T) { var instance string vpcname := fmt.Sprintf("tfins-vpc-%d", acctest.RandIntRange(10, 100)) @@ -189,6 +230,13 @@ func testAccCheckIBMISInstancesDataSourceConfig() string { data "ibm_is_instances" "ds_instances" { }`) } +func testAccCheckIBMISInstancesVniDataSourceConfig(vpcname, subnetname, sshname, publicKey, name, vniname, userData string) string { + return testAccCheckIBMISInstanceVniConfig(vpcname, subnetname, sshname, publicKey, name, vniname, userData) + fmt.Sprintf(` + data "ibm_is_instances" "ds_instances" { + vpc_name = ibm_is_vpc.testacc_vpc.name + depends_on = [ ibm_is_instance.testacc_instance ] + }`) +} func testAccCheckIBMISInstancesDataSourceReservedIpConfig(vpcname string) string { return fmt.Sprintf(` diff --git a/ibm/service/vpc/data_source_ibm_is_lbs.go b/ibm/service/vpc/data_source_ibm_is_lbs.go index 11a9a2364f..1655fa15db 100644 --- a/ibm/service/vpc/data_source_ibm_is_lbs.go +++ b/ibm/service/vpc/data_source_ibm_is_lbs.go @@ -399,7 +399,9 @@ func getLbs(d *schema.ResourceData, meta interface{}) error { if subnet.CRN != nil { sub[CRN] = *subnet.CRN } - sub[name] = *subnet.Name + if subnet.Name != nil && *subnet.Name != "" { + sub[name] = *subnet.Name + } subnetList = append(subnetList, sub) } diff --git a/ibm/service/vpc/data_source_ibm_is_reservation.go b/ibm/service/vpc/data_source_ibm_is_reservation.go new file mode 100644 index 0000000000..66b6d820bb --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_reservation.go @@ -0,0 +1,431 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsReservation() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsReservationRead, + + Schema: map[string]*schema.Schema{ + + "identifier": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"name", "identifier"}, + Description: "The reservation identifier.", + }, + + "name": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ExactlyOneOf: []string{"name", "identifier"}, + Description: "The unique user-defined name for this reservation.", + }, + + "affinity_policy": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The affinity policy to use for this reservation.", + }, + "capacity": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Optional: true, + Description: "The capacity configuration for this reservation. If absent, this reservation has no assigned capacity.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "allocated": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The amount allocated to this capacity reservation.", + }, + "available": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The amount of this capacity reservation available for new attachments.", + }, + "status": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The status of the capacity reservation.", + }, + "total": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The total amount of this capacity reservation.", + }, + "used": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The amount of this capacity reservation used by existing attachments.", + }, + }, + }, + }, + "committed_use": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Optional: true, + Description: "The committed use configuration for this reservation. If absent, this reservation has no commitment for use.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "expiration_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The expiration date and time for this committed use reservation.", + }, + "expiration_policy": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The policy to apply when the committed use term expires.", + }, + "term": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The term for this committed use reservation.", + }, + }, + }, + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the reservation was created.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this reservation.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reservation.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this reservation.", + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the reservation.", + }, + "profile": { + Type: schema.TypeList, + Computed: true, + Description: "The profile for this reservation.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this virtual server instance profile.", + }, + "name": { + 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.", + }, + }, + }, + }, + "resource_group": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The resource group for this reservation.", + 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 user-defined name for this resource group.", + }, + }, + }, + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type of resource referenced.", + }, + "status": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The status of the reservation.", + }, + "status_reasons": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current status (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "code": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A snake case string succinctly identifying the status reason.", + }, + "message": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the status reason.", + }, + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Optional: true, + Description: "Link to documentation about this status reason.", + }, + }, + }, + }, + "zone": { + Type: schema.TypeString, + Computed: true, + Description: "The zone for this reservation.", + }, + }, + } +} + +func dataSourceIBMIsReservationRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + var reservation *vpcv1.Reservation + + if v, ok := d.GetOk("identifier"); ok { + id := v.(string) + getReservationOptions := &vpcv1.GetReservationOptions{} + getReservationOptions.SetID(id) + reservationInfo, response, err := sess.GetReservationWithContext(context, getReservationOptions) + if err != nil { + log.Printf("[DEBUG] GetReservationWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] GetReservationWithContext failed %s\n%s", err, response)) + } + reservation = reservationInfo + + } + if v, ok := d.GetOk("name"); ok { + + name := v.(string) + start := "" + allrecs := []vpcv1.Reservation{} + for { + listReservationsOptions := &vpcv1.ListReservationsOptions{} + if start != "" { + listReservationsOptions.Start = &start + } + reservationCollection, response, err := sess.ListReservationsWithContext(context, listReservationsOptions) + if err != nil { + log.Printf("[DEBUG] ListReservationsWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] ListReservationsWithContext failed %s\n%s", err, response)) + } + if reservationCollection != nil && *reservationCollection.TotalCount == int64(0) { + break + } + start = flex.GetNext(reservationCollection.Next) + allrecs = append(allrecs, reservationCollection.Reservations...) + if start == "" { + break + } + } + for _, reservationInfo := range allrecs { + if *reservationInfo.Name == name { + reservation = &reservationInfo + break + } + } + if reservation == nil { + return diag.FromErr(fmt.Errorf("[ERROR] No reservation found with name (%s)", name)) + } + } + + d.SetId(*reservation.ID) + if err = d.Set("affinity_policy", reservation.AffinityPolicy); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting affinity_policy: %s", err)) + } + if reservation.Capacity != nil { + capacityList := []map[string]interface{}{} + capacityMap := dataSourceReservationCapacityToMap(*reservation.Capacity) + capacityList = append(capacityList, capacityMap) + if err = d.Set("capacity", capacityList); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting capacity: %s", err)) + } + } + if reservation.CommittedUse != nil { + committedUseList := []map[string]interface{}{} + committedUseMap := dataSourceReservationCommittedUseToMap(*reservation.CommittedUse) + committedUseList = append(committedUseList, committedUseMap) + if err = d.Set("committed_use", committedUseList); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting committed_use: %s", err)) + } + } + if err = d.Set("created_at", reservation.CreatedAt.String()); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + if err = d.Set("crn", reservation.CRN); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting crn: %s", err)) + } + if err = d.Set("href", reservation.Href); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting href: %s", err)) + } + if err = d.Set("lifecycle_state", reservation.LifecycleState); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting lifecycle_state: %s", err)) + } + if err = d.Set("name", reservation.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + if reservation.Profile != nil { + profileList := []map[string]interface{}{} + profile := reservation.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)) + } + } + if reservation.ResourceGroup != nil { + resourceGroupList := []map[string]interface{}{} + resourceGroupMap := dataSourceReservationResourceGroupToMap(*reservation.ResourceGroup) + resourceGroupList = append(resourceGroupList, resourceGroupMap) + if err = d.Set("resource_group", resourceGroupList); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_group: %s", err)) + } + } + if err = d.Set("resource_type", reservation.ResourceType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_type: %s", err)) + } + if err = d.Set("status", reservation.Status); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting status: %s", err)) + } + if reservation.StatusReasons != nil { + statusReasonsList := []map[string]interface{}{} + for _, statusReasonsItem := range reservation.StatusReasons { + statusReasonsList = append(statusReasonsList, dataSourceReservationStatusReasonsToMap(statusReasonsItem)) + } + if err = d.Set("status_reasons", statusReasonsList); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting status_reasons: %s", err)) + } + } + zone := "" + if reservation.Zone != nil && reservation.Zone.Name != nil { + zone = *reservation.Zone.Name + } + if err = d.Set("zone", zone); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting zone: %s", err)) + } + return nil +} + +func dataSourceReservationProfileToMap(profileItem vpcv1.ReservationProfile) (profileMap map[string]interface{}) { + profileMap = map[string]interface{}{} + + if profileItem.Href != nil { + profileMap["href"] = profileItem.Href + } + if profileItem.Name != nil { + profileMap["name"] = profileItem.Name + } + if profileItem.ResourceType != nil { + profileMap["resource_type"] = profileItem.ResourceType + } + return profileMap +} + +func dataSourceReservationResourceGroupToMap(resourceGroupItem vpcv1.ResourceGroupReference) (resourceGroupMap map[string]interface{}) { + resourceGroupMap = map[string]interface{}{} + + if resourceGroupItem.Href != nil { + resourceGroupMap["href"] = resourceGroupItem.Href + } + if resourceGroupItem.ID != nil { + resourceGroupMap["id"] = resourceGroupItem.ID + } + if resourceGroupItem.Name != nil { + resourceGroupMap["name"] = resourceGroupItem.Name + } + return resourceGroupMap +} + +func dataSourceReservationCapacityToMap(capacityItem vpcv1.ReservationCapacity) (capacityMap map[string]interface{}) { + capacityMap = map[string]interface{}{} + + if capacityItem.Allocated != nil { + capacityMap["allocated"] = capacityItem.Allocated + } + if capacityItem.Available != nil { + capacityMap["available"] = capacityItem.Available + } + if capacityItem.Total != nil { + capacityMap["total"] = capacityItem.Total + } + if capacityItem.Used != nil { + capacityMap["used"] = capacityItem.Used + } + if capacityItem.Status != nil { + capacityMap["status"] = capacityItem.Status + } + return capacityMap +} + +func dataSourceReservationCommittedUseToMap(committedUseItem vpcv1.ReservationCommittedUse) (committedUseMap map[string]interface{}) { + committedUseMap = map[string]interface{}{} + + if committedUseItem.ExpirationAt != nil { + committedUseMap["expiration_at"] = committedUseItem.ExpirationAt.String() + } + if committedUseItem.ExpirationPolicy != nil { + committedUseMap["expiration_policy"] = committedUseItem.ExpirationPolicy + } + if committedUseItem.Term != nil { + committedUseMap["term"] = committedUseItem.Term + } + return committedUseMap +} + +func dataSourceReservationStatusReasonsToMap(statusReasonsItem vpcv1.ReservationStatusReason) (statusReasonsMap map[string]interface{}) { + statusReasonsMap = map[string]interface{}{} + + if statusReasonsItem.Code != nil { + statusReasonsMap["code"] = statusReasonsItem.Code + } + if statusReasonsItem.Message != nil { + statusReasonsMap["message"] = statusReasonsItem.Message + } + if statusReasonsItem.MoreInfo != nil { + statusReasonsMap["more_info"] = statusReasonsItem.MoreInfo + } + return statusReasonsMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_reservation_test.go b/ibm/service/vpc/data_source_ibm_is_reservation_test.go new file mode 100644 index 0000000000..b91644ee1b --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_reservation_test.go @@ -0,0 +1,94 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMISReservationDatasource_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testDSCheckIBMISReservationConfigById(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_reservation.ds_res", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_reservation.ds_res", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_reservation.ds_res", "crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_reservation.ds_res", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_reservation.ds_res", "lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_reservation.ds_res", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_reservation.ds_res", "profile.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_reservation.ds_res", "resource_group.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_reservation.ds_res", "resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_reservation.ds_res", "zone"), + ), + }, + { + Config: testDSCheckIBMISReservationConfigByName(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_reservation.ds_res", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_reservation.ds_res", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_reservation.ds_res", "crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_reservation.ds_res", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_reservation.ds_res", "lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_reservation.ds_res", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_reservation.ds_res", "profile.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_reservation.ds_res", "resource_group.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_reservation.ds_res", "resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_reservation.ds_res", "zone"), + ), + }, + }, + }) +} + +func testDSCheckIBMISReservationConfigById() string { + return fmt.Sprintf(` + resource "ibm_is_reservation" "res" { + capacity { + total = 5 + } + committed_use { + term = "one_year" + } + profile { + name = "cx2-2x4" + resource_type = "instance_profile" + } + zone = "us-south-1" + name = "reservation-name" + } + data "ibm_is_reservation" "ds_res" { + identifier = ibm_is_reservation.res.id + }`) +} + +func testDSCheckIBMISReservationConfigByName() string { + return fmt.Sprintf(` + resource "ibm_is_reservation" "res" { + capacity { + total = 5 + } + committed_use { + term = "one_year" + } + profile { + name = "cx2-2x4" + resource_type = "instance_profile" + } + zone = "us-south-1" + name = "reservation-name" + } + data "ibm_is_reservation" "ds_res" { + name = ibm_is_reservation.res.name + }`) +} diff --git a/ibm/service/vpc/data_source_ibm_is_reservations.go b/ibm/service/vpc/data_source_ibm_is_reservations.go new file mode 100644 index 0000000000..313d7625dd --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_reservations.go @@ -0,0 +1,452 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsReservations() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsReservationsRead, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Description: "Filters the collection to resources with the exact specified name", + Optional: true, + }, + "zone_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Filters the collection to resources with a zone name property matching the exact specified name.", + }, + "resource_group": { + Type: schema.TypeString, + Description: "Filters the collection to resources in the resource group with the specified identifier", + Optional: true, + }, + "reservations": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Collection of reservations.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "affinity_policy": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The affinity policy to use for this reservation.", + }, + "capacity": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Optional: true, + Description: "The capacity configuration for this reservation. If absent, this reservation has no assigned capacity.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "allocated": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The amount allocated to this capacity reservation.", + }, + "available": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The amount of this capacity reservation available for new attachments.", + }, + "status": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The status of the capacity reservation.", + }, + "total": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The total amount of this capacity reservation.", + }, + "used": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The amount of this capacity reservation used by existing attachments.", + }, + }, + }, + }, + "committed_use": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Optional: true, + Description: "The committed use configuration for this reservation. If absent, this reservation has no commitment for use.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "expiration_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The expiration date and time for this committed use reservation.", + }, + "expiration_policy": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The policy to apply when the committed use term expires.", + }, + "term": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The term for this committed use reservation.", + }, + }, + }, + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the reservation was created.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this reservation.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reservation.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this reservation.", + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the reservation.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique user-defined name for this reservation.", + }, + "profile": { + Type: schema.TypeList, + Computed: true, + Description: "The profile for this reservation.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this virtual server instance profile.", + }, + "name": { + 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.", + }, + }, + }, + }, + "resource_group": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The resource group for this reservation.", + 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 user-defined name for this resource group.", + }, + }, + }, + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type of resource referenced.", + }, + "status": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The status of the reservation.", + }, + "status_reasons": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current status (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "code": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A snake case string succinctly identifying the status reason.", + }, + "message": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the status reason.", + }, + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Optional: true, + Description: "Link to documentation about this status reason.", + }, + }, + }, + }, + "zone": { + Type: schema.TypeString, + Computed: true, + Description: "The zone for this reservation.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsReservationsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + zoneName := d.Get("zone_name").(string) + resourceGroupId := d.Get("resource_group").(string) + + start := "" + reservations := []vpcv1.Reservation{} + + var name string + if v, ok := d.GetOk("name"); ok { + name = v.(string) + } + + for { + listReservationsOptions := &vpcv1.ListReservationsOptions{} + if start != "" { + listReservationsOptions.Start = &start + } + if name != "" { + listReservationsOptions.SetName(name) + } + if zoneName != "" { + listReservationsOptions.SetZoneName(zoneName) + } + if resourceGroupId != "" { + listReservationsOptions.SetResourceGroupID(resourceGroupId) + } + reservationCollection, response, err := sess.ListReservationsWithContext(context, listReservationsOptions) + if err != nil { + log.Printf("[DEBUG] ListReservationsWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] ListReservationsWithContext failed %s\n%s", err, response)) + } + if reservationCollection != nil && *reservationCollection.TotalCount == int64(0) { + break + } + start = flex.GetNext(reservationCollection.Next) + reservations = append(reservations, reservationCollection.Reservations...) + if start == "" { + break + } + } + + d.SetId(dataSourceIBMIsReservationsID(d)) + + if reservations != nil { + err = d.Set("reservations", dataSourceReservationCollectionFlattenReservations(reservations)) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting reservations %s", err)) + } + } + + return nil +} + +// dataSourceIBMIsReservationsID returns a reasonable ID for the list. +func dataSourceIBMIsReservationsID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceReservationCollectionFlattenReservations(result []vpcv1.Reservation) (reservations []map[string]interface{}) { + for _, reservationsItem := range result { + reservations = append(reservations, dataSourceReservationCollectionReservationsToMap(reservationsItem)) + } + return reservations +} + +func dataSourceReservationCollectionReservationsToMap(reservationsItem vpcv1.Reservation) (reservationsMap map[string]interface{}) { + reservationsMap = map[string]interface{}{} + + if reservationsItem.AffinityPolicy != nil { + reservationsMap["affinity_policy"] = reservationsItem.AffinityPolicy + } + if reservationsItem.Capacity != nil { + capacityList := []map[string]interface{}{} + capacityMap := dataSourceReservationCollectionReservationsCapacityToMap(*reservationsItem.Capacity) + capacityList = append(capacityList, capacityMap) + reservationsMap["capacity"] = capacityList + } + if reservationsItem.CommittedUse != nil { + committedUseList := []map[string]interface{}{} + committedUseMap := dataSourceReservationCollectionReservationsCommittedUseToMap(*reservationsItem.CommittedUse) + committedUseList = append(committedUseList, committedUseMap) + reservationsMap["committed_use"] = committedUseList + } + if reservationsItem.CreatedAt != nil { + reservationsMap["created_at"] = reservationsItem.CreatedAt.String() + } + if reservationsItem.CRN != nil { + reservationsMap["crn"] = reservationsItem.CRN + } + if reservationsItem.Href != nil { + reservationsMap["href"] = reservationsItem.Href + } + if reservationsItem.ID != nil { + reservationsMap["id"] = reservationsItem.ID + } + if reservationsItem.LifecycleState != nil { + reservationsMap["lifecycle_state"] = reservationsItem.LifecycleState + } + if reservationsItem.Name != nil { + reservationsMap["name"] = reservationsItem.Name + } + if reservationsItem.Profile != nil { + profileList := []map[string]interface{}{} + profile := reservationsItem.Profile + profileMap := dataSourceReservationCollectionReservationsProfileToMap(*profile) + profileList = append(profileList, profileMap) + reservationsMap["profile"] = profileList + } + if reservationsItem.ResourceGroup != nil { + resourceGroupList := []map[string]interface{}{} + resourceGroupMap := dataSourceReservationCollectionReservationsResourceGroupToMap(*reservationsItem.ResourceGroup) + resourceGroupList = append(resourceGroupList, resourceGroupMap) + reservationsMap["resource_group"] = resourceGroupList + } + if reservationsItem.ResourceType != nil { + reservationsMap["resource_type"] = reservationsItem.ResourceType + } + if reservationsItem.Status != nil { + reservationsMap["status"] = reservationsItem.Status + } + if reservationsItem.StatusReasons != nil { + statusReasonsList := []map[string]interface{}{} + for _, statusReasonsItem := range reservationsItem.StatusReasons { + statusReasonsList = append(statusReasonsList, dataSourceReservationCollectionReservationsStatusReasonsToMap(statusReasonsItem)) + } + reservationsMap["status_reasons"] = statusReasonsList + } + if reservationsItem.Zone != nil && reservationsItem.Zone.Name != nil { + reservationsMap["zone"] = *reservationsItem.Zone.Name + } + return reservationsMap +} + +func dataSourceReservationCollectionReservationsProfileToMap(profileItem vpcv1.ReservationProfile) (profileMap map[string]interface{}) { + profileMap = map[string]interface{}{} + + if profileItem.Href != nil { + profileMap["href"] = profileItem.Href + } + if profileItem.Name != nil { + profileMap["name"] = profileItem.Name + } + if profileItem.ResourceType != nil { + profileMap["resource_type"] = profileItem.ResourceType + } + return profileMap +} + +func dataSourceReservationCollectionReservationsResourceGroupToMap(resourceGroupItem vpcv1.ResourceGroupReference) (resourceGroupMap map[string]interface{}) { + resourceGroupMap = map[string]interface{}{} + + if resourceGroupItem.Href != nil { + resourceGroupMap["href"] = resourceGroupItem.Href + } + if resourceGroupItem.ID != nil { + resourceGroupMap["id"] = resourceGroupItem.ID + } + if resourceGroupItem.Name != nil { + resourceGroupMap["name"] = resourceGroupItem.Name + } + return resourceGroupMap +} + +func dataSourceReservationCollectionReservationsCapacityToMap(capacityItem vpcv1.ReservationCapacity) (capacityMap map[string]interface{}) { + capacityMap = map[string]interface{}{} + + if capacityItem.Allocated != nil { + capacityMap["allocated"] = capacityItem.Allocated + } + if capacityItem.Available != nil { + capacityMap["available"] = capacityItem.Available + } + if capacityItem.Total != nil { + capacityMap["total"] = capacityItem.Total + } + if capacityItem.Used != nil { + capacityMap["used"] = capacityItem.Used + } + if capacityItem.Status != nil { + capacityMap["status"] = capacityItem.Status + } + return capacityMap +} + +func dataSourceReservationCollectionReservationsCommittedUseToMap(committedUseItem vpcv1.ReservationCommittedUse) (committedUseMap map[string]interface{}) { + committedUseMap = map[string]interface{}{} + + if committedUseItem.ExpirationAt != nil { + committedUseMap["expiration_at"] = committedUseItem.ExpirationAt.String() + } + if committedUseItem.ExpirationPolicy != nil { + committedUseMap["expiration_policy"] = committedUseItem.ExpirationPolicy + } + if committedUseItem.Term != nil { + committedUseMap["term"] = committedUseItem.Term + } + return committedUseMap +} + +func dataSourceReservationCollectionReservationsStatusReasonsToMap(statusReasonsItem vpcv1.ReservationStatusReason) (statusReasonsMap map[string]interface{}) { + statusReasonsMap = map[string]interface{}{} + + if statusReasonsItem.Code != nil { + statusReasonsMap["code"] = statusReasonsItem.Code + } + if statusReasonsItem.Message != nil { + statusReasonsMap["message"] = statusReasonsItem.Message + } + if statusReasonsItem.MoreInfo != nil { + statusReasonsMap["more_info"] = statusReasonsItem.MoreInfo + } + return statusReasonsMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_reservations_test.go b/ibm/service/vpc/data_source_ibm_is_reservations_test.go new file mode 100644 index 0000000000..ac7419cebf --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_reservations_test.go @@ -0,0 +1,46 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMIsReservationsDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsReservationsDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_reservations.example", "reservations.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_reservations.example", "reservations.0.affinity_policy"), + resource.TestCheckResourceAttrSet("data.ibm_is_reservations.example", "reservations.0.created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_reservations.example", "reservations.0.crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_reservations.example", "reservations.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_reservations.example", "reservations.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_reservations.example", "reservations.0.lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_reservations.example", "reservations.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_reservations.example", "reservations.0.status"), + resource.TestCheckResourceAttrSet("data.ibm_is_reservations.example", "reservations.0.zone"), + resource.TestCheckResourceAttrSet("data.ibm_is_reservations.example", "reservations.0.resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_reservations.example", "reservations.0.profile.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_reservations.example", "reservations.0.resource_group.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsReservationsDataSourceConfigBasic() string { + return fmt.Sprintf(` + data "ibm_is_reservations" "example" { + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_security_group_target_test.go b/ibm/service/vpc/data_source_ibm_is_security_group_target_test.go new file mode 100644 index 0000000000..5d63eb31a5 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_security_group_target_test.go @@ -0,0 +1,160 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + 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" + "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 TestAccIBMISSecurityGroupTargetDataSource_vni(t *testing.T) { + var securityGroup string + terraformTag := "data.ibm_is_security_group_target.testacc_security_group_target" + vpcname := fmt.Sprintf("tfsg-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfsg-subnet-%d", acctest.RandIntRange(10, 100)) + lbname := fmt.Sprintf("tfsg-lb-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tfsg-one-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISSecurityGroupDataSourceTargetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISsecurityGroupTargetDataSourceVniConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISSecurityGroupDataSourceTargetExists("ibm_is_security_group_target.testacc_security_group_target", &securityGroup), + resource.TestCheckResourceAttrSet( + terraformTag, "crn"), + resource.TestCheckResourceAttr( + terraformTag, "resource_type", "virtual_network_interface"), + resource.TestCheckResourceAttrSet( + terraformTag, "target"), + ), + }, + }, + }) +} + +func testAccCheckIBMISSecurityGroupDataSourceTargetDestroy(s *terraform.State) error { + + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_security_group_target" { + continue + } + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + securityGroupID := parts[0] + targetID := parts[1] + + deleteSecurityGroupTargetBindingOptions := &vpcv1.DeleteSecurityGroupTargetBindingOptions{ + SecurityGroupID: &securityGroupID, + ID: &targetID, + } + + response, err := sess.DeleteSecurityGroupTargetBinding(deleteSecurityGroupTargetBindingOptions) + if err == nil { + return fmt.Errorf("Security Group Targets still exists: %v", response) + } + } + return nil +} + +func testAccCheckIBMISSecurityGroupDataSourceTargetExists(n string, securityGroupID *string) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + if rs.Primary.ID == "" { + return fmt.Errorf("[ERROR] No Security Group Target ID is set") + } + + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + if err != nil { + return err + } + + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + securityGroupId := parts[0] + targetID := parts[1] + + getSecurityGroupTargetOptions := &vpcv1.GetSecurityGroupTargetOptions{ + SecurityGroupID: &securityGroupId, + ID: &targetID, + } + + _, response, err := sess.GetSecurityGroupTarget(getSecurityGroupTargetOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + *securityGroupID = "" + return nil + } + return fmt.Errorf("[ERROR] Error getting Security Group Target : %s\n%s", err, response) + } + + *securityGroupID = fmt.Sprintf("%s/%s", securityGroupId, targetID) + return nil + } +} +func testAccCheckIBMISsecurityGroupTargetDataSourceVniConfig(vpcname, subnetname, zoneName, cidr, vniname, 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" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_security_group" "testacc_security_group_one" { + name = "%s" + vpc = "${ibm_is_vpc.testacc_vpc.id}" + } + + resource "ibm_is_virtual_network_interface" "testacc_vni"{ + name = "%s" + allow_ip_spoofing = false + enable_infrastructure_nat = true + primary_ip { + auto_delete = false + address = cidrhost(cidrsubnet(ibm_is_subnet.testacc_subnet.ipv4_cidr_block, 4, 6), 0) + } + subnet = ibm_is_subnet.testacc_subnet.id + } + + resource "ibm_is_security_group_target" "testacc_security_group_target" { + security_group = ibm_is_security_group.testacc_security_group_one.id + target = ibm_is_virtual_network_interface.testacc_vni.id + } + + data "ibm_is_security_group_target" "testacc_security_group_target" { + security_group = ibm_is_security_group_target.testacc_security_group_target.security_group + name = ibm_is_security_group_target.testacc_security_group_target.name + } + + `, vpcname, subnetname, zoneName, cidr, name, vniname) +} diff --git a/ibm/service/vpc/data_source_ibm_is_security_group_targets_test.go b/ibm/service/vpc/data_source_ibm_is_security_group_targets_test.go index 693e5e9bae..c55e429aec 100644 --- a/ibm/service/vpc/data_source_ibm_is_security_group_targets_test.go +++ b/ibm/service/vpc/data_source_ibm_is_security_group_targets_test.go @@ -43,6 +43,35 @@ func TestAccIBMISSecurityGroupTargets_basic(t *testing.T) { }, }) } +func TestAccIBMISSecurityGroupTargets_vni(t *testing.T) { + var securityGroup string + terraformTag := "data.ibm_is_security_group_targets.testacc_security_group_targets" + + vpcname := fmt.Sprintf("tfsg-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfsg-subnet-%d", acctest.RandIntRange(10, 100)) + vniname := fmt.Sprintf("tfsg-vni-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tfsg-one-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISSecurityGroupTargetsDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISsecurityGroupTargetsVniConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, vniname, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISSecurityGroupTargetsExists("ibm_is_security_group_target.testacc_security_group_target", &securityGroup), + resource.TestCheckResourceAttrSet( + terraformTag, "targets.0.crn"), + resource.TestCheckResourceAttr( + terraformTag, "targets.0.resource_type", "virtual_network_interface"), + resource.TestCheckResourceAttrSet( + terraformTag, "targets.0.target"), + ), + }, + }, + }) +} func testAccCheckIBMISSecurityGroupTargetsDestroy(s *terraform.State) error { @@ -141,12 +170,53 @@ func testAccCheckIBMISsecurityGroupTargetsConfig(vpcname, subnetname, zoneName, resource "ibm_is_security_group_target" "testacc_security_group_target" { security_group = ibm_is_security_group.testacc_security_group_one.id - target = ibm_is_lb.testacc_LB.id + target = ibm_is_lb.testacc_LB.id } data "ibm_is_security_group_targets" "testacc_security_group_targets" { - security_group = ibm_is_security_group.testacc_security_group_one.id + security_group = ibm_is_security_group_target.testacc_security_group_target.security_group } `, vpcname, subnetname, zoneName, cidr, name, lbname) } + +func testAccCheckIBMISsecurityGroupTargetsVniConfig(vpcname, subnetname, zoneName, cidr, vniname, 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" + ipv4_cidr_block = "%s" + } + + resource "ibm_is_security_group" "testacc_security_group_one" { + name = "%s" + vpc = "${ibm_is_vpc.testacc_vpc.id}" + } + + resource "ibm_is_virtual_network_interface" "testacc_vni"{ + name = "%s" + allow_ip_spoofing = false + enable_infrastructure_nat = true + primary_ip { + auto_delete = false + address = cidrhost(cidrsubnet(ibm_is_subnet.testacc_subnet.ipv4_cidr_block, 4, 6), 0) + } + subnet = ibm_is_subnet.testacc_subnet.id + } + + resource "ibm_is_security_group_target" "testacc_security_group_target" { + security_group = ibm_is_security_group.testacc_security_group_one.id + target = ibm_is_virtual_network_interface.testacc_vni.id + } + + data "ibm_is_security_group_targets" "testacc_security_group_targets" { + security_group = ibm_is_security_group_target.testacc_security_group_target.security_group + } + + `, vpcname, subnetname, zoneName, cidr, name, vniname) +} diff --git a/ibm/service/vpc/data_source_ibm_is_share_mount_target.go b/ibm/service/vpc/data_source_ibm_is_share_mount_target.go index f1da5dd2bf..577f223188 100644 --- a/ibm/service/vpc/data_source_ibm_is_share_mount_target.go +++ b/ibm/service/vpc/data_source_ibm_is_share_mount_target.go @@ -80,6 +80,54 @@ func DataSourceIBMIsShareTarget() *schema.Resource { Computed: true, Description: "The type of resource referenced.", }, + "primary_ip": { + Type: schema.TypeList, + Computed: true, + Description: "The primary IP address of the virtual network interface for the share mount target.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": { + Type: schema.TypeString, + Computed: true, + Description: "The IP address..", + }, + "deleted": { + 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": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this reserved IP.", + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, "subnet": { Type: schema.TypeList, Computed: true, @@ -311,6 +359,13 @@ func dataSourceIBMIsShareTargetRead(context context.Context, d *schema.ResourceD } } + if shareTarget.PrimaryIP != nil { + err = d.Set("primary_ip", dataSourceShareMountTargetFlattenPrimaryIP(*shareTarget.PrimaryIP)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting vpc %s", err)) + } + } + if shareTarget.VPC != nil { err = d.Set("vpc", dataSourceShareMountTargetFlattenVpc(*shareTarget.VPC)) if err != nil { @@ -382,6 +437,53 @@ func dataSourceShareMountTargetVpcDeletedToMap(deletedItem vpcv1.VPCReferenceDel return deletedMap } +func dataSourceShareMountTargetFlattenPrimaryIP(result vpcv1.ReservedIPReference) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceShareTargetPrimaryIPToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceShareTargetPrimaryIPToMap(primaryIPItem vpcv1.ReservedIPReference) (primaryIPMap map[string]interface{}) { + primaryIPMap = map[string]interface{}{} + + if primaryIPItem.Address != nil { + primaryIPMap["address"] = primaryIPItem.Address + } + if primaryIPItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceShareTargetPrimaryIPDeletedToMap(*primaryIPItem.Deleted) + deletedList = append(deletedList, deletedMap) + primaryIPMap["deleted"] = deletedList + } + if primaryIPItem.Href != nil { + primaryIPMap["href"] = primaryIPItem.Href + } + if primaryIPItem.ID != nil { + primaryIPMap["id"] = primaryIPItem.ID + } + if primaryIPItem.Name != nil { + primaryIPMap["name"] = primaryIPItem.Name + } + + if primaryIPItem.ResourceType != nil { + primaryIPMap["resource_type"] = primaryIPItem.ResourceType + } + + return primaryIPMap +} + +func dataSourceShareTargetPrimaryIPDeletedToMap(deletedItem vpcv1.ReservedIPReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} + func dataSourceShareMountTargetFlattenSubnet(result vpcv1.SubnetReference) (finalList []map[string]interface{}) { finalList = []map[string]interface{}{} finalMap := dataSourceShareTargetSubnetToMap(result) diff --git a/ibm/service/vpc/data_source_ibm_is_share_mount_targets.go b/ibm/service/vpc/data_source_ibm_is_share_mount_targets.go index 44d70ccdd6..6a8645360f 100644 --- a/ibm/service/vpc/data_source_ibm_is_share_mount_targets.go +++ b/ibm/service/vpc/data_source_ibm_is_share_mount_targets.go @@ -78,6 +78,54 @@ func DataSourceIBMIsShareTargets() *schema.Resource { Computed: true, Description: "The type of resource referenced.", }, + "primary_ip": { + Type: schema.TypeList, + Computed: true, + Description: "The primary IP address of the virtual network interface for the share mount target.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": { + Type: schema.TypeString, + Computed: true, + Description: "The IP address..", + }, + "deleted": { + 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": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this reserved IP.", + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, "subnet": { Type: schema.TypeList, Computed: true, @@ -319,6 +367,10 @@ func dataSourceShareMountTargetCollectionTargetsToMap(targetsItem vpcv1.ShareMou targetsMap["transit_encryption"] = *targetsItem.TransitEncryption } + if targetsItem.PrimaryIP != nil { + targetsMap["primary_ip"] = dataSourceShareMountTargetFlattenPrimaryIP(*targetsItem.PrimaryIP) + } + if targetsItem.VPC != nil { targetsMap["vpc"] = dataSourceShareMountTargetFlattenVpc(*targetsItem.VPC) } diff --git a/ibm/service/vpc/data_source_ibm_is_subnet_reserved_ip.go b/ibm/service/vpc/data_source_ibm_is_subnet_reserved_ip.go index aac3fc75cc..3c87e9d3bf 100644 --- a/ibm/service/vpc/data_source_ibm_is_subnet_reserved_ip.go +++ b/ibm/service/vpc/data_source_ibm_is_subnet_reserved_ip.go @@ -5,9 +5,7 @@ package vpc import ( "fmt" - "reflect" - "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -104,6 +102,54 @@ func DataSourceIBMISReservedIP() *schema.Resource { Computed: true, Description: "The crn for target.", }, + "target_reference": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The target this reserved IP is bound to.If absent, this reserved IP is provider-owned or unbound.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this endpoint gateway.", + }, + "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 endpoint gateway.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this endpoint gateway.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this endpoint gateway. The name is unique across all endpoint gateways in the VPC.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, }, } } @@ -137,44 +183,18 @@ func dataSdataSourceIBMISReservedIPRead(d *schema.ResourceData, meta interface{} d.Set(isReservedIPLifecycleState, *reserveIP.LifecycleState) } d.Set(isReservedIPType, *reserveIP.ResourceType) + target := []map[string]interface{}{} if reserveIP.Target != nil { - targetIntf := reserveIP.Target - switch reflect.TypeOf(targetIntf).String() { - case "*vpcv1.ReservedIPTargetEndpointGatewayReference": - { - target := targetIntf.(*vpcv1.ReservedIPTargetEndpointGatewayReference) - d.Set(isReservedIPTargetCrn, target.CRN) - d.Set(isReservedIPTarget, target.ID) - } - case "*vpcv1.ReservedIPTargetNetworkInterfaceReferenceTargetContext": - { - target := targetIntf.(*vpcv1.ReservedIPTargetNetworkInterfaceReferenceTargetContext) - d.Set(isReservedIPTarget, target.ID) - } - case "*vpcv1.ReservedIPTargetLoadBalancerReference": - { - target := targetIntf.(*vpcv1.ReservedIPTargetLoadBalancerReference) - d.Set(isReservedIPTargetCrn, target.CRN) - d.Set(isReservedIPTarget, target.ID) - } - case "*vpcv1.ReservedIPTargetVPNGatewayReference": - { - target := targetIntf.(*vpcv1.ReservedIPTargetVPNGatewayReference) - d.Set(isReservedIPTargetCrn, target.CRN) - d.Set(isReservedIPTarget, target.ID) - } - case "*vpcv1.ReservedIPTarget": - { - target := targetIntf.(*vpcv1.ReservedIPTarget) - d.Set(isReservedIPTargetCrn, target.CRN) - d.Set(isReservedIPTarget, target.ID) - } - case "*vpcv1.ReservedIPTargetGenericResourceReference": - { - target := targetIntf.(*vpcv1.ReservedIPTargetGenericResourceReference) - d.Set(isReservedIPTargetCrn, target.CRN) - } + modelMap, err := dataSourceIBMIsReservedIPReservedIPTargetToMap(reserveIP.Target) + if err != nil { + return err } + target = append(target, modelMap) + } + d.Set("target_reference", target) + if len(target) > 0 { + d.Set(isReservedIPTarget, target[0]["id"]) + d.Set(isReservedIPTargetCrn, target[0]["crn"]) } return nil // By default there should be no error } diff --git a/ibm/service/vpc/data_source_ibm_is_subnet_reserved_ip_test.go b/ibm/service/vpc/data_source_ibm_is_subnet_reserved_ip_test.go index 384267613f..7ec18f8d23 100644 --- a/ibm/service/vpc/data_source_ibm_is_subnet_reserved_ip_test.go +++ b/ibm/service/vpc/data_source_ibm_is_subnet_reserved_ip_test.go @@ -48,10 +48,45 @@ func TestAccIBMISSubnetReservedIP_targetCrn(t *testing.T) { terraformTag, "target_crn"), resource.TestCheckResourceAttrSet( terraformTag, "target"), + ), + }, + }, + }) +} +func TestAccIBMISSubnetReservedIP_targetVni(t *testing.T) { + vpcName := fmt.Sprintf("tfresip-vpc-%d", acctest.RandIntRange(10, 100)) + subnetName := fmt.Sprintf("tfresip-subnet-%d", acctest.RandIntRange(10, 100)) + resIPName := fmt.Sprintf("tfresip-reservedip-%d", acctest.RandIntRange(10, 100)) + vni := fmt.Sprintf("tfresip-vni-%d", acctest.RandIntRange(10, 100)) + terraformTag := "data.ibm_is_subnet_reserved_ip.data_resip1" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccIBMISReservedIPdataSoruceTargetVniConfig(vpcName, subnetName, resIPName, vni), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(terraformTag, "name", resIPName), + resource.TestCheckResourceAttrSet( + terraformTag, "target_crn"), + resource.TestCheckResourceAttrSet( + terraformTag, "target"), + resource.TestCheckResourceAttrSet( + terraformTag, "target_reference.#"), + resource.TestCheckResourceAttrSet( + terraformTag, "target_reference.0.href"), + resource.TestCheckResourceAttr( + terraformTag, "target_reference.0.resource_type", "virtual_network_interface"), + resource.TestCheckResourceAttrSet( + terraformTag, "target_reference.0.name"), + resource.TestCheckResourceAttrSet( + terraformTag, "target_reference.0.id"), + resource.TestCheckResourceAttrSet( + terraformTag, "target_reference.0.crn"), resource.TestCheckResourceAttrSet( - "ibm_is_virtual_endpoint_gateway_ip.example", "target.#"), + "ibm_is_virtual_network_interface.testacc_vni", "id"), resource.TestCheckResourceAttrSet( - "ibm_is_virtual_endpoint_gateway.example", "target.#"), + "ibm_is_virtual_network_interface.testacc_vni", "name"), ), }, }, @@ -126,3 +161,39 @@ func testAccIBMISReservedIPdataSoruceTargetCrnConfig(vpcName, subnetName, reserv `, vpcName, subnetName, reservedIPName, gatewayName) } +func testAccIBMISReservedIPdataSoruceTargetVniConfig(vpcName, subnetName, reservedIPName, vniname string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "vpc1" { + name = "%s" + } + + resource "ibm_is_subnet" "subnet1" { + name = "%s" + vpc = ibm_is_vpc.vpc1.id + zone = "%s" + total_ipv4_address_count = 256 + } + resource "ibm_is_virtual_network_interface" "testacc_vni"{ + name = "%s" + allow_ip_spoofing = false + enable_infrastructure_nat = true + primary_ip { + auto_delete = false + address = cidrhost(cidrsubnet(ibm_is_subnet.subnet1.ipv4_cidr_block, 4, 6), 0) + } + subnet = ibm_is_subnet.subnet1.id + } + + resource "ibm_is_subnet_reserved_ip" "resip1" { + subnet = ibm_is_subnet.subnet1.id + name = "%s" + target = ibm_is_virtual_network_interface.testacc_vni.id + } + + data "ibm_is_subnet_reserved_ip" "data_resip1" { + subnet = ibm_is_subnet.subnet1.id + reserved_ip = ibm_is_subnet_reserved_ip.resip1.reserved_ip + } + + `, vpcName, subnetName, acc.ISZoneName, vniname, reservedIPName) +} diff --git a/ibm/service/vpc/data_source_ibm_is_subnet_reserved_ips.go b/ibm/service/vpc/data_source_ibm_is_subnet_reserved_ips.go index 5bd8104608..7777bb175d 100644 --- a/ibm/service/vpc/data_source_ibm_is_subnet_reserved_ips.go +++ b/ibm/service/vpc/data_source_ibm_is_subnet_reserved_ips.go @@ -5,7 +5,6 @@ package vpc import ( "fmt" - "reflect" "time" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" @@ -104,6 +103,54 @@ func DataSourceIBMISReservedIPs() *schema.Resource { Computed: true, Description: "The crn for target.", }, + "target_reference": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The target this reserved IP is bound to.If absent, this reserved IP is provider-owned or unbound.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this endpoint gateway.", + }, + "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 endpoint gateway.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this endpoint gateway.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this endpoint gateway. The name is unique across all endpoint gateways in the VPC.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, }, }, }, @@ -158,45 +205,20 @@ func dataSdataSourceIBMISReservedIPsRead(d *schema.ResourceData, meta interface{ ipsOutput[isReservedIPName] = *data.Name ipsOutput[isReservedIPOwner] = *data.Owner ipsOutput[isReservedIPType] = *data.ResourceType + target := []map[string]interface{}{} if data.Target != nil { - targetIntf := data.Target - switch reflect.TypeOf(targetIntf).String() { - case "*vpcv1.ReservedIPTargetEndpointGatewayReference": - { - target := targetIntf.(*vpcv1.ReservedIPTargetEndpointGatewayReference) - ipsOutput[isReservedIPTarget] = target.ID - ipsOutput[isReservedIPTargetCrn] = target.CRN - } - case "*vpcv1.ReservedIPTargetNetworkInterfaceReferenceTargetContext": - { - target := targetIntf.(*vpcv1.ReservedIPTargetNetworkInterfaceReferenceTargetContext) - ipsOutput[isReservedIPTarget] = target.ID - } - case "*vpcv1.ReservedIPTargetGenericResourceReference": - { - target := targetIntf.(*vpcv1.ReservedIPTargetGenericResourceReference) - ipsOutput[isReservedIPTargetCrn] = target.CRN - } - case "*vpcv1.ReservedIPTargetLoadBalancerReference": - { - target := targetIntf.(*vpcv1.ReservedIPTargetLoadBalancerReference) - ipsOutput[isReservedIPTarget] = target.ID - ipsOutput[isReservedIPTargetCrn] = target.CRN - } - case "*vpcv1.ReservedIPTargetVPNGatewayReference": - { - target := targetIntf.(*vpcv1.ReservedIPTargetVPNGatewayReference) - ipsOutput[isReservedIPTarget] = target.ID - ipsOutput[isReservedIPTargetCrn] = target.CRN - } - case "*vpcv1.ReservedIPTarget": - { - target := targetIntf.(*vpcv1.ReservedIPTarget) - ipsOutput[isReservedIPTarget] = target.ID - ipsOutput[isReservedIPTargetCrn] = target.CRN - } + modelMap, err := dataSourceIBMIsReservedIPReservedIPTargetToMap(data.Target) + if err != nil { + return err } + target = append(target, modelMap) } + ipsOutput["target_reference"] = target + if len(target) > 0 { + ipsOutput[isReservedIPTarget] = target[0]["id"] + ipsOutput[isReservedIPTargetCrn] = target[0]["crn"] + } + reservedIPs = append(reservedIPs, ipsOutput) } @@ -206,3 +228,217 @@ func dataSdataSourceIBMISReservedIPsRead(d *schema.ResourceData, meta interface{ d.Set(isSubNetID, subnetID) return nil } + +func dataSourceIBMIsReservedIPReservedIPTargetToMap(model vpcv1.ReservedIPTargetIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.ReservedIPTargetEndpointGatewayReference); ok { + return dataSourceIBMIsReservedIPReservedIPTargetEndpointGatewayReferenceToMap(model.(*vpcv1.ReservedIPTargetEndpointGatewayReference)) + } else if _, ok := model.(*vpcv1.ReservedIPTargetVirtualNetworkInterfaceReferenceReservedIPTargetContext); ok { + return dataSourceIBMIsReservedIPReservedIPTargetVirtualNetworkInterfaceReferenceReservedIPTargetContextToMap(model.(*vpcv1.ReservedIPTargetVirtualNetworkInterfaceReferenceReservedIPTargetContext)) + } else if _, ok := model.(*vpcv1.ReservedIPTargetNetworkInterfaceReferenceTargetContext); ok { + return dataSourceIBMIsReservedIPReservedIPTargetNetworkInterfaceReferenceTargetContextToMap(model.(*vpcv1.ReservedIPTargetNetworkInterfaceReferenceTargetContext)) + } else if _, ok := model.(*vpcv1.ReservedIPTargetBareMetalServerNetworkInterfaceReferenceTargetContext); ok { + return dataSourceIBMIsReservedIPReservedIPTargetBareMetalServerNetworkInterfaceReferenceTargetContextToMap(model.(*vpcv1.ReservedIPTargetBareMetalServerNetworkInterfaceReferenceTargetContext)) + } else if _, ok := model.(*vpcv1.ReservedIPTargetLoadBalancerReference); ok { + return dataSourceIBMIsReservedIPReservedIPTargetLoadBalancerReferenceToMap(model.(*vpcv1.ReservedIPTargetLoadBalancerReference)) + } else if _, ok := model.(*vpcv1.ReservedIPTargetVPNGatewayReference); ok { + return dataSourceIBMIsReservedIPReservedIPTargetVPNGatewayReferenceToMap(model.(*vpcv1.ReservedIPTargetVPNGatewayReference)) + } else if _, ok := model.(*vpcv1.ReservedIPTargetVPNServerReference); ok { + return dataSourceIBMIsReservedIPReservedIPTargetVPNServerReferenceToMap(model.(*vpcv1.ReservedIPTargetVPNServerReference)) + } else if _, ok := model.(*vpcv1.ReservedIPTargetGenericResourceReference); ok { + return dataSourceIBMIsReservedIPReservedIPTargetGenericResourceReferenceToMap(model.(*vpcv1.ReservedIPTargetGenericResourceReference)) + } else if _, ok := model.(*vpcv1.ReservedIPTarget); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.ReservedIPTarget) + if model.CRN != nil { + modelMap["crn"] = model.CRN + } + if model.Deleted != nil { + deletedMap, err := dataSourceIBMIsReservedIPEndpointGatewayReferenceDeletedToMap(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.ReservedIPTargetIntf subtype encountered") + } +} + +func dataSourceIBMIsReservedIPEndpointGatewayReferenceDeletedToMap(model *vpcv1.EndpointGatewayReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = model.MoreInfo + return modelMap, nil +} + +func dataSourceIBMIsReservedIPReservedIPTargetEndpointGatewayReferenceToMap(model *vpcv1.ReservedIPTargetEndpointGatewayReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = model.CRN + if model.Deleted != nil { + deletedMap, err := dataSourceIBMIsReservedIPEndpointGatewayReferenceDeletedToMap(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 dataSourceIBMIsReservedIPReservedIPTargetVirtualNetworkInterfaceReferenceReservedIPTargetContextToMap(model *vpcv1.ReservedIPTargetVirtualNetworkInterfaceReferenceReservedIPTargetContext) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = model.CRN + modelMap["href"] = model.Href + modelMap["id"] = model.ID + modelMap["name"] = model.Name + modelMap["resource_type"] = model.ResourceType + return modelMap, nil +} + +func dataSourceIBMIsReservedIPReservedIPTargetNetworkInterfaceReferenceTargetContextToMap(model *vpcv1.ReservedIPTargetNetworkInterfaceReferenceTargetContext) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Deleted != nil { + deletedMap, err := dataSourceIBMIsReservedIPNetworkInterfaceReferenceTargetContextDeletedToMap(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 dataSourceIBMIsReservedIPNetworkInterfaceReferenceTargetContextDeletedToMap(model *vpcv1.NetworkInterfaceReferenceTargetContextDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = model.MoreInfo + return modelMap, nil +} + +func dataSourceIBMIsReservedIPReservedIPTargetBareMetalServerNetworkInterfaceReferenceTargetContextToMap(model *vpcv1.ReservedIPTargetBareMetalServerNetworkInterfaceReferenceTargetContext) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Deleted != nil { + deletedMap, err := dataSourceIBMIsReservedIPBareMetalServerNetworkInterfaceReferenceTargetContextDeletedToMap(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 dataSourceIBMIsReservedIPBareMetalServerNetworkInterfaceReferenceTargetContextDeletedToMap(model *vpcv1.BareMetalServerNetworkInterfaceReferenceTargetContextDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = model.MoreInfo + return modelMap, nil +} + +func dataSourceIBMIsReservedIPReservedIPTargetLoadBalancerReferenceToMap(model *vpcv1.ReservedIPTargetLoadBalancerReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = model.CRN + if model.Deleted != nil { + deletedMap, err := dataSourceIBMIsReservedIPLoadBalancerReferenceDeletedToMap(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 dataSourceIBMIsReservedIPLoadBalancerReferenceDeletedToMap(model *vpcv1.LoadBalancerReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = model.MoreInfo + return modelMap, nil +} + +func dataSourceIBMIsReservedIPReservedIPTargetVPNGatewayReferenceToMap(model *vpcv1.ReservedIPTargetVPNGatewayReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = model.CRN + if model.Deleted != nil { + deletedMap, err := dataSourceIBMIsReservedIPVPNGatewayReferenceDeletedToMap(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 dataSourceIBMIsReservedIPVPNGatewayReferenceDeletedToMap(model *vpcv1.VPNGatewayReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = model.MoreInfo + return modelMap, nil +} + +func dataSourceIBMIsReservedIPReservedIPTargetVPNServerReferenceToMap(model *vpcv1.ReservedIPTargetVPNServerReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = model.CRN + if model.Deleted != nil { + deletedMap, err := dataSourceIBMIsReservedIPVPNServerReferenceDeletedToMap(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 dataSourceIBMIsReservedIPVPNServerReferenceDeletedToMap(model *vpcv1.VPNServerReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = model.MoreInfo + return modelMap, nil +} + +func dataSourceIBMIsReservedIPReservedIPTargetGenericResourceReferenceToMap(model *vpcv1.ReservedIPTargetGenericResourceReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = model.CRN + if model.Deleted != nil { + deletedMap, err := dataSourceIBMIsReservedIPGenericResourceReferenceDeletedToMap(model.Deleted) + if err != nil { + return modelMap, err + } + modelMap["deleted"] = []map[string]interface{}{deletedMap} + } + modelMap["resource_type"] = model.ResourceType + return modelMap, nil +} + +func dataSourceIBMIsReservedIPGenericResourceReferenceDeletedToMap(model *vpcv1.GenericResourceReferenceDeleted) (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_virtual_network_interface.go b/ibm/service/vpc/data_source_ibm_is_virtual_network_interface.go index 181428db5f..cfd0945afb 100644 --- a/ibm/service/vpc/data_source_ibm_is_virtual_network_interface.go +++ b/ibm/service/vpc/data_source_ibm_is_virtual_network_interface.go @@ -26,6 +26,86 @@ func DataSourceIBMIsVirtualNetworkInterface() *schema.Resource { Required: true, Description: "The network interface identifier.", }, + // vni p2 changes + "allow_ip_spoofing": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether source IP spoofing is allowed on this interface. If `false`, source IP spoofing is prevented on this interface. If `true`, source IP spoofing is allowed on this interface.", + }, + "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.- `allow_ip_spoofing` must be `false`.- If the virtual network interface is attached: - The target `resource_type` must be `bare_metal_server_network_attachment`. - The target `interface_type` must not be `hipersocket`.", + }, + "tags": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: flex.ResourceIBMVPCHash, + Description: "UserTags for the vni instance", + }, + "access_tags": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: flex.ResourceIBMVPCHash, + Description: "Access management tags for the vni instance", + }, + + "ips": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The reserved IPs bound to this virtual network interface.May be empty when `lifecycle_state` is `pending`.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "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 reserved IP.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this reserved IP. The name is unique across all reserved IPs in a subnet.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "mac_address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The MAC address of the virtual network interface. May be absent if `lifecycle_state` is `pending`.", + }, + "auto_delete": { Type: schema.TypeBool, Computed: true, @@ -470,6 +550,49 @@ func dataSourceIBMIsVirtualNetworkInterfaceRead(context context.Context, d *sche return diag.FromErr(fmt.Errorf("Error setting zone %s", err)) } + // vni p2 changes + + tags, err := flex.GetGlobalTagsUsingCRN(meta, *virtualNetworkInterface.CRN, "", isUserTagType) + if err != nil { + log.Printf( + "Error on get of datasource vni (%s) tags: %s", *virtualNetworkInterface.ID, err) + } + + accesstags, err := flex.GetGlobalTagsUsingCRN(meta, *virtualNetworkInterface.CRN, "", isAccessTagType) + if err != nil { + log.Printf( + "Error on get of datasource vni (%s) access tags: %s", *virtualNetworkInterface.ID, err) + } + + d.Set("tags", tags) + d.Set("access_tags", accesstags) + + if err = d.Set("mac_address", virtualNetworkInterface.MacAddress); err != nil { + return diag.FromErr(fmt.Errorf("Error setting mac_address: %s", err)) + } + if err = d.Set("allow_ip_spoofing", virtualNetworkInterface.AllowIPSpoofing); err != nil { + return diag.FromErr(fmt.Errorf("Error setting allow_ip_spoofing: %s", err)) + } + if err = d.Set("enable_infrastructure_nat", virtualNetworkInterface.EnableInfrastructureNat); err != nil { + return diag.FromErr(fmt.Errorf("Error setting enable_infrastructure_nat: %s", err)) + } + + ips := []map[string]interface{}{} + if virtualNetworkInterface.Ips != nil { + for _, modelItem := range virtualNetworkInterface.Ips { + if *modelItem.ID != *virtualNetworkInterface.PrimaryIP.ID { + modelMap, err := dataSourceIBMIsVirtualNetworkInterfaceReservedIPReferenceToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + ips = append(ips, modelMap) + } + } + } + if err = d.Set("ips", ips); err != nil { + return diag.FromErr(fmt.Errorf("Error setting ips %s", err)) + } + return nil } diff --git a/ibm/service/vpc/data_source_ibm_is_virtual_network_interface_floating_ip.go b/ibm/service/vpc/data_source_ibm_is_virtual_network_interface_floating_ip.go new file mode 100644 index 0000000000..efb2c01ebb --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_virtual_network_interface_floating_ip.go @@ -0,0 +1,95 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsVirtualNetworkInterfaceFloatingIP() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsVirtualNetworkInterfaceFloatingIPRead, + + Schema: map[string]*schema.Schema{ + "virtual_network_interface": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The virtual network interface identifier", + }, + "floating_ip": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The floating IP identifier", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this floating IP. The name is unique across all floating IPs in the region.", + }, + + "deleted": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "If present, this property indicates the referenced resource has been deleted, and provides some supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Link to documentation about deleted resources", + }, + }, + }, + }, + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The globally unique IP address.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this floating IP.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this floating IP.", + }, + }, + } +} + +func dataSourceIBMIsVirtualNetworkInterfaceFloatingIPRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + vniId := d.Get("virtual_network_interface").(string) + fipId := d.Get("floating_ip").(string) + + getNetworkInterfaceFloatingIPOptions := &vpcv1.GetNetworkInterfaceFloatingIPOptions{} + getNetworkInterfaceFloatingIPOptions.SetVirtualNetworkInterfaceID(vniId) + getNetworkInterfaceFloatingIPOptions.SetID(fipId) + + floatingIP, response, err := sess.GetNetworkInterfaceFloatingIPWithContext(context, getNetworkInterfaceFloatingIPOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetVirtualNetworkInterfaceFloatingIPWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetVirtualNetworkInterfaceFloatingIPWithContext failed %s\n%s", err, response)) + } + d.SetId(*floatingIP.ID) + resourceIBMIsVirtualNetworkInterfaceFloatingIPGet(d, floatingIP) + return nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_virtual_network_interface_floating_ip_test.go b/ibm/service/vpc/data_source_ibm_is_virtual_network_interface_floating_ip_test.go new file mode 100644 index 0000000000..a587cc2b2b --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_virtual_network_interface_floating_ip_test.go @@ -0,0 +1,48 @@ +// Copyright IBM Corp. 2023 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 TestAccIBMIsVirtualNetworkInterfaceFloatingIPDataSourceBasic(t *testing.T) { + vpcname := fmt.Sprintf("tfp-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfp-subnet-%d", acctest.RandIntRange(10, 100)) + vniname := fmt.Sprintf("tfp-createname-%d", acctest.RandIntRange(10, 100)) + floatingipname := fmt.Sprintf("tfp-reservedip-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsVirtualNetworkInterfaceFloatingIPDataSourceConfigBasic(vpcname, subnetname, vniname, floatingipname), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface_floating_ip.is_floating_ip", "address"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface_floating_ip.is_floating_ip", "crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface_floating_ip.is_floating_ip", "floating_ip"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface_floating_ip.is_floating_ip", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface_floating_ip.is_floating_ip", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface_floating_ip.is_floating_ip", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface_floating_ip.is_floating_ip", "virtual_network_interface"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsVirtualNetworkInterfaceFloatingIPDataSourceConfigBasic(vpcname, subnetname, vniname, floatingipname string) string { + return testAccCheckIBMIsVirtualNetworkInterfaceFloatingIPConfigBasic(vpcname, subnetname, vniname, floatingipname) + fmt.Sprintf(` + data "ibm_is_virtual_network_interface_floating_ip" "is_floating_ip" { + virtual_network_interface = ibm_is_virtual_network_interface_floating_ip.testacc_vni_floatingip.virtual_network_interface + floating_ip = ibm_is_virtual_network_interface_floating_ip.testacc_vni_floatingip.floating_ip + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_virtual_network_interface_floating_ips.go b/ibm/service/vpc/data_source_ibm_is_virtual_network_interface_floating_ips.go new file mode 100644 index 0000000000..6282d5984f --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_virtual_network_interface_floating_ips.go @@ -0,0 +1,134 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsVirtualNetworkInterfaceFloatingIPs() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsVirtualNetworkInterfaceFloatingIPsRead, + + Schema: map[string]*schema.Schema{ + "virtual_network_interface": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The virtual network interface identifier", + }, + "floating_ips": { + Type: schema.TypeList, + Description: "List of floating ips associated with the virtual network interface id", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The floating IP identifier", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this floating IP. The name is unique across all floating IPs in the region.", + }, + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted, and provides some 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", + }, + }, + }, + }, + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The globally unique IP address.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this floating IP.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this floating IP.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsVirtualNetworkInterfaceFloatingIPsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + vniId := d.Get("virtual_network_interface").(string) + + start := "" + allrecs := []vpcv1.FloatingIPReference{} + for { + listNetworkInterfaceFloatingIpsOptions := &vpcv1.ListNetworkInterfaceFloatingIpsOptions{} + listNetworkInterfaceFloatingIpsOptions.SetVirtualNetworkInterfaceID(vniId) + if start != "" { + listNetworkInterfaceFloatingIpsOptions.Start = &start + } + floatingIPCollection, response, err := sess.ListNetworkInterfaceFloatingIpsWithContext(context, listNetworkInterfaceFloatingIpsOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error ListNetworkInterfaceFloatingIpsWithContext %s\n%s", err, response)) + } + start = flex.GetNext(floatingIPCollection.Next) + allrecs = append(allrecs, floatingIPCollection.FloatingIps...) + if start == "" { + break + } + } + floatingIpsInfo := make([]map[string]interface{}, 0) + for _, floatingIP := range allrecs { + l := map[string]interface{}{} + l["id"] = *floatingIP.ID + if !core.IsNil(floatingIP.Name) { + l["name"] = floatingIP.Name + } + l["address"] = floatingIP.Address + + l["crn"] = floatingIP.CRN + l["href"] = floatingIP.Href + deleted := make(map[string]interface{}) + + if floatingIP.Deleted != nil && floatingIP.Deleted.MoreInfo != nil { + deleted["more_info"] = floatingIP.Deleted + } + l["deleted"] = []map[string]interface{}{deleted} + floatingIpsInfo = append(floatingIpsInfo, l) + } + d.SetId(dataSourceIBMISVirtualNetworkInterfaceFloatingIPsID(d)) + d.Set("floating_ips", floatingIpsInfo) + + return nil +} + +// dataSourceIBMISVirtualNetworkInterfaceFloatingIPsID returns a reasonable ID for a Virtual Network Interface FloatingIPs ID list. +func dataSourceIBMISVirtualNetworkInterfaceFloatingIPsID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/service/vpc/data_source_ibm_is_virtual_network_interface_floating_ips_test.go b/ibm/service/vpc/data_source_ibm_is_virtual_network_interface_floating_ips_test.go new file mode 100644 index 0000000000..bf360f604d --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_virtual_network_interface_floating_ips_test.go @@ -0,0 +1,45 @@ +// Copyright IBM Corp. 2023 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 TestAccIBMIsVirtualNetworkInterfaceFloatingIPsDataSourceBasic(t *testing.T) { + vpcname := fmt.Sprintf("tfp-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfp-subnet-%d", acctest.RandIntRange(10, 100)) + vniname := fmt.Sprintf("tfp-createname-%d", acctest.RandIntRange(10, 100)) + floatingipname := fmt.Sprintf("tfp-reservedip-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsVirtualNetworkInterfaceFloatingIPsDataSourceConfigBasic(vpcname, subnetname, vniname, floatingipname), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface_floating_ips.is_floating_ips", "floating_ips.0.address"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface_floating_ips.is_floating_ips", "floating_ips.0.crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface_floating_ips.is_floating_ips", "floating_ips.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface_floating_ips.is_floating_ips", "floating_ips.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface_floating_ips.is_floating_ips", "floating_ips.0.name"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsVirtualNetworkInterfaceFloatingIPsDataSourceConfigBasic(vpcname, subnetname, vniname, floatingipname string) string { + return testAccCheckIBMIsVirtualNetworkInterfaceFloatingIPConfigBasic(vpcname, subnetname, vniname, floatingipname) + fmt.Sprintf(` + data "ibm_is_virtual_network_interface_floating_ips" "is_floating_ips" { + virtual_network_interface = ibm_is_virtual_network_interface_floating_ip.testacc_vni_floatingip.virtual_network_interface + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_virtual_network_interface_ip.go b/ibm/service/vpc/data_source_ibm_is_virtual_network_interface_ip.go new file mode 100644 index 0000000000..105f5704f3 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_virtual_network_interface_ip.go @@ -0,0 +1,100 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsVirtualNetworkInterfaceIP() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIsVirtualNetworkInterfaceIPRead, + + Schema: map[string]*schema.Schema{ + "virtual_network_interface": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The virtual network interface identifier", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The reserved IP identifier.", + }, + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP.", + }, + "reserved_ip": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this reserved IP. The name is unique across all reserved IPs in a subnet.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + } +} + +func dataSourceIsVirtualNetworkInterfaceIPRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + getVirtualNetworkInterfaceIPOptions := &vpcv1.GetVirtualNetworkInterfaceIPOptions{} + + getVirtualNetworkInterfaceIPOptions.SetVirtualNetworkInterfaceID(d.Get("virtual_network_interface").(string)) + getVirtualNetworkInterfaceIPOptions.SetID(d.Get("reserved_ip").(string)) + + reservedIP, response, err := vpcClient.GetVirtualNetworkInterfaceIPWithContext(context, getVirtualNetworkInterfaceIPOptions) + if err != nil { + log.Printf("[DEBUG] GetVirtualNetworkInterfaceIPWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetVirtualNetworkInterfaceIPWithContext failed for datasource %s\n%s", err, response)) + } + + d.SetId(*reservedIP.ID) + + if err = d.Set("address", reservedIP.Address); err != nil { + return diag.FromErr(fmt.Errorf("Error setting address: %s", err)) + } + if err = d.Set("href", reservedIP.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + if err = d.Set("reserved_ip", reservedIP.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting reserved_ip: %s", err)) + } + + if err = d.Set("name", reservedIP.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + if err = d.Set("resource_type", reservedIP.ResourceType); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_type: %s", err)) + } + + return nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_virtual_network_interface_ip_test.go b/ibm/service/vpc/data_source_ibm_is_virtual_network_interface_ip_test.go new file mode 100644 index 0000000000..99239c2bbc --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_virtual_network_interface_ip_test.go @@ -0,0 +1,48 @@ +// Copyright IBM Corp. 2023 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 TestAccIBMIsVirtualNetworkInterfaceIpDataSourceBasic(t *testing.T) { + vpcname := fmt.Sprintf("tfp-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfp-subnet-%d", acctest.RandIntRange(10, 100)) + vniname := fmt.Sprintf("tfp-createname-%d", acctest.RandIntRange(10, 100)) + reservedipname := fmt.Sprintf("tfp-reservedip-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsVirtualNetworkInterfaceIpDataSourceConfigBasic(vpcname, subnetname, vniname, reservedipname), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface_ip.is_reserved_ip", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface_ip.is_reserved_ip", "address"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface_ip.is_reserved_ip", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface_ip.is_reserved_ip", "reserved_ip"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface_ip.is_reserved_ip", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface_ip.is_reserved_ip", "resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface_ip.is_reserved_ip", "virtual_network_interface"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsVirtualNetworkInterfaceIpDataSourceConfigBasic(vpcname, subnetname, vniname, reservedipname string) string { + return testAccCheckIBMIsVirtualNetworkInterfaceIPConfigBasic(vpcname, subnetname, vniname, reservedipname) + fmt.Sprintf(` + data "ibm_is_virtual_network_interface_ip" "is_reserved_ip" { + virtual_network_interface = ibm_is_virtual_network_interface_ip.testacc_vni_reservedip.virtual_network_interface + reserved_ip = ibm_is_virtual_network_interface_ip.testacc_vni_reservedip.reserved_ip + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_virtual_network_interface_ips.go b/ibm/service/vpc/data_source_ibm_is_virtual_network_interface_ips.go new file mode 100644 index 0000000000..1a6c0395f7 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_virtual_network_interface_ips.go @@ -0,0 +1,136 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsVirtualNetworkInterfaceIPs() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIsVirtualNetworkInterfaceIPsRead, + + Schema: map[string]*schema.Schema{ + "virtual_network_interface": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The virtual network interface identifier", + }, + "reserved_ips": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Collection of reserved IPs for this virtual 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 has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this reserved IP.", + }, + "reserved_ip": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this reserved IP. The name is unique across all reserved IPs in a subnet.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIsVirtualNetworkInterfaceIPsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + listVirtualNetworkInterfaceIpsOptions := &vpcv1.ListVirtualNetworkInterfaceIpsOptions{} + + listVirtualNetworkInterfaceIpsOptions.SetVirtualNetworkInterfaceID(d.Get("virtual_network_interface").(string)) + var pager *vpcv1.VirtualNetworkInterfaceIpsPager + pager, err = vpcClient.NewVirtualNetworkInterfaceIpsPager(listVirtualNetworkInterfaceIpsOptions) + if err != nil { + return diag.FromErr(err) + } + + allItems, err := pager.GetAll() + if err != nil { + log.Printf("[DEBUG] VirtualNetworkInterfaceIpsPager.GetAll() failed %s", err) + return diag.FromErr(fmt.Errorf("VirtualNetworkInterfaceIpsPager.GetAll() failed %s", err)) + } + + d.SetId(dataSourceVirtualNetworkInterfaceIPsID(d)) + + mapSlice := []map[string]interface{}{} + for _, modelItem := range allItems { + modelMap, err := dataSourceIBMIsReservedIpsReservedIPToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + mapSlice = append(mapSlice, modelMap) + } + + if err = d.Set("reserved_ips", mapSlice); err != nil { + return diag.FromErr(fmt.Errorf("Error setting reserved_ips for virtual network interface datasource %s", err)) + } + + return nil +} + +// dataSourceVirtualNetworkInterfaceIPsID returns a reasonable ID for the list. +func dataSourceVirtualNetworkInterfaceIPsID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceIBMIsReservedIpsReservedIPCollectionFirstToMap(model *vpcv1.ReservedIPCollectionFirst) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = model.Href + return modelMap, nil +} + +func dataSourceIBMIsReservedIpsReservedIPCollectionNextToMap(model *vpcv1.ReservedIPCollectionNext) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = model.Href + return modelMap, nil +} + +func dataSourceIBMIsReservedIpsReservedIPToMap(model *vpcv1.ReservedIPReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["address"] = model.Address + modelMap["href"] = model.Href + modelMap["id"] = model.ID + modelMap["reserved_ip"] = model.ID + modelMap["name"] = model.Name + modelMap["resource_type"] = model.ResourceType + return modelMap, nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_virtual_network_interface_ips_test.go b/ibm/service/vpc/data_source_ibm_is_virtual_network_interface_ips_test.go new file mode 100644 index 0000000000..48eb37b3d1 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_virtual_network_interface_ips_test.go @@ -0,0 +1,46 @@ +// Copyright IBM Corp. 2023 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 TestAccIBMIsVirtualNetworkInterfaceIpsDataSourceBasic(t *testing.T) { + vpcname := fmt.Sprintf("tfp-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfp-subnet-%d", acctest.RandIntRange(10, 100)) + vniname := fmt.Sprintf("tfp-createname-%d", acctest.RandIntRange(10, 100)) + reservedipname := fmt.Sprintf("tfp-reservedip-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsVirtualNetworkInterfaceIpsDataSourceConfigBasic(vpcname, subnetname, vniname, reservedipname), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface_ips.is_reserved_ips", "reserved_ips.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface_ips.is_reserved_ips", "reserved_ips.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface_ips.is_reserved_ips", "reserved_ips.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface_ips.is_reserved_ips", "reserved_ips.0.address"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface_ips.is_reserved_ips", "reserved_ips.0.resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface_ips.is_reserved_ips", "reserved_ips.0.reserved_ip"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsVirtualNetworkInterfaceIpsDataSourceConfigBasic(vpcname, subnetname, vniname, reservedipname string) string { + return testAccCheckIBMIsVirtualNetworkInterfaceIPConfigBasic(vpcname, subnetname, vniname, reservedipname) + fmt.Sprintf(` + data "ibm_is_virtual_network_interface_ips" "is_reserved_ips" { + virtual_network_interface = ibm_is_virtual_network_interface_ip.testacc_vni_reservedip.virtual_network_interface + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_virtual_network_interface_test.go b/ibm/service/vpc/data_source_ibm_is_virtual_network_interface_test.go index bb94209e65..cb62f06806 100644 --- a/ibm/service/vpc/data_source_ibm_is_virtual_network_interface_test.go +++ b/ibm/service/vpc/data_source_ibm_is_virtual_network_interface_test.go @@ -7,19 +7,31 @@ import ( "fmt" "testing" + "github.com/IBM/vpc-go-sdk/vpcv1" + "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 TestAccIBMIsVirtualNetworkInterfaceDataSourceBasic(t *testing.T) { + var conf vpcv1.VirtualNetworkInterface + vpcname := fmt.Sprintf("tfvpngw-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfvpngw-subnet-%d", acctest.RandIntRange(10, 100)) + vniname := fmt.Sprintf("tfvpngw-createname-%d", acctest.RandIntRange(10, 100)) + tag1 := "env:test" + tag2 := "env:dev" + tag3 := "env:prod" + enable_infrastructure_nat := true + allow_ip_spoofing := true resource.Test(t, resource.TestCase{ PreCheck: func() { acc.TestAccPreCheck(t) }, Providers: acc.TestAccProviders, Steps: []resource.TestStep{ resource.TestStep{ - Config: testAccCheckIBMIsVirtualNetworkInterfaceDataSourceConfigBasic(), + Config: testAccCheckIBMIsVirtualNetworkInterfaceDataSourceConfigBasic(vpcname, subnetname, vniname, tag1, tag2, tag3, enable_infrastructure_nat, allow_ip_spoofing, false), Check: resource.ComposeTestCheckFunc( + testAccCheckIBMIsVirtualNetworkInterfaceExists("ibm_is_virtual_network_interface.testacc_vni", conf), resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface.is_virtual_network_interface", "virtual_network_interface"), resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface.is_virtual_network_interface", "auto_delete"), resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface.is_virtual_network_interface", "created_at"), @@ -32,17 +44,57 @@ func TestAccIBMIsVirtualNetworkInterfaceDataSourceBasic(t *testing.T) { resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface.is_virtual_network_interface", "security_groups.0.id"), resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface.is_virtual_network_interface", "subnet.0.id"), resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface.is_virtual_network_interface", "vpc.0.id"), + resource.TestCheckResourceAttr("data.ibm_is_virtual_network_interface.is_virtual_network_interface", "tags.#", "3"), resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface.is_virtual_network_interface", "zone.0.name"), ), }, }, }) } +func TestAccIBMIsVirtualNetworkInterfaceDataSourceVniBasic(t *testing.T) { + var conf vpcv1.VirtualNetworkInterface + vpcname := fmt.Sprintf("tfvpngw-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfvpngw-subnet-%d", acctest.RandIntRange(10, 100)) + vniname := fmt.Sprintf("tfvpngw-createname-%d", acctest.RandIntRange(10, 100)) + tag1 := "env:test" + tag2 := "env:dev" + tag3 := "env:prod" + enable_infrastructure_nat := true + allow_ip_spoofing := true + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsVirtualNetworkInterfaceDataSourceConfigBasic(vpcname, subnetname, vniname, tag1, tag2, tag3, enable_infrastructure_nat, allow_ip_spoofing, false), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMIsVirtualNetworkInterfaceExists("ibm_is_virtual_network_interface.testacc_vni", conf), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface.is_virtual_network_interface", "virtual_network_interface"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface.is_virtual_network_interface", "auto_delete"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface.is_virtual_network_interface", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface.is_virtual_network_interface", "crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface.is_virtual_network_interface", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface.is_virtual_network_interface", "lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface.is_virtual_network_interface", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface.is_virtual_network_interface", "resource_group.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface.is_virtual_network_interface", "resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface.is_virtual_network_interface", "security_groups.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface.is_virtual_network_interface", "subnet.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface.is_virtual_network_interface", "vpc.0.id"), + resource.TestCheckResourceAttr("data.ibm_is_virtual_network_interface.is_virtual_network_interface", "tags.#", "3"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface.is_virtual_network_interface", "zone.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface.is_virtual_network_interface", "enable_infrastructure_nat"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interface.is_virtual_network_interface", "allow_ip_spoofing"), + ), + }, + }, + }) +} -func testAccCheckIBMIsVirtualNetworkInterfaceDataSourceConfigBasic() string { - return fmt.Sprintf(` +func testAccCheckIBMIsVirtualNetworkInterfaceDataSourceConfigBasic(vpcname, subnetname, vniname, tag1, tag2, tag3 string, enablenat, allowipspoofing, isUpdate bool) string { + return testAccCheckIBMIsVirtualNetworkInterfaceConfigBasic(vpcname, subnetname, vniname, tag1, tag2, tag3, enablenat, allowipspoofing, false) + fmt.Sprintf(` data "ibm_is_virtual_network_interface" "is_virtual_network_interface" { - virtual_network_interface = "%s" + virtual_network_interface = ibm_is_virtual_network_interface.testacc_vni.id } - `, acc.VNIId) + `) } diff --git a/ibm/service/vpc/data_source_ibm_is_virtual_network_interfaces.go b/ibm/service/vpc/data_source_ibm_is_virtual_network_interfaces.go index 8705e323cb..4db5bee907 100644 --- a/ibm/service/vpc/data_source_ibm_is_virtual_network_interfaces.go +++ b/ibm/service/vpc/data_source_ibm_is_virtual_network_interfaces.go @@ -28,11 +28,92 @@ func DataSourceIBMIsVirtualNetworkInterfaces() *schema.Resource { Description: "Collection of virtual network interfaces.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ + + // vni p2 changes + "allow_ip_spoofing": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether source IP spoofing is allowed on this interface. If `false`, source IP spoofing is prevented on this interface. If `true`, source IP spoofing is allowed on this interface.", + }, + "tags": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: flex.ResourceIBMVPCHash, + Description: "UserTags for the vni instance", + }, + "access_tags": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: flex.ResourceIBMVPCHash, + Description: "Access management tags for the vni instance", + }, + "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.- `allow_ip_spoofing` must be `false`.- If the virtual network interface is attached: - The target `resource_type` must be `bare_metal_server_network_attachment`. - The target `interface_type` must not be `hipersocket`.", + }, + "ips": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The reserved IPs bound to this virtual network interface.May be empty when `lifecycle_state` is `pending`.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "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 reserved IP.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this reserved IP. The name is unique across all reserved IPs in a subnet.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "mac_address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The MAC address of the virtual network interface. May be absent if `lifecycle_state` is `pending`.", + }, + "auto_delete": &schema.Schema{ Type: schema.TypeBool, Computed: true, Description: "Indicates whether this virtual network interface will be automatically deleted when`target` is deleted.", }, + "created_at": &schema.Schema{ Type: schema.TypeString, Computed: true, @@ -384,6 +465,21 @@ func dataSourceIBMIsVirtualNetworkInterfacesRead(context context.Context, d *sch if err != nil { return diag.FromErr(err) } + + tags, err := flex.GetGlobalTagsUsingCRN(meta, *modelItem.CRN, "", isUserTagType) + if err != nil { + log.Printf( + "Error on get of datasources vni (%s) tags: %s", *modelItem.ID, err) + } + + accesstags, err := flex.GetGlobalTagsUsingCRN(meta, *modelItem.CRN, "", isAccessTagType) + if err != nil { + log.Printf( + "Error on get of datasources vni (%s) access tags: %s", *modelItem.ID, err) + } + + modelMap["tags"] = tags + modelMap["access_tags"] = accesstags mapSlice = append(mapSlice, modelMap) } @@ -478,5 +574,25 @@ func dataSourceIBMIsVirtualNetworkInterfacesVirtualNetworkInterfaceToMap(model * } modelMap["zone"] = []map[string]interface{}{zoneMap} } + // vni p2 changes + + modelMap["mac_address"] = model.MacAddress + modelMap["allow_ip_spoofing"] = model.AllowIPSpoofing + modelMap["enable_infrastructure_nat"] = model.EnableInfrastructureNat + + ips := []map[string]interface{}{} + if model.Ips != nil { + for _, modelItem := range model.Ips { + if *modelItem.ID != *model.PrimaryIP.ID { + modelMap, err := dataSourceIBMIsVirtualNetworkInterfaceReservedIPReferenceToMap(&modelItem) + if err != nil { + return modelMap, err + } + ips = append(ips, modelMap) + } + } + } + modelMap["ips"] = ips + return modelMap, nil } diff --git a/ibm/service/vpc/data_source_ibm_is_virtual_network_interfaces_test.go b/ibm/service/vpc/data_source_ibm_is_virtual_network_interfaces_test.go index a8fe404294..f3491a1e7e 100644 --- a/ibm/service/vpc/data_source_ibm_is_virtual_network_interfaces_test.go +++ b/ibm/service/vpc/data_source_ibm_is_virtual_network_interfaces_test.go @@ -41,6 +41,37 @@ func TestAccIBMIsVirtualNetworkInterfacesDataSourceBasic(t *testing.T) { }, }) } +func TestAccIBMIsVirtualNetworkInterfacesDataSourceVniBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsVirtualNetworkInterfacesDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interfaces.is_virtual_network_interfaces", "virtual_network_interfaces.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interfaces.is_virtual_network_interfaces", "virtual_network_interfaces.0.auto_delete"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interfaces.is_virtual_network_interfaces", "virtual_network_interfaces.0.created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interfaces.is_virtual_network_interfaces", "virtual_network_interfaces.0.crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interfaces.is_virtual_network_interfaces", "virtual_network_interfaces.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interfaces.is_virtual_network_interfaces", "virtual_network_interfaces.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interfaces.is_virtual_network_interfaces", "virtual_network_interfaces.0.lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interfaces.is_virtual_network_interfaces", "virtual_network_interfaces.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interfaces.is_virtual_network_interfaces", "virtual_network_interfaces.0.resource_group.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interfaces.is_virtual_network_interfaces", "virtual_network_interfaces.0.resource_group.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interfaces.is_virtual_network_interfaces", "virtual_network_interfaces.0.resource_group.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interfaces.is_virtual_network_interfaces", "virtual_network_interfaces.0.resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interfaces.is_virtual_network_interfaces", "virtual_network_interfaces.0.security_groups.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interfaces.is_virtual_network_interfaces", "virtual_network_interfaces.0.subnet.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interfaces.is_virtual_network_interfaces", "virtual_network_interfaces.0.vpc.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interfaces.is_virtual_network_interfaces", "virtual_network_interfaces.0.zone.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interfaces.is_virtual_network_interfaces", "virtual_network_interfaces.0.allow_ip_spoofing"), + resource.TestCheckResourceAttrSet("data.ibm_is_virtual_network_interfaces.is_virtual_network_interfaces", "virtual_network_interfaces.0.enable_infrastructure_nat"), + ), + }, + }, + }) +} func testAccCheckIBMIsVirtualNetworkInterfacesDataSourceConfigBasic() string { return fmt.Sprintf(` diff --git a/ibm/service/vpc/data_source_ibm_is_vpc_routing_table.go b/ibm/service/vpc/data_source_ibm_is_vpc_routing_table.go index 7293a719fd..d80be4197a 100644 --- a/ibm/service/vpc/data_source_ibm_is_vpc_routing_table.go +++ b/ibm/service/vpc/data_source_ibm_is_vpc_routing_table.go @@ -245,6 +245,9 @@ func dataSourceIBMIBMIsVPCRoutingTableRead(context context.Context, d *schema.Re routingTable = &r } } + if routingTable == nil { + return diag.FromErr(fmt.Errorf("[ERROR] Provided routing table %s cannot be found in the vpc %s", routingTableName, vpcId)) + } } d.SetId(*routingTable.ID) diff --git a/ibm/service/vpc/data_source_ibm_is_vpc_routing_table_routes.go b/ibm/service/vpc/data_source_ibm_is_vpc_routing_table_routes.go index 205d002bdc..6e723e5db6 100644 --- a/ibm/service/vpc/data_source_ibm_is_vpc_routing_table_routes.go +++ b/ibm/service/vpc/data_source_ibm_is_vpc_routing_table_routes.go @@ -221,6 +221,9 @@ func dataSourceIBMISVPCRoutingTableRoutesList(d *schema.ResourceData, meta inter if instance.LifecycleState != nil { route[isRoutingTableRouteLifecycleState] = *instance.LifecycleState } + if instance.Action != nil { + route[isRoutingTableRouteAction] = *instance.Action + } if instance.Advertise != nil { route["advertise"] = *instance.Advertise } 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 0d16c8493b..a8f8638b7c 100644 --- a/ibm/service/vpc/resource_ibm_is_bare_metal_server.go +++ b/ibm/service/vpc/resource_ibm_is_bare_metal_server.go @@ -12,6 +12,7 @@ import ( "os" "reflect" "strings" + "sync" "time" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" @@ -272,11 +273,14 @@ func ResourceIBMIsBareMetalServer() *schema.Resource { Description: "Enables stopping type of the bare metal server before deleting", }, isBareMetalServerPrimaryNetworkInterface: { - Type: schema.TypeList, - MinItems: 1, - MaxItems: 1, - Required: true, - Description: "Primary Network interface info", + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Optional: true, + Computed: true, + ExactlyOneOf: []string{"primary_network_attachment", "primary_network_interface"}, + ConflictsWith: []string{"primary_network_attachment", "network_attachments"}, + Description: "Primary Network interface info", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "id": { @@ -390,11 +394,278 @@ func ResourceIBMIsBareMetalServer() *schema.Resource { }, }, + "primary_network_attachment": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "The primary network attachment.", + ExactlyOneOf: []string{"primary_network_attachment", "primary_network_interface"}, + ConflictsWith: []string{"primary_network_interface", "network_interfaces"}, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + + // pna can accept either vni id or prototype + isBareMetalServerNicAllowedVlans: { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeInt}, + Set: schema.HashInt, + Description: "Indicates what VLAN IDs (for VLAN type only) can use this physical (PCI type) interface. A given VLAN can only be in the allowed_vlans array for one PCI type adapter per bare metal server.", + }, + + isBareMetalServerNicAllowInterfaceToFloat: { + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Indicates if the interface can float to any other server within the same resource_group. The interface will float automatically if the network detects a GARP or RARP on another bare metal server in the resource group. Applies only to vlan type interfaces.", + }, + + isBareMetalServerNicVlan: { + Type: schema.TypeInt, + Optional: true, + Computed: true, + Description: "Indicates the 802.1Q VLAN ID tag that must be used for all traffic on this interface", + }, + + isBareMetalServerNicInterfaceType: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_bare_metal_server", isBareMetalServerNicInterfaceType), + Description: "The network interface type: [ pci, vlan, hipersocket ]", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_bare_metal_server", "name"), + Description: "The name for this bare metal server network attachment. The name is unique across all network attachments for the bare metal server.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this bare metal server network attachment.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this bare metal server network attachment.", + }, + "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.", + }, + }, + }, + }, + + "virtual_network_interface": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Computed: true, + Description: "A virtual network interface for the bare metal server network attachment. This can be specified using an existing virtual network interface, or a prototype object for a new virtual network interface.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The virtual network interface id for this bare metal server network attachment.", + }, + "allow_ip_spoofing": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + ConflictsWith: []string{"primary_network_attachment.0.virtual_network_interface.0.id"}, + Computed: true, + Description: "Indicates whether source IP spoofing is allowed on this interface. If `false`, source IP spoofing is prevented on this interface. If `true`, source IP spoofing is allowed on this interface.", + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Indicates whether this virtual network interface will be automatically deleted when`target` is deleted.", + }, + "enable_infrastructure_nat": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + ConflictsWith: []string{"primary_network_attachment.0.virtual_network_interface.0.id"}, + 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 network interface, allowing the workload to perform any needed NAT operations.- `allow_ip_spoofing` must be `false`.- If the virtual network interface is attached: - The target `resource_type` must be `bare_metal_server_network_attachment`. - The target `interface_type` must not be `hipersocket`.", + }, + "ips": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Set: hashIpsList, + ConflictsWith: []string{"primary_network_attachment.0.virtual_network_interface.0.id"}, + Computed: true, + Description: "The reserved IPs bound to this virtual network interface.May be empty when `lifecycle_state` is `pending`.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "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.", + }, + }, + }, + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP.", + }, + "reserved_ip": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this reserved IP. The name is unique across all reserved IPs in a subnet.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"primary_network_attachment.0.virtual_network_interface.0.id"}, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_virtual_network_interface", "vni_name"), + Description: "The name for this virtual network interface. The name is unique across all virtual network interfaces in the VPC.", + }, + "primary_ip": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + ConflictsWith: []string{"primary_network_attachment.0.virtual_network_interface.0.id"}, + Computed: true, + Description: "The primary IP address of the virtual network interface for the bare metal server networkattachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "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 reserved IP.", + }, + "reserved_ip": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The name for this reserved IP. The name is unique across all reserved IPs in a subnet.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "resource_group": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"primary_network_attachment.0.virtual_network_interface.0.id"}, + Computed: true, + Description: "The resource group id for this virtual network interface.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "security_groups": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + ConflictsWith: []string{"primary_network_attachment.0.virtual_network_interface.0.id"}, + ForceNew: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "The security groups for this virtual network interface.", + }, + "subnet": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"primary_network_attachment.0.virtual_network_interface.0.id"}, + Computed: true, + ForceNew: true, + Description: "The associated subnet id.", + }, + }, + }, + }, + }, + }, + }, + isBareMetalServerNetworkInterfaces: { - Type: schema.TypeSet, - Optional: true, - Set: resourceIBMBMSNicSet, - Computed: true, + Type: schema.TypeSet, + Optional: true, + Set: resourceIBMBMSNicSet, + ConflictsWith: []string{"primary_network_attachment", "network_attachments"}, + Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "id": { @@ -520,6 +791,257 @@ func ResourceIBMIsBareMetalServer() *schema.Resource { }, }, + "network_attachments": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + ConflictsWith: []string{"primary_network_interface", "network_interfaces"}, + Description: "The network attachments for this bare metal server, including the primary network attachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + + // sna can accept either vni id or prototype + isBareMetalServerNicAllowedVlans: { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeInt}, + Set: schema.HashInt, + Description: "Indicates what VLAN IDs (for VLAN type only) can use this physical (PCI type) interface. A given VLAN can only be in the allowed_vlans array for one PCI type adapter per bare metal server.", + }, + + "allow_to_float": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Indicates if the interface can float to any other server within the same resource_group. The interface will float automatically if the network detects a GARP or RARP on another bare metal server in the resource group. Applies only to vlan type interfaces.", + }, + + isBareMetalServerNicVlan: { + Type: schema.TypeInt, + Optional: true, + Computed: true, + Description: "Indicates the 802.1Q VLAN ID tag that must be used for all traffic on this interface", + }, + + isBareMetalServerNicInterfaceType: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_bare_metal_server", isBareMetalServerNicInterfaceType), + Description: "The network interface type: [ pci, vlan, hipersocket ]", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_is_bare_metal_server", "name"), + Description: "The name for this bare metal server network attachment. The name is unique across all network attachments for the bare metal server.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this bare metal server network attachment.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this bare metal server network attachment.", + }, + "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.", + }, + }, + }, + }, + + "virtual_network_interface": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Computed: true, + Description: "A virtual network interface for the bare metal server network attachment. This can be specified using an existing virtual network interface, or a prototype object for a new virtual network interface.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The virtual network interface id for this bare metal server network attachment.", + }, + "allow_ip_spoofing": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Indicates whether source IP spoofing is allowed on this interface. If `false`, source IP spoofing is prevented on this interface. If `true`, source IP spoofing is allowed on this interface.", + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Indicates whether this virtual network interface will be automatically deleted when`target` is deleted.", + }, + "enable_infrastructure_nat": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + 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 network interface, allowing the workload to perform any needed NAT operations.- `allow_ip_spoofing` must be `false`.- If the virtual network interface is attached: - The target `resource_type` must be `bare_metal_server_network_attachment`. - The target `interface_type` must not be `hipersocket`.", + }, + "ips": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Set: hashIpsList, + Computed: true, + Description: "The reserved IPs bound to this virtual network interface.May be empty when `lifecycle_state` is `pending`.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "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.", + }, + }, + }, + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP.", + }, + "reserved_ip": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this reserved IP. The name is unique across all reserved IPs in a subnet.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_virtual_network_interface", "vni_name"), + Description: "The name for this virtual network interface. The name is unique across all virtual network interfaces in the VPC.", + }, + "primary_ip": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Computed: true, + Description: "The primary IP address of the virtual network interface for the bare metal server networkattachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "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 reserved IP.", + }, + "reserved_ip": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The name for this reserved IP. The name is unique across all reserved IPs in a subnet.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "resource_group": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The resource group id for this virtual network interface.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "security_groups": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "The security groups for this virtual network interface.", + }, + "subnet": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The associated subnet id.", + }, + }, + }, + }, + }, + }, + }, + isBareMetalServerKeys: { Type: schema.TypeSet, Required: true, @@ -840,6 +1362,35 @@ func resourceIBMISBareMetalServerCreate(context context.Context, d *schema.Resou options.PrimaryNetworkInterface = primnicobj } + if _, ok := d.GetOk("primary_network_attachment"); ok { + primarynetworkAttachmentsIntf := d.Get("primary_network_attachment") + i := 0 + allowipspoofing := fmt.Sprintf("primary_network_attachment.0.virtual_network_interface.%d.allow_ip_spoofing", i) + autodelete := fmt.Sprintf("primary_network_attachment.0.virtual_network_interface.%d.autodelete", i) + enablenat := fmt.Sprintf("primary_network_attachment.0.virtual_network_interface.%d.enable_infrastructure_nat", i) + primaryNetworkAttachmentModel, err := resourceIBMIsBareMetalServerMapToBareMetalServerPrimaryNetworkAttachmentPrototype(allowipspoofing, autodelete, enablenat, d, primarynetworkAttachmentsIntf.([]interface{})[0].(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + options.PrimaryNetworkAttachment = primaryNetworkAttachmentModel + } + if i, ok := d.GetOk("network_attachments"); ok { + allowipspoofing := fmt.Sprintf("network_attachments.%d.virtual_network_interface.0.allow_ip_spoofing", i) + autodelete := fmt.Sprintf("network_attachments.%d.virtual_network_interface.0.autodelete", i) + enablenat := fmt.Sprintf("network_attachments.%d.virtual_network_interface.0.enable_infrastructure_nat", i) + allowfloat := fmt.Sprintf("network_attachments.%d.virtual_network_interface.0.allow_to_float", i) + networkAttachmentsIntf := d.Get("network_attachments") + networkAttachments := []vpcv1.BareMetalServerNetworkAttachmentPrototypeIntf{} + for _, networkAttachmentsItem := range networkAttachmentsIntf.([]interface{}) { + networkAttachmentsItemModel, err := resourceIBMIsBareMetalServerMapToBareMetalServerNetworkAttachmentPrototype(allowipspoofing, allowfloat, autodelete, enablenat, d, networkAttachmentsItem.(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + networkAttachments = append(networkAttachments, networkAttachmentsItemModel) + } + options.NetworkAttachments = networkAttachments + } + if nicsintf, ok := d.GetOk(isBareMetalServerNetworkInterfaces); ok { nics := nicsintf.(*schema.Set).List() @@ -1551,6 +2102,25 @@ func bareMetalServerGet(context context.Context, d *schema.ResourceData, meta in d.Set(isBareMetalServerPrimaryNetworkInterface, primaryNicList) } + if !core.IsNil(bms.PrimaryNetworkAttachment) { + pnaId := *bms.PrimaryNetworkAttachment.ID + getBareMetalServerNetworkAttachment := &vpcv1.GetBareMetalServerNetworkAttachmentOptions{ + BareMetalServerID: &id, + ID: &pnaId, + } + pna, response, err := sess.GetBareMetalServerNetworkAttachment(getBareMetalServerNetworkAttachment) + if err != nil { + return fmt.Errorf("[ERROR] Error on GetBareMetalServerNetworkAttachment in bms : %s\n%s", err, response) + } + primaryNetworkAttachmentMap, err := resourceIBMIsBareMetalServerBareMetalServerNetworkAttachmentReferenceToMap(bms.PrimaryNetworkAttachment, pna, sess) + if err != nil { + return err + } + if err = d.Set("primary_network_attachment", []map[string]interface{}{primaryNetworkAttachmentMap}); err != nil { + return fmt.Errorf("[ERROR] Error setting primary_network_attachment: %s", err) + } + } + //ni if bms.NetworkInterfaces != nil { interfacesList := make([]map[string]interface{}, 0) @@ -1675,6 +2245,32 @@ func bareMetalServerGet(context context.Context, d *schema.ResourceData, meta in } d.Set(isBareMetalServerNetworkInterfaces, interfacesList) } + + if !core.IsNil(bms.NetworkAttachments) { + networkAttachments := []map[string]interface{}{} + for _, networkAttachmentsItem := range bms.NetworkAttachments { + naId := *networkAttachmentsItem.ID + if *bms.PrimaryNetworkAttachment.ID != naId { + getBareMetalServerNetworkAttachment := &vpcv1.GetBareMetalServerNetworkAttachmentOptions{ + BareMetalServerID: &id, + ID: &naId, + } + na, response, err := sess.GetBareMetalServerNetworkAttachment(getBareMetalServerNetworkAttachment) + if err != nil { + return fmt.Errorf("[ERROR] Error on GetBareMetalServerNetworkAttachment in baremetal server : %s\n%s", err, response) + } + networkAttachmentsItemMap, err := resourceIBMIsBareMetalServerBareMetalServerNetworkAttachmentReferenceToMap(&networkAttachmentsItem, na, sess) + if err != nil { + return err + } + networkAttachments = append(networkAttachments, networkAttachmentsItemMap) + } + } + if err = d.Set("network_attachments", networkAttachments); err != nil { + return fmt.Errorf("[ERROR] Error setting network_attachments: %s", err) + } + } + d.Set(isBareMetalServerProfile, *bms.Profile.Name) if bms.ResourceGroup != nil { d.Set(isBareMetalServerResourceGroup, *bms.ResourceGroup.ID) @@ -1734,13 +2330,508 @@ func bareMetalServerUpdate(context context.Context, d *schema.ResourceData, meta return err } isServerStopped := false - if d.HasChange(isBareMetalServerTags) || d.HasChange(isBareMetalServerAccessTags) { - bmscrn := d.Get(isBareMetalServerCRN).(string) - if bmscrn == "" { - options := &vpcv1.GetBareMetalServerOptions{ - ID: &id, + + // network attachments + + // primary network attachment + + if d.HasChange("primary_network_attachment") && !d.IsNewResource() { + nameChanged := d.HasChange("primary_network_attachment.0.name") + avChanged := d.HasChange("primary_network_attachment.0.allowed_vlans") + vniChanged := d.HasChange("primary_network_attachment.0.virtual_network_interface") + if nameChanged || avChanged { + pnacId := d.Get("primary_network_attachment.0.id").(string) + updateBareMetalServerNetworkAttachmentOptions := &vpcv1.UpdateBareMetalServerNetworkAttachmentOptions{} + updateBareMetalServerNetworkAttachmentOptions.SetBareMetalServerID(d.Id()) + updateBareMetalServerNetworkAttachmentOptions.SetID(pnacId) + patchVals := &vpcv1.BareMetalServerNetworkAttachmentPatch{} + if avChanged { + var allowedVlans []int64 + for _, v := range d.Get("primary_network_attachment.0.allowed_vlans").(*schema.Set).List() { + allowedVlansItem := int64(v.(int)) + allowedVlans = append(allowedVlans, allowedVlansItem) + } + patchVals.AllowedVlans = allowedVlans } - bms, response, err := sess.GetBareMetalServerWithContext(context, options) + if nameChanged { + newName := d.Get("primary_network_attachment.0.name").(string) + patchVals.Name = &newName + } + updateBareMetalServerNetworkAttachmentOptions.BareMetalServerNetworkAttachmentPatch, _ = patchVals.AsPatch() + _, response, err := sess.UpdateBareMetalServerNetworkAttachmentWithContext(context, updateBareMetalServerNetworkAttachmentOptions) + if err != nil { + log.Printf("[DEBUG] UpdateBareMetalServerNetworkAttachmentWithContext failed %s\n%s", err, response) + return fmt.Errorf("UpdateBareMetalServerNetworkAttachmentWithContext failed %s\n%s", err, response) + } + } + if vniChanged { + vniId := d.Get("primary_network_attachment.0.virtual_network_interface.0.id").(string) + updateVirtualNetworkInterfaceOptions := &vpcv1.UpdateVirtualNetworkInterfaceOptions{ + ID: &vniId, + } + virtualNetworkInterfacePatch := &vpcv1.VirtualNetworkInterfacePatch{} + if d.HasChange("primary_network_attachment.0.virtual_network_interface.0.auto_delete") { + autodelete := d.Get("primary_network_attachment.0.virtual_network_interface.0.auto_delete").(bool) + virtualNetworkInterfacePatch.AutoDelete = &autodelete + } + if d.HasChange("primary_network_attachment.0.virtual_network_interface.0.name") { + name := d.Get("primary_network_attachment.0.virtual_network_interface.0.name").(string) + virtualNetworkInterfacePatch.Name = &name + } + if d.HasChange("primary_network_attachment.0.virtual_network_interface.0.enable_infrastructure_nat") { + enableNat := d.Get("primary_network_attachment.0.virtual_network_interface.0.enable_infrastructure_nat").(bool) + virtualNetworkInterfacePatch.EnableInfrastructureNat = &enableNat + } + if d.HasChange("primary_network_attachment.0.virtual_network_interface.0.allow_ip_spoofing") { + allIpSpoofing := d.Get("primary_network_attachment.0.virtual_network_interface.0.allow_ip_spoofing").(bool) + virtualNetworkInterfacePatch.AllowIPSpoofing = &allIpSpoofing + } + virtualNetworkInterfacePatchAsPatch, err := virtualNetworkInterfacePatch.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error encountered while apply as patch for virtualNetworkInterfacePatch of BareMetalServer(%s) vni (%s) %s", d.Id(), vniId, err) + } + updateVirtualNetworkInterfaceOptions.VirtualNetworkInterfacePatch = virtualNetworkInterfacePatchAsPatch + _, response, err := sess.UpdateVirtualNetworkInterfaceWithContext(context, updateVirtualNetworkInterfaceOptions) + if err != nil { + log.Printf("[DEBUG] UpdateVirtualNetworkInterfaceWithContext failed %s\n%s", err, response) + return fmt.Errorf("UpdateVirtualNetworkInterfaceWithContext failed during BareMetalServer(%s) network attachment patch %s\n%s", d.Id(), err, response) + } + + if d.HasChange("primary_network_attachment.0.virtual_network_interface.0.ips") { + oldips, newips := d.GetChange("primary_network_attachment.0.virtual_network_interface.0.ips") + os := oldips.(*schema.Set) + ns := newips.(*schema.Set) + var oldset, newset *schema.Set + + var out = make([]interface{}, ns.Len(), ns.Len()) + for i, nA := range ns.List() { + newPack := nA.(map[string]interface{}) + out[i] = newPack["reserved_ip"].(string) + } + newset = schema.NewSet(schema.HashString, out) + + out = make([]interface{}, os.Len(), os.Len()) + for i, oA := range os.List() { + oldPack := oA.(map[string]interface{}) + out[i] = oldPack["reserved_ip"].(string) + } + oldset = schema.NewSet(schema.HashString, out) + + remove := flex.ExpandStringList(oldset.Difference(newset).List()) + add := flex.ExpandStringList(newset.Difference(oldset).List()) + + if add != nil && len(add) > 0 { + for _, ipItem := range add { + if ipItem != "" { + + addVirtualNetworkInterfaceIPOptions := &vpcv1.AddVirtualNetworkInterfaceIPOptions{} + addVirtualNetworkInterfaceIPOptions.SetVirtualNetworkInterfaceID(vniId) + addVirtualNetworkInterfaceIPOptions.SetID(ipItem) + _, response, err := sess.AddVirtualNetworkInterfaceIPWithContext(context, addVirtualNetworkInterfaceIPOptions) + if err != nil { + log.Printf("[DEBUG] AddVirtualNetworkInterfaceIPWithContext failed in VirtualNetworkInterface patch during BareMetalServer nac patch %s\n%s", err, response) + return fmt.Errorf("AddVirtualNetworkInterfaceIPWithContext failed in VirtualNetworkInterface patch during BareMetalServer nac patch %s\n%s", err, response) + } + } + } + } + if remove != nil && len(remove) > 0 { + for _, ipItem := range remove { + if ipItem != "" { + + removeVirtualNetworkInterfaceIPOptions := &vpcv1.RemoveVirtualNetworkInterfaceIPOptions{} + removeVirtualNetworkInterfaceIPOptions.SetVirtualNetworkInterfaceID(vniId) + removeVirtualNetworkInterfaceIPOptions.SetID(ipItem) + response, err := sess.RemoveVirtualNetworkInterfaceIPWithContext(context, removeVirtualNetworkInterfaceIPOptions) + if err != nil { + log.Printf("[DEBUG] RemoveVirtualNetworkInterfaceIPWithContext failed in VirtualNetworkInterface patch during BareMetalServer nac patch %s\n%s", err, response) + return fmt.Errorf("RemoveVirtualNetworkInterfaceIPWithContext failed in VirtualNetworkInterface patch during BareMetalServer nac patch %s\n%s", err, response) + } + } + } + } + + } + if d.HasChange("primary_network_attachment.0.virtual_network_interface.0.primary_ip") { + subnetId := d.Get("primary_network_attachment.0.virtual_network_interface.0.subnet").(string) + ripId := d.Get("primary_network_attachment.0.virtual_network_interface.0.primary_ip.0.reserved_ip").(string) + updateripoptions := &vpcv1.UpdateSubnetReservedIPOptions{ + SubnetID: &subnetId, + ID: &ripId, + } + reservedIpPath := &vpcv1.ReservedIPPatch{} + if d.HasChange("primary_network_attachment.0.virtual_network_interface.0.primary_ip.0.name") { + name := d.Get("primary_network_attachment.0.virtual_network_interface.0.primary_ip.0.name").(string) + reservedIpPath.Name = &name + } + if d.HasChange("primary_network_attachment.0.virtual_network_interface.0.primary_ip.0.auto_delete") { + auto := d.Get("primary_network_attachment.0.virtual_network_interface.0.primary_ip.0.auto_delete").(bool) + reservedIpPath.AutoDelete = &auto + } + reservedIpPathAsPatch, err := reservedIpPath.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error calling reserved ip as patch on vni patch \n%s", err) + } + updateripoptions.ReservedIPPatch = reservedIpPathAsPatch + _, response, err := sess.UpdateSubnetReservedIP(updateripoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error updating vni reserved ip(%s): %s\n%s", ripId, err, response) + } + } + if d.HasChange("primary_network_attachment.0.virtual_network_interface.0.security_groups") { + ovs, nvs := d.GetChange("primary_network_attachment.0.virtual_network_interface.0.security_groups") + ov := ovs.(*schema.Set) + nv := nvs.(*schema.Set) + remove := flex.ExpandStringList(ov.Difference(nv).List()) + add := flex.ExpandStringList(nv.Difference(ov).List()) + if len(add) > 0 { + for i := range add { + createsgnicoptions := &vpcv1.CreateSecurityGroupTargetBindingOptions{ + SecurityGroupID: &add[i], + ID: &vniId, + } + _, response, err := sess.CreateSecurityGroupTargetBinding(createsgnicoptions) + if err != nil { + return (fmt.Errorf("[ERROR] Error while creating security group %q for virtual network interface %s\n%s: %q", add[i], d.Id(), err, response)) + } + _, err = isWaitForVirtualNetworkInterfaceAvailable(sess, vniId, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return (err) + } + } + + } + if len(remove) > 0 { + for i := range remove { + deletesgnicoptions := &vpcv1.DeleteSecurityGroupTargetBindingOptions{ + SecurityGroupID: &remove[i], + ID: &vniId, + } + response, err := sess.DeleteSecurityGroupTargetBinding(deletesgnicoptions) + if err != nil { + return (fmt.Errorf("[ERROR] Error while removing security group %q for virtual network interface %s\n%s: %q", remove[i], d.Id(), err, response)) + } + _, err = isWaitForVirtualNetworkInterfaceAvailable(sess, vniId, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return (err) + } + } + } + } + + } + } + + // network attachments + + if d.HasChange("network_attachments") && !d.IsNewResource() { + // nacs := d.Get("network_attachments").([]interface{}) + ots, nts := d.GetChange("network_attachments") + otsIntf := ots.([]interface{}) + ntsIntf := nts.([]interface{}) + + // out := make([]string, len(otsIntf)) + listToRemove, listToAdd, serverToStop, listToUpdate := findNetworkAttachmentDifferences(otsIntf, ntsIntf, d.Id(), sess, d) + + if listToUpdate != nil { + return fmt.Errorf("[ERROR] Error while updating network attachment BareMetalServer(%s) \n%s", d.Id(), err) + } + serverStopped := false + if serverToStop { + // stop the server + serverStopped = true + isServerStopped, err = resourceStopServerIfRunning(id, "hard", d, context, sess, isServerStopped) + if err != nil { + return err + } + } + for _, removeItem := range listToRemove { + res, err := sess.DeleteBareMetalServerNetworkAttachment(&removeItem) + if err != nil { + return fmt.Errorf("[ERROR] Error while removing network attachment(%s) of BareMetalServer(%s) \n%s: %q", *removeItem.ID, d.Id(), err, res) + } + } + for _, addItem := range listToAdd { + _, res, err := sess.CreateBareMetalServerNetworkAttachment(&addItem) + if err != nil { + return fmt.Errorf("[ERROR] Error while adding network attachment(%s) of BareMetalServer(%s) \n%s: %q", *addItem.BareMetalServerID, d.Id(), err, res) + } + } + if serverStopped && isServerStopped { + // retstart ther server + isServerStopped, err = resourceStartServerIfStopped(id, "hard", d, context, sess, isServerStopped) + if err != nil { + return err + } + } + // j := 0 + // for _, currOtsG := range otsIntf { + // currOts := currOtsG.(map[string]interface{}) + // flag := false + // for _, currNtsG := range ntsIntf { + // currNts := currNtsG.(map[string]interface{}) + // if currOts["id"].(string) == currNts["id"].(string) { + // flag = true + // } + // } + // if !flag { + // log.Printf("[INFO] Nac with name (%s) will be deleted", currOts["name"].(string)) + // nacId := currOts["id"] + // if nacId != nil && nacId.(string) != "" { + // nacIdStr := nacId.(string) + // if !containsNacId(out, nacIdStr) { + // out[j] = nacIdStr + // j = j + 1 + // deleteBareMetalServerNetworkAttachmentOptions := &vpcv1.DeleteBareMetalServerNetworkAttachmentOptions{ + // BareMetalServerID: &id, + // ID: &nacIdStr, + // } + // res, err := sess.DeleteBareMetalServerNetworkAttachment(deleteBareMetalServerNetworkAttachmentOptions) + // if err != nil { + // return fmt.Errorf("[ERROR] Error while deleting network attachment(%s) of BareMetalServer(%s) \n%s: %q", nacIdStr, d.Id(), err, res) + // } + // } + // } + // } + // } + + // for i, nac := range nacs { + // nacIdKey := fmt.Sprintf("network_attachments.%d.id", i) + // nacId := d.Get(nacIdKey).(string) + // // if nacId is empty, then create + // // if nacId == "" || containsNacId(out, nacId) { + + // if nacId == "" { + // log.Printf("[DEBUG] nacId is empty") + // allowipspoofing := fmt.Sprintf("network_attachments.%d.virtual_network_interface.0.allow_ip_spoofing", i) + // autodelete := fmt.Sprintf("network_attachments.%d.virtual_network_interface.0.auto_delete", i) + // enablenat := fmt.Sprintf("network_attachments.%d.virtual_network_interface.0.enable_infrastructure_nat", i) + // nacMap := nac.(map[string]interface{}) + // VirtualNetworkInterfaceModel, err := resourceIBMIsBareMetalServerMapToVirtualNetworkInterfacePrototypeAttachmentContext(allowipspoofing, autodelete, enablenat, d, nacMap["virtual_network_interface"].([]interface{})[0].(map[string]interface{})) + // if err != nil { + // return err + // } + // nacNameStr := nacMap["name"].(string) + // createBareMetalServerNetworkAttachmentOptions := &vpcv1.CreateBareMetalServerNetworkAttachmentOptions{ + // BareMetalServerID: &id, + // } + // bareMetalServerNetworkAttachmentPrototype := &vpcv1.BareMetalServerNetworkAttachmentPrototype{ + // Name: &nacNameStr, + // VirtualNetworkInterface: VirtualNetworkInterfaceModel, + // } + // createBareMetalServerNetworkAttachmentOptions.BareMetalServerNetworkAttachmentPrototype = bareMetalServerNetworkAttachmentPrototype + // _, res, err := sess.CreateBareMetalServerNetworkAttachment(createBareMetalServerNetworkAttachmentOptions) + // if err != nil { + // return fmt.Errorf("[ERROR] Error while creating network attachment(%s) of BareMetalServer(%s) \n%s: %q", nacNameStr, d.Id(), err, res) + // } + // } else { + // log.Printf("[DEBUG] nacId is not empty") + // nacName := fmt.Sprintf("network_attachments.%d.name", i) + // nacVniName := fmt.Sprintf("network_attachments.%d.virtual_network_interface", i) + // primaryipName := fmt.Sprintf("%s.%s", nacVniName, "0.primary_ip") + // sgName := fmt.Sprintf("%s.%s", nacVniName, "0.security_groups") + // if d.HasChange(nacName) { + // networkName := d.Get(nacName).(string) + // updateBareMetalServerNetworkAttachmentOptions := &vpcv1.UpdateBareMetalServerNetworkAttachmentOptions{ + // BareMetalServerID: &id, + // ID: &nacId, + // } + // bareMetalServerNetworkAttachmentPatch := &vpcv1.InstanceNetworkAttachmentPatch{ + // Name: &networkName, + // } + // bareMetalServerNetworkAttachmentPatchAsPatch, err := bareMetalServerNetworkAttachmentPatch.AsPatch() + // if err != nil { + // return (fmt.Errorf("[ERROR] Error encountered while apply as patch for BareMetalServerNetworkAttachmentPatchAsPatch of network attachment(%s) of instance(%s) %s", nacId, id, err)) + // } + // updateBareMetalServerNetworkAttachmentOptions.BareMetalServerNetworkAttachmentPatch = bareMetalServerNetworkAttachmentPatchAsPatch + // _, res, err := sess.UpdateBareMetalServerNetworkAttachment(updateBareMetalServerNetworkAttachmentOptions) + // if err != nil { + // return (fmt.Errorf("[ERROR] Error encountered while updating network attachment(%s) name of BareMetalServer(%s) %s/n%s", nacId, id, err, res)) + // } + // // output, err := json.MarshalIndent(updateInstanceNetworkAttachmentOptions, "", " ") + // // if err == nil { + // // log.Printf("%+v\n", string(output)) + // // } else { + // // log.Printf("Error : %#v", updateInstanceNetworkAttachmentOptions) + // // } + // } + // if d.HasChange(nacVniName) { + // vniId := d.Get(fmt.Sprintf("%s.%s", nacVniName, "0.id")).(string) + // updateVirtualNetworkInterfaceOptions := &vpcv1.UpdateVirtualNetworkInterfaceOptions{ + // ID: &vniId, + // } + // virtualNetworkInterfacePatch := &vpcv1.VirtualNetworkInterfacePatch{} + // autoDeleteName := fmt.Sprintf("%s.%s", nacVniName, "0.auto_delete") + // nameName := fmt.Sprintf("%s.%s", nacVniName, "0.name") + // ipsName := fmt.Sprintf("%s.%s", nacVniName, "0.ips") + // enableNatName := fmt.Sprintf("%s.%s", nacVniName, "0.enable_infrastructure_nat") + // allowIpSpoofingName := fmt.Sprintf("%s.%s", nacVniName, "0.allow_ip_spoofing") + // if d.HasChange(autoDeleteName) { + // autodelete := d.Get(autoDeleteName).(bool) + // virtualNetworkInterfacePatch.AutoDelete = &autodelete + // } + // if d.HasChange(nameName) { + // name := d.Get(nameName).(string) + // virtualNetworkInterfacePatch.Name = &name + // } + // if d.HasChange(enableNatName) { + // enableNat := d.Get(enableNatName).(bool) + // virtualNetworkInterfacePatch.EnableInfrastructureNat = &enableNat + // } + // if d.HasChange(allowIpSpoofingName) { + // allIpSpoofing := d.Get(allowIpSpoofingName).(bool) + // virtualNetworkInterfacePatch.AllowIPSpoofing = &allIpSpoofing + // } + // virtualNetworkInterfacePatchAsPatch, err := virtualNetworkInterfacePatch.AsPatch() + // if err != nil { + // return fmt.Errorf("[ERROR] Error encountered while apply as patch for virtualNetworkInterfacePatch of instance(%s) vni (%s) %s", d.Id(), vniId, err) + // } + // updateVirtualNetworkInterfaceOptions.VirtualNetworkInterfacePatch = virtualNetworkInterfacePatchAsPatch + // _, response, err := sess.UpdateVirtualNetworkInterface(updateVirtualNetworkInterfaceOptions) + // if err != nil { + // log.Printf("[DEBUG] UpdateVirtualNetworkInterfaceWithContext failed %s\n%s", err, response) + // return fmt.Errorf("UpdateVirtualNetworkInterfaceWithContext failed during instance(%s) network attachment patch %s\n%s", d.Id(), err, response) + // } + + // if d.HasChange(ipsName) { + // oldips, newips := d.GetChange(ipsName) + // os := oldips.(*schema.Set) + // ns := newips.(*schema.Set) + // var oldset, newset *schema.Set + + // var out = make([]interface{}, ns.Len(), ns.Len()) + // for i, nA := range ns.List() { + // newPack := nA.(map[string]interface{}) + // out[i] = newPack["reserved_ip"].(string) + // } + // newset = schema.NewSet(schema.HashString, out) + + // out = make([]interface{}, os.Len(), os.Len()) + // for i, oA := range os.List() { + // oldPack := oA.(map[string]interface{}) + // out[i] = oldPack["reserved_ip"].(string) + // } + // oldset = schema.NewSet(schema.HashString, out) + + // remove := flex.ExpandStringList(oldset.Difference(newset).List()) + // add := flex.ExpandStringList(newset.Difference(oldset).List()) + + // if add != nil && len(add) > 0 { + // for _, ipItem := range add { + // if ipItem != "" { + // addVirtualNetworkInterfaceIPOptions := &vpcv1.AddVirtualNetworkInterfaceIPOptions{} + // addVirtualNetworkInterfaceIPOptions.SetVirtualNetworkInterfaceID(vniId) + // addVirtualNetworkInterfaceIPOptions.SetID(ipItem) + // _, response, err := sess.AddVirtualNetworkInterfaceIP(addVirtualNetworkInterfaceIPOptions) + // if err != nil { + // log.Printf("[DEBUG] AddVirtualNetworkInterfaceIPWithContext failed in VirtualNetworkInterface patch during instance nac patch %s\n%s", err, response) + // return fmt.Errorf("AddVirtualNetworkInterfaceIPWithContext failed in VirtualNetworkInterface patch during instance nac patch %s\n%s", err, response) + // } + // } + // } + // } + // if remove != nil && len(remove) > 0 { + // for _, ipItem := range remove { + // if ipItem != "" { + // removeVirtualNetworkInterfaceIPOptions := &vpcv1.RemoveVirtualNetworkInterfaceIPOptions{} + // removeVirtualNetworkInterfaceIPOptions.SetVirtualNetworkInterfaceID(vniId) + // removeVirtualNetworkInterfaceIPOptions.SetID(ipItem) + // response, err := sess.RemoveVirtualNetworkInterfaceIP(removeVirtualNetworkInterfaceIPOptions) + // if err != nil { + // log.Printf("[DEBUG] RemoveVirtualNetworkInterfaceIPWithContext failed in VirtualNetworkInterface patch during instance nac patch %s\n%s", err, response) + // return fmt.Errorf("RemoveVirtualNetworkInterfaceIPWithContext failed in VirtualNetworkInterface patch during instance nac patch %s\n%s", err, response) + // } + // } + // } + // } + // } + + // if d.HasChange(primaryipName) { + // subnetIdName := fmt.Sprintf("%s.%s", nacVniName, "0.subnet") + // ripIdName := fmt.Sprintf("%s.%s", primaryipName, "0.reserved_ip") + // subnetId := d.Get(subnetIdName).(string) + // primaryipNameName := fmt.Sprintf("%s.%s", primaryipName, "0.name") + // primaryipAutoDeleteName := fmt.Sprintf("%s.%s", primaryipName, "0.name") + // ripId := d.Get(ripIdName).(string) + // updateripoptions := &vpcv1.UpdateSubnetReservedIPOptions{ + // SubnetID: &subnetId, + // ID: &ripId, + // } + // reservedIpPath := &vpcv1.ReservedIPPatch{} + // if d.HasChange(primaryipNameName) { + // name := d.Get(primaryipNameName).(string) + // reservedIpPath.Name = &name + // } + // if d.HasChange(primaryipAutoDeleteName) { + // auto := d.Get(primaryipAutoDeleteName).(bool) + // reservedIpPath.AutoDelete = &auto + // } + // reservedIpPathAsPatch, err := reservedIpPath.AsPatch() + // if err != nil { + // return fmt.Errorf("[ERROR] Error calling reserved ip as patch on vni patch \n%s", err) + // } + // updateripoptions.ReservedIPPatch = reservedIpPathAsPatch + // _, response, err := sess.UpdateSubnetReservedIP(updateripoptions) + // if err != nil { + // return fmt.Errorf("[ERROR] Error updating vni reserved ip(%s): %s\n%s", ripId, err, response) + // } + // } + // if d.HasChange(sgName) { + // ovs, nvs := d.GetChange(sgName) + // ov := ovs.(*schema.Set) + // nv := nvs.(*schema.Set) + // remove := flex.ExpandStringList(ov.Difference(nv).List()) + // add := flex.ExpandStringList(nv.Difference(ov).List()) + // if len(add) > 0 { + // for i := range add { + // createsgnicoptions := &vpcv1.CreateSecurityGroupTargetBindingOptions{ + // SecurityGroupID: &add[i], + // ID: &vniId, + // } + // _, response, err := sess.CreateSecurityGroupTargetBinding(createsgnicoptions) + // if err != nil { + // return fmt.Errorf("[ERROR] Error while creating security group %q for virtual network interface %s\n%s: %q", add[i], vniId, err, response) + // } + // _, err = isWaitForVirtualNetworkInterfaceAvailable(sess, vniId, d.Timeout(schema.TimeoutUpdate)) + // if err != nil { + // return err + // } + // } + + // } + // if len(remove) > 0 { + // for i := range remove { + // deletesgnicoptions := &vpcv1.DeleteSecurityGroupTargetBindingOptions{ + // SecurityGroupID: &remove[i], + // ID: &vniId, + // } + // response, err := sess.DeleteSecurityGroupTargetBinding(deletesgnicoptions) + // if err != nil { + // return fmt.Errorf("[ERROR] Error while removing security group %q for virtual network interface %s\n%s: %q", remove[i], d.Id(), err, response) + // } + // _, err = isWaitForVirtualNetworkInterfaceAvailable(sess, vniId, d.Timeout(schema.TimeoutUpdate)) + // if err != nil { + // return err + // } + // } + // } + // } + + // } + + // } + // // } + // } + + } + + if d.HasChange(isBareMetalServerTags) || d.HasChange(isBareMetalServerAccessTags) { + bmscrn := d.Get(isBareMetalServerCRN).(string) + if bmscrn == "" { + options := &vpcv1.GetBareMetalServerOptions{ + ID: &id, + } + bms, response, err := sess.GetBareMetalServerWithContext(context, options) if err != nil { if response != nil && response.StatusCode == 404 { d.SetId("") @@ -2880,3 +3971,817 @@ func resourceIBMIsBareMetalServerBareMetalServerTrustedPlatformModulePrototypeTo } return modelMap, nil } + +func resourceIBMIsBareMetalServerBareMetalServerNetworkAttachmentReferenceToMap(model *vpcv1.BareMetalServerNetworkAttachmentReference, na vpcv1.BareMetalServerNetworkAttachmentIntf, instanceC *vpcv1.VpcV1) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Deleted != nil { + deletedMap, err := resourceIBMIsBareMetalServerBareMetalServerNetworkAttachmentReferenceDeletedToMap(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 + vniMap := make(map[string]interface{}) + vniid := "" + switch reflect.TypeOf(na).String() { + case "*vpcv1.BareMetalServerNetworkAttachmentByPci": + { + vna := na.(*vpcv1.BareMetalServerNetworkAttachmentByPci) + if vna.AllowedVlans != nil { + var out = make([]interface{}, len(vna.AllowedVlans)) + for i, v := range vna.AllowedVlans { + out[i] = int(v) + } + modelMap["allowed_vlans"] = schema.NewSet(schema.HashInt, out) + } + if vna.VirtualNetworkInterface != nil { + vniid = *vna.VirtualNetworkInterface.ID + vniMap["id"] = vniid + vniMap["name"] = vna.VirtualNetworkInterface.Name + vniMap["resource_type"] = vna.VirtualNetworkInterface.ResourceType + } + } + case "*vpcv1.BareMetalServerNetworkAttachmentByVlan": + { + vna := na.(*vpcv1.BareMetalServerNetworkAttachmentByVlan) + if vna.Vlan != nil { + modelMap["vlan"] = *vna.Vlan + } + if vna.AllowToFloat != nil { + modelMap["allow_to_float"] = *vna.AllowToFloat + } + if vna.VirtualNetworkInterface != nil { + vniid = *vna.VirtualNetworkInterface.ID + vniMap["id"] = vniid + vniMap["name"] = vna.VirtualNetworkInterface.Name + vniMap["resource_type"] = vna.VirtualNetworkInterface.ResourceType + } + } + default: + { + vna := na.(*vpcv1.BareMetalServerNetworkAttachment) + if vna.VirtualNetworkInterface != nil { + vniid = *vna.VirtualNetworkInterface.ID + vniMap["id"] = vniid + vniMap["name"] = vna.VirtualNetworkInterface.Name + vniMap["resource_type"] = vna.VirtualNetworkInterface.ResourceType + } + if vna.AllowedVlans != nil { + var out = make([]interface{}, len(vna.AllowedVlans)) + for i, v := range vna.AllowedVlans { + out[i] = int(v) + } + modelMap["allowed_vlans"] = schema.NewSet(schema.HashInt, out) + } + if vna.Vlan != nil { + modelMap["vlan"] = *vna.Vlan + } + if vna.AllowToFloat != nil { + modelMap["allow_to_float"] = *vna.AllowToFloat + } + + } + } + + getVirtualNetworkInterfaceOptions := &vpcv1.GetVirtualNetworkInterfaceOptions{ + ID: &vniid, + } + vniDetails, response, err := instanceC.GetVirtualNetworkInterface(getVirtualNetworkInterfaceOptions) + if err != nil { + return nil, fmt.Errorf("[ERROR] Error on GetInstanceNetworkAttachment in instance : %s\n%s", err, response) + } + vniMap["allow_ip_spoofing"] = vniDetails.AllowIPSpoofing + vniMap["auto_delete"] = vniDetails.AutoDelete + vniMap["enable_infrastructure_nat"] = vniDetails.EnableInfrastructureNat + vniMap["resource_group"] = vniDetails.ResourceGroup.ID + primaryipId := *vniDetails.PrimaryIP.ID + if !core.IsNil(vniDetails.Ips) { + ips := []map[string]interface{}{} + for _, ipsItem := range vniDetails.Ips { + if *ipsItem.ID != primaryipId { + ipsItemMap, err := resourceIBMIsVirtualNetworkInterfaceReservedIPReferenceToMap(&ipsItem, true) + if err != nil { + return nil, err + } + ips = append(ips, ipsItemMap) + } + } + vniMap["ips"] = ips + } + primaryIPMap, err := resourceIBMIsBareMetalServerReservedIPReferenceToMap(model.PrimaryIP) + if err != nil { + return modelMap, err + } + vniMap["primary_ip"] = []map[string]interface{}{primaryIPMap} + + if !core.IsNil(vniDetails.SecurityGroups) { + securityGroups := make([]string, 0) + for _, securityGroupsItem := range vniDetails.SecurityGroups { + if securityGroupsItem.ID != nil { + securityGroups = append(securityGroups, *securityGroupsItem.ID) + } + } + vniMap["security_groups"] = securityGroups + } + if model.ResourceType != nil { + modelMap["resource_type"] = *model.ResourceType + } + if model.Subnet != nil { + vniMap["subnet"] = *model.Subnet.ID + } + modelMap["virtual_network_interface"] = []map[string]interface{}{vniMap} + return modelMap, nil +} + +func resourceIBMIsBareMetalServerBareMetalServerNetworkAttachmentReferenceDeletedToMap(model *vpcv1.BareMetalServerNetworkAttachmentReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = model.MoreInfo + return modelMap, nil +} + +func resourceIBMIsBareMetalServerReservedIPReferenceToMap(model *vpcv1.ReservedIPReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["address"] = model.Address + if model.Deleted != nil { + deletedMap, err := resourceIBMIsBareMetalServerReservedIPReferenceDeletedToMap(model.Deleted) + if err != nil { + return modelMap, err + } + modelMap["deleted"] = []map[string]interface{}{deletedMap} + } + modelMap["href"] = model.Href + modelMap["reserved_ip"] = model.ID + modelMap["name"] = model.Name + modelMap["resource_type"] = model.ResourceType + return modelMap, nil +} + +func resourceIBMIsBareMetalServerReservedIPReferenceDeletedToMap(model *vpcv1.ReservedIPReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = model.MoreInfo + return modelMap, nil +} + +func resourceIBMIsBareMetalServerMapToBareMetalServerPrimaryNetworkAttachmentPrototype(allowipspoofing, autodelete, enablenat string, d *schema.ResourceData, modelMap map[string]interface{}) (*vpcv1.BareMetalServerPrimaryNetworkAttachmentPrototype, error) { + model := &vpcv1.BareMetalServerPrimaryNetworkAttachmentPrototype{} + interface_type := "pci" + if modelMap["allowed_vlans"] != nil && modelMap["allowed_vlans"].(*schema.Set).Len() > 0 { + allowedVlans := []int64{} + for _, allowedVlansItem := range modelMap["allowed_vlans"].(*schema.Set).List() { + allowedVlans = append(allowedVlans, int64(allowedVlansItem.(int))) + } + model.AllowedVlans = allowedVlans + interface_type = "pci" + } + if modelMap["interface_type"].(string) != "" { + interface_type = modelMap["interface_type"].(string) + } + model.InterfaceType = &interface_type + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + VirtualNetworkInterfaceModel, err := resourceIBMIsBareMetalServerMapToVirtualNetworkInterfacePrototypeAttachmentContext(allowipspoofing, autodelete, enablenat, d, modelMap["virtual_network_interface"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.VirtualNetworkInterface = VirtualNetworkInterfaceModel + return model, nil +} +func resourceIBMIsBareMetalServerMapToVirtualNetworkInterfaceIPsReservedIPPrototype(modelMap map[string]interface{}) (vpcv1.VirtualNetworkInterfaceIPPrototypeIntf, error) { + model := &vpcv1.VirtualNetworkInterfaceIPPrototype{} + 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 resourceIBMIsBareMetalServerMapToVirtualNetworkInterfacePrimaryIPReservedIPPrototype(modelMap map[string]interface{}) (vpcv1.VirtualNetworkInterfacePrimaryIPPrototypeIntf, error) { + model := &vpcv1.VirtualNetworkInterfacePrimaryIPPrototype{} + 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 resourceIBMIsBareMetalServerMapToVirtualNetworkInterfacePrototypeAttachmentContext(allowipspoofing, autodelete, enablenat string, d *schema.ResourceData, modelMap map[string]interface{}) (vpcv1.BareMetalServerNetworkAttachmentPrototypeVirtualNetworkInterfaceIntf, error) { + model := &vpcv1.BareMetalServerNetworkAttachmentPrototypeVirtualNetworkInterface{} + if _, ok := d.GetOkExists(allowipspoofing); ok && modelMap["allow_ip_spoofing"] != nil { + model.AllowIPSpoofing = core.BoolPtr(modelMap["allow_ip_spoofing"].(bool)) + } + if _, ok := d.GetOkExists(autodelete); ok && modelMap["auto_delete"] != nil { + model.AutoDelete = core.BoolPtr(modelMap["auto_delete"].(bool)) + } + if _, ok := d.GetOkExists(enablenat); ok && modelMap["enable_infrastructure_nat"] != nil { + model.EnableInfrastructureNat = core.BoolPtr(modelMap["enable_infrastructure_nat"].(bool)) + } + if modelMap["ips"] != nil && modelMap["ips"].(*schema.Set).Len() > 0 { + ips := []vpcv1.VirtualNetworkInterfaceIPPrototypeIntf{} + for _, ipsItem := range modelMap["ips"].(*schema.Set).List() { + ipsItemModel, err := resourceIBMIsBareMetalServerMapToVirtualNetworkInterfaceIPsReservedIPPrototype(ipsItem.(map[string]interface{})) + if err != nil { + return model, err + } + ips = append(ips, ipsItemModel) + } + model.Ips = ips + } + 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 := resourceIBMIsBareMetalServerMapToVirtualNetworkInterfacePrimaryIPReservedIPPrototype(modelMap["primary_ip"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.PrimaryIP = PrimaryIPModel + } + if modelMap["resource_group"] != nil && modelMap["resource_group"].(string) != "" { + resourceGroupId := modelMap["resource_group"].(string) + model.ResourceGroup = &vpcv1.ResourceGroupIdentity{ + ID: &resourceGroupId, + } + } + if modelMap["security_groups"] != nil { + securityGroups := []vpcv1.SecurityGroupIdentityIntf{} + sg := modelMap["security_groups"].(*schema.Set) + for _, v := range sg.List() { + value := v.(string) + securityGroupsItem := &vpcv1.SecurityGroupIdentity{ + ID: &value, + } + securityGroups = append(securityGroups, securityGroupsItem) + } + model.SecurityGroups = securityGroups + } + if modelMap["subnet"] != nil && modelMap["subnet"].(string) != "" { + subnetId := modelMap["subnet"].(string) + model.Subnet = &vpcv1.SubnetIdentity{ + ID: &subnetId, + } + } + 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["crn"] != nil && modelMap["crn"].(string) != "" { + model.CRN = core.StringPtr(modelMap["crn"].(string)) + } + return model, nil +} +func resourceIBMIsBareMetalServerMapToSubnetIdentity(modelMap map[string]interface{}) (vpcv1.SubnetIdentityIntf, error) { + model := &vpcv1.SubnetIdentity{} + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + if modelMap["crn"] != nil && modelMap["crn"].(string) != "" { + model.CRN = core.StringPtr(modelMap["crn"].(string)) + } + if modelMap["href"] != nil && modelMap["href"].(string) != "" { + model.Href = core.StringPtr(modelMap["href"].(string)) + } + return model, nil +} +func resourceIBMIsBareMetalServerMapToSecurityGroupIdentity(modelMap map[string]interface{}) (vpcv1.SecurityGroupIdentityIntf, error) { + model := &vpcv1.SecurityGroupIdentity{} + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + if modelMap["crn"] != nil && modelMap["crn"].(string) != "" { + model.CRN = core.StringPtr(modelMap["crn"].(string)) + } + if modelMap["href"] != nil && modelMap["href"].(string) != "" { + model.Href = core.StringPtr(modelMap["href"].(string)) + } + return model, nil +} + +func resourceIBMIsBareMetalServerMapToBareMetalServerNetworkAttachmentPrototype(allowipspoofing, allowfloat, autodelete, enablenat string, d *schema.ResourceData, modelMap map[string]interface{}) (vpcv1.BareMetalServerNetworkAttachmentPrototypeIntf, error) { + if modelMap["vlan"] != nil && int64(modelMap["vlan"].(int)) != 0 { + return resourceIBMIsBareMetalServerMapToBareMetalServerNetworkAttachmentPrototypeBareMetalServerNetworkAttachmentByVlanPrototype(allowipspoofing, allowfloat, autodelete, enablenat, d, modelMap) + } else { + return resourceIBMIsBareMetalServerMapToBareMetalServerNetworkAttachmentPrototypeBareMetalServerNetworkAttachmentByPciPrototype(allowipspoofing, autodelete, enablenat, d, modelMap) + } +} + +func resourceIBMIsBareMetalServerMapToBareMetalServerNetworkAttachmentPrototypeBareMetalServerNetworkAttachmentByVlanPrototype(allowipspoofing, allowfloat, autodelete, enablenat string, d *schema.ResourceData, modelMap map[string]interface{}) (*vpcv1.BareMetalServerNetworkAttachmentPrototypeBareMetalServerNetworkAttachmentByVlanPrototype, error) { + model := &vpcv1.BareMetalServerNetworkAttachmentPrototypeBareMetalServerNetworkAttachmentByVlanPrototype{} + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + VirtualNetworkInterfaceModel, err := resourceIBMIsBareMetalServerMapToVirtualNetworkInterfacePrototypeAttachmentContext(allowipspoofing, autodelete, enablenat, d, modelMap["virtual_network_interface"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + + model.VirtualNetworkInterface = VirtualNetworkInterfaceModel + if _, ok := d.GetOkExists(allowfloat); ok && modelMap["allow_to_float"] != nil { + model.AllowToFloat = core.BoolPtr(modelMap["allow_to_float"].(bool)) + } + model.InterfaceType = core.StringPtr("vlan") + model.Vlan = core.Int64Ptr(int64(modelMap["vlan"].(int))) + return model, nil +} + +func resourceIBMIsBareMetalServerMapToBareMetalServerNetworkAttachmentPrototypeBareMetalServerNetworkAttachmentByPciPrototype(allowipspoofing, autodelete, enablenat string, d *schema.ResourceData, modelMap map[string]interface{}) (*vpcv1.BareMetalServerNetworkAttachmentPrototypeBareMetalServerNetworkAttachmentByPciPrototype, error) { + model := &vpcv1.BareMetalServerNetworkAttachmentPrototypeBareMetalServerNetworkAttachmentByPciPrototype{} + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + VirtualNetworkInterfaceModel, err := resourceIBMIsBareMetalServerMapToVirtualNetworkInterfacePrototypeAttachmentContext(allowipspoofing, autodelete, enablenat, d, modelMap["virtual_network_interface"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.VirtualNetworkInterface = VirtualNetworkInterfaceModel + if modelMap["allowed_vlans"] != nil { + allowedVlans := []int64{} + for _, allowedVlansItem := range modelMap["allowed_vlans"].(*schema.Set).List() { + allowedVlans = append(allowedVlans, int64(allowedVlansItem.(int))) + } + model.AllowedVlans = allowedVlans + } + model.InterfaceType = core.StringPtr("pci") + return model, nil +} + +func findNetworkAttachmentDifferences(oldList, newList []interface{}, bareMetalServerId string, sess *vpcv1.VpcV1, d *schema.ResourceData) ([]vpcv1.DeleteBareMetalServerNetworkAttachmentOptions, []vpcv1.CreateBareMetalServerNetworkAttachmentOptions, bool, error) { + var wg sync.WaitGroup + wg.Add(3) + + var listToDelete []vpcv1.DeleteBareMetalServerNetworkAttachmentOptions + var listToAdd []vpcv1.CreateBareMetalServerNetworkAttachmentOptions + var err error + var serverRestartNeeded bool + + go func() { + listToDelete, serverRestartNeeded = compareRemovedNacs(oldList, newList, bareMetalServerId) + wg.Done() + }() + + go func() { + listToAdd, serverRestartNeeded = compareAddedNacs(oldList, newList, bareMetalServerId) + wg.Done() + }() + + go func() { + err = compareModifiedNacs(oldList, newList, bareMetalServerId, sess, d) + wg.Done() + }() + + wg.Wait() + return listToDelete, listToAdd, serverRestartNeeded, err +} +func compareRemovedNacs(oldList, newList []interface{}, bareMetalServerId string) ([]vpcv1.DeleteBareMetalServerNetworkAttachmentOptions, bool) { + var removed []vpcv1.DeleteBareMetalServerNetworkAttachmentOptions + newListMap := make(map[string]struct{}) + restartNeeded := false + for _, newListitem := range newList { + newListitemMap := newListitem.(map[string]interface{}) + // list of ids in new list + if newListitemMap["id"] != nil && newListitemMap["id"].(string) != "" { + newListMap[newListitemMap["id"].(string)] = struct{}{} + } + } + // find the ids missing in the oldList, difference are the ones to be removed + for _, oldListitem1 := range oldList { + oldListitemMap := oldListitem1.(map[string]interface{}) + if _, exists := newListMap[oldListitemMap["id"].(string)]; !exists { + deleteNac := &vpcv1.DeleteBareMetalServerNetworkAttachmentOptions{ + BareMetalServerID: &bareMetalServerId, + ID: core.StringPtr(oldListitemMap["id"].(string)), + } + if oldListitemMap["interface_type"].(string) == "pci" { + restartNeeded = true + } + removed = append(removed, *deleteNac) + } + } + return removed, restartNeeded +} + +func compareAddedNacs(oldList, newList []interface{}, bareMetalServerId string) ([]vpcv1.CreateBareMetalServerNetworkAttachmentOptions, bool) { + var added []vpcv1.CreateBareMetalServerNetworkAttachmentOptions + + restartNeeded := false + // the nac(s) which dont have the id are to be created + for _, newListitem := range newList { + newListitemmMap := newListitem.(map[string]interface{}) + // if _, exists := oldListMap[newListitemmMap["name"].(string)]; !exists { + if (newListitemmMap["id"] == nil) || (newListitemmMap["id"] != nil && newListitemmMap["id"].(string) == "") { + addNac := &vpcv1.CreateBareMetalServerNetworkAttachmentOptions{ + BareMetalServerID: &bareMetalServerId, + } + if newListitemmMap["vlan"] != nil && newListitemmMap["vlan"].(int) != 0 { + vlanId := int64(newListitemmMap["vlan"].(int)) + interfaceType := "vlan" + nacAttPrototype := &vpcv1.BareMetalServerNetworkAttachmentPrototypeBareMetalServerNetworkAttachmentByVlanPrototype{ + Vlan: core.Int64Ptr(vlanId), + InterfaceType: &interfaceType, + } + name := newListitemmMap["name"].(string) + if name != "" { + nacAttPrototype.Name = &name + } + if newListitemmMap["virtual_network_interface"] != nil { + newListItemVniMap := newListitemmMap["virtual_network_interface"].([]interface{})[0].(map[string]interface{}) + virtualNetworkInterface := &vpcv1.BareMetalServerNetworkAttachmentPrototypeVirtualNetworkInterface{} + if newListItemVniMap["allow_ip_spoofing"] != nil { + virtualNetworkInterface.AllowIPSpoofing = core.BoolPtr(newListItemVniMap["allow_ip_spoofing"].(bool)) + } + if newListItemVniMap["auto_delete"] != nil { + virtualNetworkInterface.AutoDelete = core.BoolPtr(newListItemVniMap["auto_delete"].(bool)) + } + if newListItemVniMap["enable_infrastructure_nat"] != nil { + virtualNetworkInterface.EnableInfrastructureNat = core.BoolPtr(newListItemVniMap["enable_infrastructure_nat"].(bool)) + } + if newListItemVniMap["ips"] != nil && newListItemVniMap["ips"].(*schema.Set).Len() > 0 { + ips := []vpcv1.VirtualNetworkInterfaceIPPrototypeIntf{} + for _, ipsItem := range newListItemVniMap["ips"].(*schema.Set).List() { + ipsItemModelMap := ipsItem.(map[string]interface{}) + idIntf := ipsItemModelMap["id"] + if idIntf != nil && idIntf.(string) != "" { + ipsItemModel := &vpcv1.VirtualNetworkInterfaceIPPrototype{ + ID: core.StringPtr(idIntf.(string)), + } + ips = append(ips, ipsItemModel) + } + } + virtualNetworkInterface.Ips = ips + } + if newListItemVniMap["name"] != nil && newListItemVniMap["name"].(string) != "" { + virtualNetworkInterface.Name = core.StringPtr(newListItemVniMap["name"].(string)) + } + if newListItemVniMap["primary_ip"] != nil && len(newListItemVniMap["primary_ip"].([]interface{})) > 0 { + primaryIPMapModel := newListItemVniMap["primary_ip"].([]interface{})[0].(map[string]interface{}) + primaryIPModel := &vpcv1.VirtualNetworkInterfacePrimaryIPPrototype{} + if primaryIPMapModel["id"] != nil && primaryIPMapModel["id"].(string) != "" { + primaryIPModel.ID = core.StringPtr(primaryIPMapModel["id"].(string)) + } + if primaryIPMapModel["href"] != nil && primaryIPMapModel["href"].(string) != "" { + primaryIPModel.Href = core.StringPtr(primaryIPMapModel["href"].(string)) + } + if primaryIPMapModel["address"] != nil && primaryIPMapModel["address"].(string) != "" { + primaryIPModel.Address = core.StringPtr(primaryIPMapModel["address"].(string)) + } + if primaryIPMapModel["auto_delete"] != nil { + primaryIPModel.AutoDelete = core.BoolPtr(primaryIPMapModel["auto_delete"].(bool)) + } + if primaryIPMapModel["name"] != nil && primaryIPMapModel["name"].(string) != "" { + primaryIPModel.Name = core.StringPtr(primaryIPMapModel["name"].(string)) + } + virtualNetworkInterface.PrimaryIP = primaryIPModel + } + if newListItemVniMap["resource_group"] != nil && newListItemVniMap["resource_group"].(string) != "" { + + virtualNetworkInterface.ResourceGroup = &vpcv1.ResourceGroupIdentity{ + ID: core.StringPtr(newListItemVniMap["resource_group"].(string)), + } + } + if newListItemVniMap["security_groups"] != nil && newListItemVniMap["security_groups"].(*schema.Set).Len() > 0 { + securityGroups := []vpcv1.SecurityGroupIdentityIntf{} + for _, securityGroupsItem := range newListItemVniMap["security_groups"].(*schema.Set).List() { + securityGroupsItemModel := &vpcv1.SecurityGroupIdentity{ + ID: core.StringPtr(securityGroupsItem.(string)), + } + securityGroups = append(securityGroups, securityGroupsItemModel) + } + virtualNetworkInterface.SecurityGroups = securityGroups + } + if newListItemVniMap["subnet"] != nil && newListItemVniMap["subnet"].(string) != "" { + virtualNetworkInterface.Subnet = &vpcv1.SubnetIdentity{ + ID: core.StringPtr(newListItemVniMap["subnet"].(string)), + } + } + if newListItemVniMap["id"] != nil && newListItemVniMap["id"].(string) != "" { + virtualNetworkInterface.ID = core.StringPtr(newListItemVniMap["id"].(string)) + } + nacAttPrototype.VirtualNetworkInterface = virtualNetworkInterface + } + addNac.BareMetalServerNetworkAttachmentPrototype = nacAttPrototype + } else { + restartNeeded = true + name := newListitemmMap["name"].(string) + interfaceType := "pci" + nacAttPrototype := &vpcv1.BareMetalServerNetworkAttachmentPrototypeBareMetalServerNetworkAttachmentByPciPrototype{ + InterfaceType: &interfaceType, + } + if name != "" { + nacAttPrototype.Name = &name + } + if newListitemmMap["virtual_network_interface"] != nil { + newListVniitemmMap := newListitemmMap["virtual_network_interface"].([]interface{})[0].(map[string]interface{}) + virtualNetworkInterface := &vpcv1.BareMetalServerNetworkAttachmentPrototypeVirtualNetworkInterface{} + if newListVniitemmMap["allow_ip_spoofing"] != nil { + virtualNetworkInterface.AllowIPSpoofing = core.BoolPtr(newListVniitemmMap["allow_ip_spoofing"].(bool)) + } + if newListVniitemmMap["auto_delete"] != nil { + virtualNetworkInterface.AutoDelete = core.BoolPtr(newListVniitemmMap["auto_delete"].(bool)) + } + if newListVniitemmMap["enable_infrastructure_nat"] != nil { + virtualNetworkInterface.EnableInfrastructureNat = core.BoolPtr(newListVniitemmMap["enable_infrastructure_nat"].(bool)) + } + if newListVniitemmMap["ips"] != nil && newListVniitemmMap["ips"].(*schema.Set).Len() > 0 { + ips := []vpcv1.VirtualNetworkInterfaceIPPrototypeIntf{} + for _, ipsItem := range newListVniitemmMap["ips"].(*schema.Set).List() { + ipsItemModelMap := ipsItem.(map[string]interface{}) + idIntf := ipsItemModelMap["id"] + if idIntf != nil && idIntf.(string) != "" { + ipsItemModel := &vpcv1.VirtualNetworkInterfaceIPPrototype{ + ID: core.StringPtr(idIntf.(string)), + } + ips = append(ips, ipsItemModel) + } + } + virtualNetworkInterface.Ips = ips + } + if newListVniitemmMap["name"] != nil && newListVniitemmMap["name"].(string) != "" { + virtualNetworkInterface.Name = core.StringPtr(newListVniitemmMap["name"].(string)) + } + if newListVniitemmMap["primary_ip"] != nil && len(newListVniitemmMap["primary_ip"].([]interface{})) > 0 { + primaryIPMapModel := newListVniitemmMap["primary_ip"].([]interface{})[0].(map[string]interface{}) + primaryIPModel := &vpcv1.VirtualNetworkInterfacePrimaryIPPrototype{} + if primaryIPMapModel["id"] != nil && primaryIPMapModel["id"].(string) != "" { + primaryIPModel.ID = core.StringPtr(primaryIPMapModel["id"].(string)) + } + if primaryIPMapModel["href"] != nil && primaryIPMapModel["href"].(string) != "" { + primaryIPModel.Href = core.StringPtr(primaryIPMapModel["href"].(string)) + } + if primaryIPMapModel["address"] != nil && primaryIPMapModel["address"].(string) != "" { + primaryIPModel.Address = core.StringPtr(primaryIPMapModel["address"].(string)) + } + if primaryIPMapModel["auto_delete"] != nil { + primaryIPModel.AutoDelete = core.BoolPtr(primaryIPMapModel["auto_delete"].(bool)) + } + if primaryIPMapModel["name"] != nil && primaryIPMapModel["name"].(string) != "" { + primaryIPModel.Name = core.StringPtr(primaryIPMapModel["name"].(string)) + } + virtualNetworkInterface.PrimaryIP = primaryIPModel + } + if newListVniitemmMap["resource_group"] != nil && newListVniitemmMap["resource_group"].(string) != "" { + + virtualNetworkInterface.ResourceGroup = &vpcv1.ResourceGroupIdentity{ + ID: core.StringPtr(newListVniitemmMap["resource_group"].(string)), + } + } + if newListVniitemmMap["security_groups"] != nil && newListVniitemmMap["security_groups"].(*schema.Set).Len() > 0 { + securityGroups := []vpcv1.SecurityGroupIdentityIntf{} + for _, securityGroupsItem := range newListVniitemmMap["security_groups"].(*schema.Set).List() { + securityGroupsItemModel := &vpcv1.SecurityGroupIdentity{ + ID: core.StringPtr(securityGroupsItem.(string)), + } + securityGroups = append(securityGroups, securityGroupsItemModel) + } + virtualNetworkInterface.SecurityGroups = securityGroups + } + if newListVniitemmMap["subnet"] != nil && newListVniitemmMap["subnet"].(string) != "" { + virtualNetworkInterface.Subnet = &vpcv1.SubnetIdentity{ + ID: core.StringPtr(newListVniitemmMap["subnet"].(string)), + } + } + if newListVniitemmMap["id"] != nil && newListVniitemmMap["id"].(string) != "" { + virtualNetworkInterface.ID = core.StringPtr(newListVniitemmMap["id"].(string)) + } + nacAttPrototype.VirtualNetworkInterface = virtualNetworkInterface + } + allowedVlansIntf := newListitemmMap["allowed_vlans"] + if allowedVlansIntf != nil && allowedVlansIntf.(*schema.Set).Len() > 0 { + allowedVlans := []int64{} + for _, allowedVlansItem := range allowedVlansIntf.(*schema.Set).List() { + allowedVlans = append(allowedVlans, int64(allowedVlansItem.(int))) + } + nacAttPrototype.AllowedVlans = allowedVlans + } + addNac.BareMetalServerNetworkAttachmentPrototype = nacAttPrototype + } + added = append(added, *addNac) + } + } + + return added, restartNeeded +} + +func compareModifiedNacs(oldList, newList []interface{}, bareMetalServerId string, sess *vpcv1.VpcV1, d *schema.ResourceData) error { + list2Map := make(map[string]interface{}) + + for _, newListitem := range newList { + newListitemMap := newListitem.(map[string]interface{}) + if newListitemMap["id"] != nil && newListitemMap["id"] != "" { + list2Map[newListitemMap["id"].(string)] = newListitem + } + } + + for _, oldListitem1 := range oldList { + oldListitemMap := oldListitem1.(map[string]interface{}) + if oldListitemMap["id"] != nil { + if oldListitem2, exists := list2Map[oldListitemMap["id"].(string)]; exists { + s1 := oldListitem1.(map[string]interface{}) + s2 := oldListitem2.(map[string]interface{}) + id := s1["id"].(string) + modilfiedNac := &vpcv1.UpdateBareMetalServerNetworkAttachmentOptions{ + BareMetalServerID: &bareMetalServerId, + ID: &id, + } + s1AllowedVlan := s1["allowed_vlans"] + s2AllowedVlan := s2["allowed_vlans"] + s1Name := s1["name"] + s2Name := s2["name"] + s1Vni := s1["virtual_network_interface"] + s2Vni := s2["virtual_network_interface"] + bmsNacPatchModel := &vpcv1.BareMetalServerNetworkAttachmentPatch{} + hasChanged := false + if s1AllowedVlan != nil && s2AllowedVlan != nil { + if !s1AllowedVlan.(*schema.Set).Equal(s2AllowedVlan.(*schema.Set)) { + hasChanged = true + allowedVlansList := s2AllowedVlan.(*schema.Set).List() + allowedVlans := make([]int64, 0, len(allowedVlansList)) + for _, k := range allowedVlansList { + allowedVlans = append(allowedVlans, int64(k.(int))) + } + bmsNacPatchModel.AllowedVlans = allowedVlans + } + } + if s1Name != nil && s2Name != nil { + if s1Name.(string) != s2Name.(string) { + hasChanged = true + bmsNacPatchModel.Name = core.StringPtr(s2Name.(string)) + } + } + if hasChanged { + bmsNacPatch, _ := bmsNacPatchModel.AsPatch() + modilfiedNac.BareMetalServerNetworkAttachmentPatch = bmsNacPatch + _, res, err := sess.UpdateBareMetalServerNetworkAttachment(modilfiedNac) + if err != nil { + return fmt.Errorf("%s/n%v", err, res) + } + } + if s1Vni != nil && s2Vni != nil { + s1VniMap := s1Vni.([]interface{})[0].(map[string]interface{}) + s2VniMap := s2Vni.([]interface{})[0].(map[string]interface{}) + vniId := s1VniMap["id"].(string) + s1vniMapAIS := s1VniMap["allow_ip_spoofing"] + s1vniMapAD := s1VniMap["auto_delete"] + s1vniMapEIN := s1VniMap["enable_infrastructure_nat"] + s1vniMapIPS := s1VniMap["ips"] + s1vniMapName := s1VniMap["name"] + s1vniMapSG := s1VniMap["security_groups"] + s2vniMapAIS := s2VniMap["allow_ip_spoofing"] + s2vniMapAD := s2VniMap["auto_delete"] + s2vniMapEIN := s2VniMap["enable_infrastructure_nat"] + s2vniMapIPS := s2VniMap["ips"] + s2vniMapName := s2VniMap["name"] + s2vniMapSG := s2VniMap["security_groups"] + vniUpdateOptions := &vpcv1.UpdateVirtualNetworkInterfaceOptions{ + ID: &vniId, + } + hasChanged := false + vniPatch := &vpcv1.VirtualNetworkInterfacePatch{} + if s1vniMapAIS != nil && s2vniMapAIS != nil && s1vniMapAIS.(bool) != s2vniMapAIS.(bool) { + vniPatch.AllowIPSpoofing = core.BoolPtr(s2vniMapAIS.(bool)) + hasChanged = true + } + if s1vniMapAD != nil && s2vniMapAD != nil && s1vniMapAD.(bool) != s2vniMapAD.(bool) { + vniPatch.AutoDelete = core.BoolPtr(s2vniMapAD.(bool)) + hasChanged = true + } + if s1vniMapEIN != nil && s2vniMapEIN != nil && s1vniMapEIN.(bool) != s2vniMapEIN.(bool) { + vniPatch.EnableInfrastructureNat = core.BoolPtr(s2vniMapEIN.(bool)) + hasChanged = true + } + if s1vniMapName != nil && s2vniMapName != nil && s1vniMapName.(string) != s2vniMapName.(string) { + vniPatch.Name = core.StringPtr(s2vniMapName.(string)) + hasChanged = true + } + if hasChanged { + _, res, err := sess.UpdateVirtualNetworkInterface(vniUpdateOptions) + if err != nil { + return fmt.Errorf("%s/n%v", err, res) + } + } + if s1vniMapIPS != nil && s2vniMapIPS != nil && !s1vniMapIPS.(*schema.Set).Equal(s2vniMapIPS.(*schema.Set)) { + + os := s1vniMapIPS.(*schema.Set) + ns := s2vniMapIPS.(*schema.Set) + var oldset, newset *schema.Set + + var out = make([]interface{}, ns.Len(), ns.Len()) + for i, nA := range ns.List() { + newPack := nA.(map[string]interface{}) + out[i] = newPack["reserved_ip"].(string) + } + newset = schema.NewSet(schema.HashString, out) + + out = make([]interface{}, os.Len(), os.Len()) + for i, oA := range os.List() { + oldPack := oA.(map[string]interface{}) + out[i] = oldPack["reserved_ip"].(string) + } + oldset = schema.NewSet(schema.HashString, out) + + remove := flex.ExpandStringList(oldset.Difference(newset).List()) + add := flex.ExpandStringList(newset.Difference(oldset).List()) + + if add != nil && len(add) > 0 { + for _, ipItem := range add { + if ipItem != "" { + + addVirtualNetworkInterfaceIPOptions := &vpcv1.AddVirtualNetworkInterfaceIPOptions{} + addVirtualNetworkInterfaceIPOptions.SetVirtualNetworkInterfaceID(vniId) + addVirtualNetworkInterfaceIPOptions.SetID(ipItem) + _, response, err := sess.AddVirtualNetworkInterfaceIP(addVirtualNetworkInterfaceIPOptions) + if err != nil { + log.Printf("[DEBUG] AddVirtualNetworkInterfaceIP failed in VirtualNetworkInterface patch during BareMetalServer nac patch %s\n%s", err, response) + return fmt.Errorf("AddVirtualNetworkInterfaceIP failed in VirtualNetworkInterface patch during BareMetalServer nac patch %s\n%s", err, response) + } + } + } + } + if remove != nil && len(remove) > 0 { + for _, ipItem := range remove { + if ipItem != "" { + + removeVirtualNetworkInterfaceIPOptions := &vpcv1.RemoveVirtualNetworkInterfaceIPOptions{} + removeVirtualNetworkInterfaceIPOptions.SetVirtualNetworkInterfaceID(vniId) + removeVirtualNetworkInterfaceIPOptions.SetID(ipItem) + response, err := sess.RemoveVirtualNetworkInterfaceIP(removeVirtualNetworkInterfaceIPOptions) + if err != nil { + log.Printf("[DEBUG] RemoveVirtualNetworkInterfaceIP failed in VirtualNetworkInterface patch during BareMetalServer nac patch %s\n%s", err, response) + return fmt.Errorf("RemoveVirtualNetworkInterfaceIP failed in VirtualNetworkInterface patch during BareMetalServer nac patch %s\n%s", err, response) + } + } + } + } + + } + if s1vniMapSG != nil && s2vniMapSG != nil && !s1vniMapSG.(*schema.Set).Equal(s2vniMapSG.(*schema.Set)) { + + ov := s1vniMapSG.(*schema.Set) + nv := s2vniMapSG.(*schema.Set) + remove := flex.ExpandStringList(ov.Difference(nv).List()) + add := flex.ExpandStringList(nv.Difference(ov).List()) + if len(add) > 0 { + for i := range add { + createsgnicoptions := &vpcv1.CreateSecurityGroupTargetBindingOptions{ + SecurityGroupID: &add[i], + ID: &vniId, + } + _, response, err := sess.CreateSecurityGroupTargetBinding(createsgnicoptions) + if err != nil { + return (fmt.Errorf("[ERROR] Error while creating security group %q for virtual network interface %s\n%s: %q", add[i], d.Id(), err, response)) + } + _, err = isWaitForVirtualNetworkInterfaceAvailable(sess, vniId, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return (err) + } + } + + } + if len(remove) > 0 { + for i := range remove { + deletesgnicoptions := &vpcv1.DeleteSecurityGroupTargetBindingOptions{ + SecurityGroupID: &remove[i], + ID: &vniId, + } + response, err := sess.DeleteSecurityGroupTargetBinding(deletesgnicoptions) + if err != nil { + return (fmt.Errorf("[ERROR] Error while removing security group %q for virtual network interface %s\n%s: %q", remove[i], d.Id(), err, response)) + } + _, err = isWaitForVirtualNetworkInterfaceAvailable(sess, vniId, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return (err) + } + } + } + + } + } + } + } + } + return nil +} diff --git a/ibm/service/vpc/resource_ibm_is_bare_metal_server_network_attachment.go b/ibm/service/vpc/resource_ibm_is_bare_metal_server_network_attachment.go new file mode 100644 index 0000000000..93c4309274 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_bare_metal_server_network_attachment.go @@ -0,0 +1,1230 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "regexp" + "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/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 ResourceIBMIsBareMetalServerNetworkAttachment() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMIsBareMetalServerNetworkAttachmentCreate, + ReadContext: resourceIBMIsBareMetalServerNetworkAttachmentRead, + UpdateContext: resourceIBMIsBareMetalServerNetworkAttachmentUpdate, + DeleteContext: resourceIBMIsBareMetalServerNetworkAttachmentDelete, + Importer: &schema.ResourceImporter{}, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Update: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + Schema: map[string]*schema.Schema{ + "bare_metal_server": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_is_bare_metal_server_network_attachment", "bare_metal_server"), + Description: "The bare metal server identifier.", + }, + "floating_bare_metal_server": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The bare metal server identifier of the server where the attachment is floated to(only applicated for allow_to_float true).", + }, + + "network_attachment": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The network attachment's id.", + }, + "virtual_network_interface_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The virtual_network_interface's id.", + }, + "interface_type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_bare_metal_server_network_attachment", "interface_type"), + Description: "The network attachment's interface type:- `pci`: a physical PCI device which can only be created or deleted when the bare metal server is stopped - Has an `allowed_vlans` property which controls the VLANs that will be permitted to use the PCI attachment - Cannot directly use an IEEE 802.1q VLAN tag.- `vlan`: a virtual device, used through a `pci` device that has the `vlan` in its array of `allowed_vlans`. - Must use an IEEE 802.1q tag.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_bare_metal_server_network_attachment", "name"), + Description: "The name for this bare metal server network attachment. The name is unique across all network attachments for the bare metal server.", + }, + "virtual_network_interface": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Computed: true, + Description: "A virtual network interface for the bare metal server network attachment. This can be specified using an existing virtual network interface, or a prototype object for a new virtual network interface.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + Description: "The virtual network interface id for this bare metal server network attachment.", + }, + "allow_ip_spoofing": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + ConflictsWith: []string{"virtual_network_interface.0.id"}, + Computed: true, + Description: "Indicates whether source IP spoofing is allowed on this interface. If `false`, source IP spoofing is prevented on this interface. If `true`, source IP spoofing is allowed on this interface.", + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + ConflictsWith: []string{"virtual_network_interface.0.id"}, + Description: "Indicates whether this virtual network interface will be automatically deleted when`target` is deleted.", + }, + "enable_infrastructure_nat": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + ConflictsWith: []string{"virtual_network_interface.0.id"}, + 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 network interface, allowing the workload to perform any needed NAT operations.- `allow_ip_spoofing` must be `false`.- If the virtual network interface is attached: - The target `resource_type` must be `bare_metal_server_network_attachment`. - The target `interface_type` must not be `hipersocket`.", + }, + "ips": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Computed: true, + Set: hashIpsList, + ConflictsWith: []string{"virtual_network_interface.0.id"}, + Description: "The reserved IPs bound to this virtual network interface.May be empty when `lifecycle_state` is `pending`.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + // Optional: true, + Computed: true, + Description: "The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "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.", + }, + }, + }, + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + // Optional: true, + Computed: true, + Description: "Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP.", + }, + "reserved_ip": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + // Optional: true, + Computed: true, + Description: "The name for this reserved IP. The name is unique across all reserved IPs in a subnet.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ConflictsWith: []string{"virtual_network_interface.0.id"}, + ValidateFunc: validate.InvokeValidator("ibm_is_virtual_network_interface", "vni_name"), + Description: "The name for this virtual network interface. The name is unique across all virtual network interfaces in the VPC.", + }, + "primary_ip": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Computed: true, + ConflictsWith: []string{"virtual_network_interface.0.id"}, + Description: "The primary IP address of the virtual network interface for the bare metal server networkattachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "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 reserved IP.", + }, + "reserved_ip": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The name for this reserved IP. The name is unique across all reserved IPs in a subnet.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "resource_group": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"virtual_network_interface.0.id"}, + Computed: true, + Description: "The resource group id for this virtual network interface.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "security_groups": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + ConflictsWith: []string{"virtual_network_interface.0.id"}, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "The security groups for this virtual network interface.", + }, + "subnet": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ConflictsWith: []string{"virtual_network_interface.0.id"}, + Description: "The associated subnet id.", + }, + }, + }, + }, + "allowed_vlans": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + ConflictsWith: []string{"vlan"}, + Set: schema.HashInt, + Description: "Indicates what VLAN IDs (for VLAN type only) can use this physical (PCI type) attachment.", + Elem: &schema.Schema{Type: schema.TypeInt}, + }, + "allow_to_float": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + ConflictsWith: []string{"allowed_vlans"}, + Description: "Indicates if the bare metal server network attachment can automatically float to any other server within the same `resource_group`. The bare metal server network attachment will float automatically if the network detects a GARP or RARP on another bare metal server in the resource group. Applies only to bare metal server network attachments with `vlan` interface type.", + }, + "vlan": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + ConflictsWith: []string{"allowed_vlans"}, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_bare_metal_server_network_attachment", "vlan"), + Description: "Indicates the 802.1Q VLAN ID tag that must be used for all traffic on this attachment.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the bare metal server network attachment was created.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this bare metal server network attachment.", + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the bare metal server network attachment.", + }, + "port_speed": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The port speed for this bare metal server network attachment in Mbps.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The bare metal server network attachment type.", + }, + isBareMetalServerHardStop: { + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: "Only used for PCI network attachments, whether to hard/immediately stop server", + }, + }, + } +} + +func ResourceIBMIsBareMetalServerNetworkAttachmentValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "bare_metal_server", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[-0-9a-z_]+$`, + MinValueLength: 1, + MaxValueLength: 64, + }, + validate.ValidateSchema{ + Identifier: "interface_type", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "pci, vlan", + }, + 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, + }, + validate.ValidateSchema{ + Identifier: "vlan", + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, + Optional: true, + MinValue: "1", + MaxValue: "4094", + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_bare_metal_server_network_attachment", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMIsBareMetalServerNetworkAttachmentCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + rebootNeeded := true + rebooted := false + bodyModelMap := map[string]interface{}{} + createBareMetalServerNetworkAttachmentOptions := &vpcv1.CreateBareMetalServerNetworkAttachmentOptions{} + + bodyModelMap["interface_type"] = d.Get("interface_type") + if _, ok := d.GetOk("name"); ok { + bodyModelMap["name"] = d.Get("name") + } + bodyModelMap["virtual_network_interface"] = d.Get("virtual_network_interface") + _, bodyModelMap["allow_ip_spoofing_exists"] = d.GetOkExists("virtual_network_interface.0.allow_ip_spoofing") + _, bodyModelMap["auto_delete_exists"] = d.GetOkExists("virtual_network_interface.0.auto_delete") + _, bodyModelMap["enable_infrastructure_nat_exists"] = d.GetOkExists("virtual_network_interface.0.enable_infrastructure_nat") + if _, ok := d.GetOk("allow_to_float"); ok { + bodyModelMap["allow_to_float"] = d.Get("allow_to_float") + } + if _, ok := d.GetOk("vlan"); ok { + bodyModelMap["vlan"] = d.Get("vlan") + if int64(d.Get("vlan").(int)) != 0 { + rebootNeeded = false + } + } + if _, ok := d.GetOk("allowed_vlans"); ok { + bodyModelMap["allowed_vlans"] = d.Get("allowed_vlans") + } + bareMetalServerId := d.Get("bare_metal_server").(string) + createBareMetalServerNetworkAttachmentOptions.SetBareMetalServerID(bareMetalServerId) + convertedModel, err := resourceIBMIsBareMetalServerNetworkAttachmentMapToBareMetalServerNetworkAttachmentPrototype(bodyModelMap) + if err != nil { + return diag.FromErr(err) + } + if rebootNeeded { + getbmsoptions := &vpcv1.GetBareMetalServerOptions{ + ID: &bareMetalServerId, + } + + bms, response, err := vpcClient.GetBareMetalServerWithContext(context, getbmsoptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error fetching bare metal server (%s) during network attachment create err %s\n%s", bareMetalServerId, err, response)) + } + // failed, pending, restarting, running, starting, stopped, stopping, maintenance + if *bms.Status == "failed" { + return diag.FromErr(fmt.Errorf("[ERROR] Error cannot attach network attachment to a failed bare metal server")) + } else if *bms.Status == "running" && rebootNeeded { + log.Printf("[DEBUG] Stopping bare metal server (%s) to create a PCI network attachment", bareMetalServerId) + stopType := "hard" + if _, ok := d.GetOk(isBareMetalServerHardStop); ok && !d.Get(isBareMetalServerHardStop).(bool) { + stopType = "soft" + } + createstopaction := &vpcv1.StopBareMetalServerOptions{ + ID: &bareMetalServerId, + Type: &stopType, + } + res, err := vpcClient.StopBareMetalServerWithContext(context, createstopaction) + if err != nil || res.StatusCode != 204 { + return diag.FromErr(fmt.Errorf("[ERROR] Error stopping bare metal server (%s) during network attachment create err %s\n%s", bareMetalServerId, err, response)) + } + _, err = isWaitForBareMetalServerStoppedForNIC(vpcClient, bareMetalServerId, d.Timeout(schema.TimeoutCreate), d) + if err != nil { + return diag.FromErr(err) + } + rebooted = true + } else if *bms.Status != "stopped" { + return diag.FromErr(fmt.Errorf("[ERROR] Error bare metal server in %s state, please try after some time", *bms.Status)) + } + } + createBareMetalServerNetworkAttachmentOptions.BareMetalServerNetworkAttachmentPrototype = convertedModel + + bareMetalServerNetworkAttachmentIntf, response, err := vpcClient.CreateBareMetalServerNetworkAttachmentWithContext(context, createBareMetalServerNetworkAttachmentOptions) + if err != nil { + log.Printf("[DEBUG] CreateBareMetalServerNetworkAttachmentWithContext failed %s\n%s", err, response) + if rebooted { + createstartaction := &vpcv1.StartBareMetalServerOptions{ + ID: &bareMetalServerId, + } + res, err := vpcClient.StartBareMetalServerWithContext(context, createstartaction) + if err != nil || res.StatusCode != 204 { + return diag.FromErr(fmt.Errorf("[ERROR] Error starting bare metal server (%s) after attachment creation failed err %s\n%s", bareMetalServerId, err, response)) + } + _, err = isWaitForBareMetalServerAvailableForNIC(vpcClient, bareMetalServerId, d.Timeout(schema.TimeoutCreate), d) + if err != nil { + return diag.FromErr(err) + } + } + return diag.FromErr(fmt.Errorf("CreateBareMetalServerNetworkAttachmentWithContext failed %s\n%s", err, response)) + } + + if _, ok := bareMetalServerNetworkAttachmentIntf.(*vpcv1.BareMetalServerNetworkAttachmentByVlan); ok { + bareMetalServerNetworkAttachment := bareMetalServerNetworkAttachmentIntf.(*vpcv1.BareMetalServerNetworkAttachmentByVlan) + if bareMetalServerNetworkAttachment.VirtualNetworkInterface != nil && bareMetalServerNetworkAttachment.VirtualNetworkInterface.ID != nil { + d.Set("virtual_network_interface_id", *bareMetalServerNetworkAttachment.VirtualNetworkInterface.ID) + } + d.SetId(fmt.Sprintf("%s/%s", *createBareMetalServerNetworkAttachmentOptions.BareMetalServerID, *bareMetalServerNetworkAttachment.ID)) + d.Set("floating_bare_metal_server", *createBareMetalServerNetworkAttachmentOptions.BareMetalServerID) + } else if _, ok := bareMetalServerNetworkAttachmentIntf.(*vpcv1.BareMetalServerNetworkAttachmentByPci); ok { + bareMetalServerNetworkAttachment := bareMetalServerNetworkAttachmentIntf.(*vpcv1.BareMetalServerNetworkAttachmentByPci) + if bareMetalServerNetworkAttachment.VirtualNetworkInterface != nil && bareMetalServerNetworkAttachment.VirtualNetworkInterface.ID != nil { + d.Set("virtual_network_interface_id", *bareMetalServerNetworkAttachment.VirtualNetworkInterface.ID) + } + d.SetId(fmt.Sprintf("%s/%s", *createBareMetalServerNetworkAttachmentOptions.BareMetalServerID, *bareMetalServerNetworkAttachment.ID)) + d.Set("floating_bare_metal_server", *createBareMetalServerNetworkAttachmentOptions.BareMetalServerID) + } else if _, ok := bareMetalServerNetworkAttachmentIntf.(*vpcv1.BareMetalServerNetworkAttachment); ok { + bareMetalServerNetworkAttachment := bareMetalServerNetworkAttachmentIntf.(*vpcv1.BareMetalServerNetworkAttachment) + if bareMetalServerNetworkAttachment.VirtualNetworkInterface != nil && bareMetalServerNetworkAttachment.VirtualNetworkInterface.ID != nil { + d.Set("virtual_network_interface_id", *bareMetalServerNetworkAttachment.VirtualNetworkInterface.ID) + } + d.SetId(fmt.Sprintf("%s/%s", *createBareMetalServerNetworkAttachmentOptions.BareMetalServerID, *bareMetalServerNetworkAttachment.ID)) + d.Set("floating_bare_metal_server", *createBareMetalServerNetworkAttachmentOptions.BareMetalServerID) + } else { + return diag.FromErr(fmt.Errorf("Unrecognized vpcv1.BareMetalServerNetworkAttachmentIntf subtype encountered")) + } + + if rebooted { + createstartaction := &vpcv1.StartBareMetalServerOptions{ + ID: &bareMetalServerId, + } + res, err := vpcClient.StartBareMetalServerWithContext(context, createstartaction) + if err != nil || res.StatusCode != 204 { + return diag.FromErr(fmt.Errorf("[ERROR] Error starting bare metal server (%s) after attachment creation err %s\n%s", bareMetalServerId, err, response)) + } + _, err = isWaitForBareMetalServerAvailableForNIC(vpcClient, bareMetalServerId, d.Timeout(schema.TimeoutCreate), d) + if err != nil { + return diag.FromErr(err) + } + } + + return resourceIBMIsBareMetalServerNetworkAttachmentRead(context, d, meta) +} + +func resourceIBMIsBareMetalServerNetworkAttachmentRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + getBareMetalServerNetworkAttachmentOptions := &vpcv1.GetBareMetalServerNetworkAttachmentOptions{} + bmId := "" + nacId := "" + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + bmId = parts[0] + nacId = parts[1] + getBareMetalServerNetworkAttachmentOptions.SetBareMetalServerID(bmId) + getBareMetalServerNetworkAttachmentOptions.SetID(nacId) + bareMetalServerNetworkAttachmentIntf, response, err := vpcClient.GetBareMetalServerNetworkAttachmentWithContext(context, getBareMetalServerNetworkAttachmentOptions) + if err != nil { + + if response != nil && response.StatusCode == 404 { + + allowToFloatIntf := d.Get("allow_to_float") + if allowToFloatIntf != nil && allowToFloatIntf.(bool) { + + vniid := d.Get("virtual_network_interface.0.id").(string) + getVirtualNetworkInterfaceOptions := &vpcv1.GetVirtualNetworkInterfaceOptions{ + ID: &vniid, + } + vniDetails, response, err := vpcClient.GetVirtualNetworkInterface(getVirtualNetworkInterfaceOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return diag.FromErr(fmt.Errorf("[ERROR] Error on GetVirtualNetworkInterface in BareMetalServer : %s\n%s", err, response)) + } + + vniTargetIntf := vniDetails.Target + + if _, ok := vniTargetIntf.(*vpcv1.VirtualNetworkInterfaceTargetShareMountTargetReference); ok { + vniTarget := vniTargetIntf.(*vpcv1.VirtualNetworkInterfaceTargetShareMountTargetReference) + ree := regexp.MustCompile(`([^/]+)/network_attachments/([^/]+)`) + + // Find the matches + matches := ree.FindStringSubmatch(*vniTarget.Href) + if len(matches) >= 3 { + bmId = (matches[1]) + nacId = matches[2] + } + + } else if _, ok := vniTargetIntf.(*vpcv1.VirtualNetworkInterfaceTargetInstanceNetworkAttachmentReferenceVirtualNetworkInterfaceContext); ok { + vniTarget := vniTargetIntf.(*vpcv1.VirtualNetworkInterfaceTargetInstanceNetworkAttachmentReferenceVirtualNetworkInterfaceContext) + ree := regexp.MustCompile(`([^/]+)/network_attachments/([^/]+)`) + + // Find the matches + matches := ree.FindStringSubmatch(*vniTarget.Href) + if len(matches) >= 3 { + bmId = (matches[1]) + nacId = matches[2] + } + + } else if _, ok := vniTargetIntf.(*vpcv1.VirtualNetworkInterfaceTargetBareMetalServerNetworkAttachmentReferenceVirtualNetworkInterfaceContext); ok { + vniTarget := vniTargetIntf.(*vpcv1.VirtualNetworkInterfaceTargetBareMetalServerNetworkAttachmentReferenceVirtualNetworkInterfaceContext) + ree := regexp.MustCompile(`([^/]+)/network_attachments/([^/]+)`) + + // Find the matches + matches := ree.FindStringSubmatch(*vniTarget.Href) + if len(matches) >= 3 { + bmId = (matches[1]) + nacId = matches[2] + } + + } else if _, ok := vniTargetIntf.(*vpcv1.VirtualNetworkInterfaceTarget); ok { + vniTarget := vniTargetIntf.(*vpcv1.VirtualNetworkInterfaceTarget) + ree := regexp.MustCompile(`([^/]+)/network_attachments/([^/]+)`) + + // Find the matches + matches := ree.FindStringSubmatch(*vniTarget.Href) + if len(matches) >= 3 { + bmId = (matches[1]) + nacId = matches[2] + } + + } + + getBareMetalServerNetworkAttachmentOptions.SetBareMetalServerID(bmId) + getBareMetalServerNetworkAttachmentOptions.SetID(nacId) + + bareMetalServerNetworkAttachmentIntf, response, err = vpcClient.GetBareMetalServerNetworkAttachmentWithContext(context, getBareMetalServerNetworkAttachmentOptions) + if err != nil { + + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + } + } + + log.Printf("[DEBUG] GetBareMetalServerNetworkAttachmentWithContext failed %s\n%s", err, response) + // return diag.FromErr(fmt.Errorf("GetBareMetalServerNetworkAttachmentWithContext failed %s\n%s", err, response)) + } else { + log.Printf("[DEBUG] GetBareMetalServerNetworkAttachmentWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetBareMetalServerNetworkAttachmentWithContext failed %s\n%s", err, response)) + } + } + + if _, ok := bareMetalServerNetworkAttachmentIntf.(*vpcv1.BareMetalServerNetworkAttachmentByVlan); ok { + bareMetalServerNetworkAttachment := bareMetalServerNetworkAttachmentIntf.(*vpcv1.BareMetalServerNetworkAttachmentByVlan) + d.SetId(fmt.Sprintf("%s/%s", bmId, *bareMetalServerNetworkAttachment.ID)) + if err = d.Set("interface_type", bareMetalServerNetworkAttachment.InterfaceType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting interface_type: %s", err)) + } + if !core.IsNil(bareMetalServerNetworkAttachment.Name) { + if err = d.Set("name", bareMetalServerNetworkAttachment.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + } + virtualNetworkInterfaceMap, err := resourceIBMIsBareMetalServerNetworkAttachmentVirtualNetworkInterfaceReferenceAttachmentContextToMap(bareMetalServerNetworkAttachment.VirtualNetworkInterface, vpcClient) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("virtual_network_interface", []map[string]interface{}{virtualNetworkInterfaceMap}); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting virtual_network_interface: %s", err)) + } + if !core.IsNil(bareMetalServerNetworkAttachment.AllowToFloat) { + if err = d.Set("allow_to_float", bareMetalServerNetworkAttachment.AllowToFloat); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting allow_to_float: %s", err)) + } + } + if !core.IsNil(bareMetalServerNetworkAttachment.Vlan) { + if err = d.Set("vlan", flex.IntValue(bareMetalServerNetworkAttachment.Vlan)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting vlan: %s", err)) + } + } + if err = d.Set("created_at", flex.DateTimeToString(bareMetalServerNetworkAttachment.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + if err = d.Set("href", bareMetalServerNetworkAttachment.Href); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting href: %s", err)) + } + if err = d.Set("lifecycle_state", bareMetalServerNetworkAttachment.LifecycleState); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting lifecycle_state: %s", err)) + } + if err = d.Set("port_speed", flex.IntValue(bareMetalServerNetworkAttachment.PortSpeed)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting port_speed: %s", err)) + } + if err = d.Set("resource_type", bareMetalServerNetworkAttachment.ResourceType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_type: %s", err)) + } + if err = d.Set("type", bareMetalServerNetworkAttachment.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) + } + } else if _, ok := bareMetalServerNetworkAttachmentIntf.(*vpcv1.BareMetalServerNetworkAttachmentByPci); ok { + bareMetalServerNetworkAttachment := bareMetalServerNetworkAttachmentIntf.(*vpcv1.BareMetalServerNetworkAttachmentByPci) + if err = d.Set("interface_type", bareMetalServerNetworkAttachment.InterfaceType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting interface_type: %s", err)) + } + if !core.IsNil(bareMetalServerNetworkAttachment.Name) { + if err = d.Set("name", bareMetalServerNetworkAttachment.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + } + virtualNetworkInterfaceMap, err := resourceIBMIsBareMetalServerNetworkAttachmentVirtualNetworkInterfaceReferenceAttachmentContextToMap(bareMetalServerNetworkAttachment.VirtualNetworkInterface, vpcClient) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("virtual_network_interface", []map[string]interface{}{virtualNetworkInterfaceMap}); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting virtual_network_interface: %s", err)) + } + if !core.IsNil(bareMetalServerNetworkAttachment.AllowedVlans) { + allowedVlans := []interface{}{} + for _, allowedVlansItem := range bareMetalServerNetworkAttachment.AllowedVlans { + allowedVlans = append(allowedVlans, int64(allowedVlansItem)) + } + if err = d.Set("allowed_vlans", allowedVlans); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting allowed_vlans: %s", err)) + } + } + if err = d.Set("created_at", flex.DateTimeToString(bareMetalServerNetworkAttachment.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + if err = d.Set("href", bareMetalServerNetworkAttachment.Href); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting href: %s", err)) + } + if err = d.Set("lifecycle_state", bareMetalServerNetworkAttachment.LifecycleState); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting lifecycle_state: %s", err)) + } + if err = d.Set("port_speed", flex.IntValue(bareMetalServerNetworkAttachment.PortSpeed)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting port_speed: %s", err)) + } + if err = d.Set("resource_type", bareMetalServerNetworkAttachment.ResourceType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_type: %s", err)) + } + + if err = d.Set("type", bareMetalServerNetworkAttachment.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) + } + d.SetId(fmt.Sprintf("%s/%s", bmId, *bareMetalServerNetworkAttachment.ID)) + } else if _, ok := bareMetalServerNetworkAttachmentIntf.(*vpcv1.BareMetalServerNetworkAttachment); ok { + bareMetalServerNetworkAttachment := bareMetalServerNetworkAttachmentIntf.(*vpcv1.BareMetalServerNetworkAttachment) + d.SetId(fmt.Sprintf("%s/%s", bmId, *bareMetalServerNetworkAttachment.ID)) + + // parent class argument: bare_metal_server string + if err = d.Set("floating_bare_metal_server", getBareMetalServerNetworkAttachmentOptions.BareMetalServerID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting bare_metal_server: %s", err)) + } + // parent class argument: interface_type string + // parent class argument: name string + // parent class argument: virtual_network_interface VirtualNetworkInterfaceReferenceAttachmentContext + // parent class argument: allowed_vlans []int64 + // parent class argument: allow_to_float bool + // parent class argument: vlan int64 + if err = d.Set("interface_type", bareMetalServerNetworkAttachment.InterfaceType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting interface_type: %s", err)) + } + if !core.IsNil(bareMetalServerNetworkAttachment.Name) { + if err = d.Set("name", bareMetalServerNetworkAttachment.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + } + virtualNetworkInterfaceMap, err := resourceIBMIsBareMetalServerNetworkAttachmentVirtualNetworkInterfaceReferenceAttachmentContextToMap(bareMetalServerNetworkAttachment.VirtualNetworkInterface, vpcClient) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("virtual_network_interface", []map[string]interface{}{virtualNetworkInterfaceMap}); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting virtual_network_interface: %s", err)) + } + if !core.IsNil(bareMetalServerNetworkAttachment.AllowedVlans) { + allowedVlans := []interface{}{} + for _, allowedVlansItem := range bareMetalServerNetworkAttachment.AllowedVlans { + allowedVlans = append(allowedVlans, int64(allowedVlansItem)) + } + if err = d.Set("allowed_vlans", allowedVlans); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting allowed_vlans: %s", err)) + } + } + if !core.IsNil(bareMetalServerNetworkAttachment.AllowToFloat) { + if err = d.Set("allow_to_float", bareMetalServerNetworkAttachment.AllowToFloat); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting allow_to_float: %s", err)) + } + } + if !core.IsNil(bareMetalServerNetworkAttachment.Vlan) { + if err = d.Set("vlan", flex.IntValue(bareMetalServerNetworkAttachment.Vlan)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting vlan: %s", err)) + } + } + if err = d.Set("created_at", flex.DateTimeToString(bareMetalServerNetworkAttachment.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + if err = d.Set("href", bareMetalServerNetworkAttachment.Href); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting href: %s", err)) + } + if err = d.Set("lifecycle_state", bareMetalServerNetworkAttachment.LifecycleState); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting lifecycle_state: %s", err)) + } + if err = d.Set("port_speed", flex.IntValue(bareMetalServerNetworkAttachment.PortSpeed)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting port_speed: %s", err)) + } + if err = d.Set("resource_type", bareMetalServerNetworkAttachment.ResourceType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_type: %s", err)) + } + if err = d.Set("type", bareMetalServerNetworkAttachment.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) + } + if err = d.Set("network_attachment", bareMetalServerNetworkAttachment.ID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting network_attachment: %s", err)) + } + } else { + return diag.FromErr(fmt.Errorf("Unrecognized vpcv1.BareMetalServerNetworkAttachmentIntf subtype encountered")) + } + + return nil +} + +func resourceIBMIsBareMetalServerNetworkAttachmentUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + updateBareMetalServerNetworkAttachmentOptions := &vpcv1.UpdateBareMetalServerNetworkAttachmentOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + updateBareMetalServerNetworkAttachmentOptions.SetBareMetalServerID(parts[0]) + updateBareMetalServerNetworkAttachmentOptions.SetID(parts[1]) + + hasChange := false + + patchVals := &vpcv1.BareMetalServerNetworkAttachmentPatch{} + if d.HasChange("bare_metal_server") { + return diag.FromErr(fmt.Errorf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "bare_metal_server")) + } + if d.HasChange("allowed_vlans") { + var allowedVlans []int64 + for _, v := range d.Get("allowed_vlans").(*schema.Set).List() { + allowedVlansItem := int64(v.(int)) + allowedVlans = append(allowedVlans, allowedVlansItem) + } + patchVals.AllowedVlans = allowedVlans + hasChange = true + } + if d.HasChange("name") { + newName := d.Get("name").(string) + patchVals.Name = &newName + hasChange = true + } + + if hasChange { + updateBareMetalServerNetworkAttachmentOptions.BareMetalServerNetworkAttachmentPatch, _ = patchVals.AsPatch() + _, response, err := vpcClient.UpdateBareMetalServerNetworkAttachmentWithContext(context, updateBareMetalServerNetworkAttachmentOptions) + if err != nil { + log.Printf("[DEBUG] UpdateBareMetalServerNetworkAttachmentWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateBareMetalServerNetworkAttachmentWithContext failed %s\n%s", err, response)) + } + } + + if d.HasChange("virtual_network_interface") && !d.IsNewResource() { + vniId := d.Get("virtual_network_interface.0.id").(string) + updateVirtualNetworkInterfaceOptions := &vpcv1.UpdateVirtualNetworkInterfaceOptions{ + ID: &vniId, + } + virtualNetworkInterfacePatch := &vpcv1.VirtualNetworkInterfacePatch{} + if d.HasChange("virtual_network_interface.0.auto_delete") { + autodelete := d.Get("virtual_network_interface.0.auto_delete").(bool) + virtualNetworkInterfacePatch.AutoDelete = &autodelete + } + if d.HasChange("virtual_network_interface.0.name") { + name := d.Get("virtual_network_interface.0.name").(string) + virtualNetworkInterfacePatch.Name = &name + } + if d.HasChange("virtual_network_interface.0.enable_infrastructure_nat") { + enableNat := d.Get("virtual_network_interface.0.enable_infrastructure_nat").(bool) + virtualNetworkInterfacePatch.EnableInfrastructureNat = &enableNat + } + if d.HasChange("virtual_network_interface.0.allow_ip_spoofing") { + allIpSpoofing := d.Get("virtual_network_interface.0.allow_ip_spoofing").(bool) + virtualNetworkInterfacePatch.AllowIPSpoofing = &allIpSpoofing + } + virtualNetworkInterfacePatchAsPatch, err := virtualNetworkInterfacePatch.AsPatch() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error encountered while apply as patch for virtualNetworkInterfacePatch of BareMetalServer(%s) vni (%s) %s", d.Id(), vniId, err)) + } + updateVirtualNetworkInterfaceOptions.VirtualNetworkInterfacePatch = virtualNetworkInterfacePatchAsPatch + _, response, err := vpcClient.UpdateVirtualNetworkInterfaceWithContext(context, updateVirtualNetworkInterfaceOptions) + if err != nil { + log.Printf("[DEBUG] UpdateVirtualNetworkInterfaceWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateVirtualNetworkInterfaceWithContext failed during BareMetalServer(%s) network attachment patch %s\n%s", d.Id(), err, response)) + } + + if d.HasChange("virtual_network_interface.0.ips") { + oldips, newips := d.GetChange("virtual_network_interface.0.ips") + os := oldips.(*schema.Set) + ns := newips.(*schema.Set) + var oldset, newset *schema.Set + + var out = make([]interface{}, ns.Len(), ns.Len()) + for i, nA := range ns.List() { + newPack := nA.(map[string]interface{}) + out[i] = newPack["reserved_ip"].(string) + } + newset = schema.NewSet(schema.HashString, out) + + out = make([]interface{}, os.Len(), os.Len()) + for i, oA := range os.List() { + oldPack := oA.(map[string]interface{}) + out[i] = oldPack["reserved_ip"].(string) + } + oldset = schema.NewSet(schema.HashString, out) + + remove := flex.ExpandStringList(oldset.Difference(newset).List()) + add := flex.ExpandStringList(newset.Difference(oldset).List()) + + if add != nil && len(add) > 0 { + for _, ipItem := range add { + if ipItem != "" { + + addVirtualNetworkInterfaceIPOptions := &vpcv1.AddVirtualNetworkInterfaceIPOptions{} + addVirtualNetworkInterfaceIPOptions.SetVirtualNetworkInterfaceID(vniId) + addVirtualNetworkInterfaceIPOptions.SetID(ipItem) + _, response, err := vpcClient.AddVirtualNetworkInterfaceIPWithContext(context, addVirtualNetworkInterfaceIPOptions) + if err != nil { + log.Printf("[DEBUG] AddVirtualNetworkInterfaceIPWithContext failed in VirtualNetworkInterface patch during BareMetalServer nac patch %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("AddVirtualNetworkInterfaceIPWithContext failed in VirtualNetworkInterface patch during BareMetalServer nac patch %s\n%s", err, response)) + } + } + } + } + if remove != nil && len(remove) > 0 { + for _, ipItem := range remove { + if ipItem != "" { + + removeVirtualNetworkInterfaceIPOptions := &vpcv1.RemoveVirtualNetworkInterfaceIPOptions{} + removeVirtualNetworkInterfaceIPOptions.SetVirtualNetworkInterfaceID(vniId) + removeVirtualNetworkInterfaceIPOptions.SetID(ipItem) + response, err := vpcClient.RemoveVirtualNetworkInterfaceIPWithContext(context, removeVirtualNetworkInterfaceIPOptions) + if err != nil { + log.Printf("[DEBUG] RemoveVirtualNetworkInterfaceIPWithContext failed in VirtualNetworkInterface patch during BareMetalServer nac patch %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("RemoveVirtualNetworkInterfaceIPWithContext failed in VirtualNetworkInterface patch during BareMetalServer nac patch %s\n%s", err, response)) + } + } + } + } + + } + if d.HasChange("virtual_network_interface.0.primary_ip") { + subnetId := d.Get("virtual_network_interface.0.subnet").(string) + ripId := d.Get("virtual_network_interface.0.primary_ip.0.reserved_ip").(string) + updateripoptions := &vpcv1.UpdateSubnetReservedIPOptions{ + SubnetID: &subnetId, + ID: &ripId, + } + reservedIpPath := &vpcv1.ReservedIPPatch{} + if d.HasChange("virtual_network_interface.0.primary_ip.0.name") { + name := d.Get("virtual_network_interface.0.primary_ip.0.name").(string) + reservedIpPath.Name = &name + } + if d.HasChange("virtual_network_interface.0.primary_ip.0.auto_delete") { + auto := d.Get("virtual_network_interface.0.primary_ip.0.auto_delete").(bool) + reservedIpPath.AutoDelete = &auto + } + reservedIpPathAsPatch, err := reservedIpPath.AsPatch() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error calling reserved ip as patch on vni patch \n%s", err)) + } + updateripoptions.ReservedIPPatch = reservedIpPathAsPatch + _, response, err := vpcClient.UpdateSubnetReservedIP(updateripoptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating vni reserved ip(%s): %s\n%s", ripId, err, response)) + } + } + if d.HasChange("virtual_network_interface.0.security_groups") { + ovs, nvs := d.GetChange("virtual_network_interface.0.security_groups") + ov := ovs.(*schema.Set) + nv := nvs.(*schema.Set) + remove := flex.ExpandStringList(ov.Difference(nv).List()) + add := flex.ExpandStringList(nv.Difference(ov).List()) + if len(add) > 0 { + for i := range add { + createsgnicoptions := &vpcv1.CreateSecurityGroupTargetBindingOptions{ + SecurityGroupID: &add[i], + ID: &vniId, + } + _, response, err := vpcClient.CreateSecurityGroupTargetBinding(createsgnicoptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error while creating security group %q for virtual network interface %s\n%s: %q", add[i], d.Id(), err, response)) + } + _, err = isWaitForVirtualNetworkInterfaceAvailable(vpcClient, vniId, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return diag.FromErr(err) + } + } + + } + if len(remove) > 0 { + for i := range remove { + deletesgnicoptions := &vpcv1.DeleteSecurityGroupTargetBindingOptions{ + SecurityGroupID: &remove[i], + ID: &vniId, + } + response, err := vpcClient.DeleteSecurityGroupTargetBinding(deletesgnicoptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error while removing security group %q for virtual network interface %s\n%s: %q", remove[i], d.Id(), err, response)) + } + _, err = isWaitForVirtualNetworkInterfaceAvailable(vpcClient, vniId, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return diag.FromErr(err) + } + } + } + } + + } + + return resourceIBMIsBareMetalServerNetworkAttachmentRead(context, d, meta) +} + +func resourceIBMIsBareMetalServerNetworkAttachmentDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + ifServerStopped := false + interfaceType := d.Get("interface_type").(string) + bareMetalServerId := d.Get("floating_bare_metal_server").(string) + if interfaceType == "pci" { + getbmsoptions := &vpcv1.GetBareMetalServerOptions{ + ID: &bareMetalServerId, + } + + bms, response, err := vpcClient.GetBareMetalServerWithContext(context, getbmsoptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error fetching bare metal server (%s) during network attachment create err %s\n%s", bareMetalServerId, err, response)) + } + // failed, pending, restarting, running, starting, stopped, stopping, maintenance + if *bms.Status == "failed" { + return diag.FromErr(fmt.Errorf("[ERROR] Error cannot attach network attachment to a failed bare metal server")) + } else if *bms.Status == "running" { + log.Printf("[DEBUG] Stopping bare metal server (%s) to create a PCI network attachment", bareMetalServerId) + stopType := "hard" + if _, ok := d.GetOk(isBareMetalServerHardStop); ok && !d.Get(isBareMetalServerHardStop).(bool) { + stopType = "soft" + } + createstopaction := &vpcv1.StopBareMetalServerOptions{ + ID: &bareMetalServerId, + Type: &stopType, + } + res, err := vpcClient.StopBareMetalServerWithContext(context, createstopaction) + ifServerStopped = true + if err != nil || res.StatusCode != 204 { + return diag.FromErr(fmt.Errorf("[ERROR] Error stopping bare metal server (%s) during network attachment create err %s\n%s", bareMetalServerId, err, response)) + } + _, err = isWaitForBareMetalServerStoppedForNIC(vpcClient, bareMetalServerId, d.Timeout(schema.TimeoutCreate), d) + if err != nil { + return diag.FromErr(err) + } + } else if *bms.Status != "stopped" { + return diag.FromErr(fmt.Errorf("[ERROR] Error bare metal server in %s state, please try after some time", *bms.Status)) + } + } + deleteBareMetalServerNetworkAttachmentOptions := &vpcv1.DeleteBareMetalServerNetworkAttachmentOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteBareMetalServerNetworkAttachmentOptions.SetBareMetalServerID(parts[0]) + deleteBareMetalServerNetworkAttachmentOptions.SetID(parts[1]) + + response, err := vpcClient.DeleteBareMetalServerNetworkAttachmentWithContext(context, deleteBareMetalServerNetworkAttachmentOptions) + if err != nil { + log.Printf("[DEBUG] DeleteBareMetalServerNetworkAttachmentWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteBareMetalServerNetworkAttachmentWithContext failed %s\n%s", err, response)) + } + if ifServerStopped { + createstartaction := &vpcv1.StartBareMetalServerOptions{ + ID: &bareMetalServerId, + } + res, err := vpcClient.StartBareMetalServerWithContext(context, createstartaction) + if err != nil || res.StatusCode != 204 { + return diag.FromErr(fmt.Errorf("[ERROR] Error starting bare metal server (%s) after attachment creation err %s\n%s", bareMetalServerId, err, response)) + } + _, err = isWaitForBareMetalServerAvailableForNIC(vpcClient, bareMetalServerId, d.Timeout(schema.TimeoutCreate), d) + if err != nil { + return diag.FromErr(err) + } + } + + d.SetId("") + + return nil +} + +func resourceIBMIsBareMetalServerNetworkAttachmentMapToBareMetalServerNetworkAttachmentPrototypeVirtualNetworkInterface(modelMap map[string]interface{}, allow_ip_spoofing_exists, auto_delete_exists, enable_infrastructure_nat_exists interface{}) (vpcv1.BareMetalServerNetworkAttachmentPrototypeVirtualNetworkInterfaceIntf, error) { + model := &vpcv1.BareMetalServerNetworkAttachmentPrototypeVirtualNetworkInterface{} + if allow_ip_spoofing_exists.(bool) && modelMap["allow_ip_spoofing"] != nil { + model.AllowIPSpoofing = core.BoolPtr(modelMap["allow_ip_spoofing"].(bool)) + } + if auto_delete_exists.(bool) && modelMap["auto_delete"] != nil { + model.AutoDelete = core.BoolPtr(modelMap["auto_delete"].(bool)) + } + if enable_infrastructure_nat_exists.(bool) && modelMap["enable_infrastructure_nat"] != nil { + model.EnableInfrastructureNat = core.BoolPtr(modelMap["enable_infrastructure_nat"].(bool)) + } + if modelMap["ips"] != nil && modelMap["ips"].(*schema.Set).Len() > 0 { + ips := []vpcv1.VirtualNetworkInterfaceIPPrototypeIntf{} + for _, ipsItem := range modelMap["ips"].(*schema.Set).List() { + ipsItemModel, err := resourceIBMIsBareMetalServerNetworkAttachmentMapToVirtualNetworkInterfaceIPPrototype(ipsItem.(map[string]interface{})) + if err != nil { + return model, err + } + ips = append(ips, ipsItemModel) + } + model.Ips = ips + } + 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 := resourceIBMIsBareMetalServerNetworkAttachmentMapToVirtualNetworkInterfacePrimaryIPPrototype(modelMap["primary_ip"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.PrimaryIP = PrimaryIPModel + } + if modelMap["resource_group"] != nil && modelMap["resource_group"].(string) != "" { + + model.ResourceGroup = &vpcv1.ResourceGroupIdentity{ + ID: core.StringPtr(modelMap["resource_group"].(string)), + } + } + if modelMap["security_groups"] != nil && modelMap["security_groups"].(*schema.Set).Len() > 0 { + securityGroups := []vpcv1.SecurityGroupIdentityIntf{} + for _, securityGroupsItem := range modelMap["security_groups"].(*schema.Set).List() { + securityGroupsItemModel := &vpcv1.SecurityGroupIdentity{ + ID: core.StringPtr(securityGroupsItem.(string)), + } + securityGroups = append(securityGroups, securityGroupsItemModel) + } + model.SecurityGroups = securityGroups + } + if modelMap["subnet"] != nil && modelMap["subnet"].(string) != "" { + model.Subnet = &vpcv1.SubnetIdentity{ + ID: core.StringPtr(modelMap["subnet"].(string)), + } + } + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + return model, nil +} + +func resourceIBMIsBareMetalServerNetworkAttachmentMapToVirtualNetworkInterfaceIPPrototype(modelMap map[string]interface{}) (vpcv1.VirtualNetworkInterfaceIPPrototypeIntf, error) { + model := &vpcv1.VirtualNetworkInterfaceIPPrototype{} + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + return model, nil +} + +func resourceIBMIsBareMetalServerNetworkAttachmentMapToVirtualNetworkInterfacePrimaryIPPrototype(modelMap map[string]interface{}) (vpcv1.VirtualNetworkInterfacePrimaryIPPrototypeIntf, error) { + model := &vpcv1.VirtualNetworkInterfacePrimaryIPPrototype{} + 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 resourceIBMIsBareMetalServerNetworkAttachmentMapToBareMetalServerNetworkAttachmentPrototype(modelMap map[string]interface{}) (vpcv1.BareMetalServerNetworkAttachmentPrototypeIntf, error) { + model := &vpcv1.BareMetalServerNetworkAttachmentPrototype{} + if modelMap["vlan"] != nil && int64(modelMap["vlan"].(int)) != 0 { + model.InterfaceType = core.StringPtr("vlan") + } else { + model.InterfaceType = core.StringPtr("pci") + } + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + VirtualNetworkInterfaceModel, err := resourceIBMIsBareMetalServerNetworkAttachmentMapToBareMetalServerNetworkAttachmentPrototypeVirtualNetworkInterface(modelMap["virtual_network_interface"].([]interface{})[0].(map[string]interface{}), modelMap["allow_ip_spoofing_exists"], modelMap["auto_delete_exists"], modelMap["enable_infrastructure_nat_exists"]) + if err != nil { + return model, err + } + model.VirtualNetworkInterface = VirtualNetworkInterfaceModel + if modelMap["allowed_vlans"] != nil { + allowedVlans := []int64{} + for _, allowedVlansItem := range modelMap["allowed_vlans"].(*schema.Set).List() { + allowedVlans = append(allowedVlans, int64(allowedVlansItem.(int))) + } + model.AllowedVlans = allowedVlans + } + if modelMap["allow_to_float"] != nil { + model.AllowToFloat = core.BoolPtr(modelMap["allow_to_float"].(bool)) + } + if modelMap["vlan"] != nil { + model.Vlan = core.Int64Ptr(int64(modelMap["vlan"].(int))) + } + return model, nil +} + +func resourceIBMIsBareMetalServerNetworkAttachmentVirtualNetworkInterfaceReferenceAttachmentContextToMap(model *vpcv1.VirtualNetworkInterfaceReferenceAttachmentContext, sess *vpcv1.VpcV1) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + vniid := *model.ID + getVirtualNetworkInterfaceOptions := &vpcv1.GetVirtualNetworkInterfaceOptions{ + ID: &vniid, + } + vniDetails, response, err := sess.GetVirtualNetworkInterface(getVirtualNetworkInterfaceOptions) + if err != nil { + return nil, fmt.Errorf("[ERROR] Error on GetBareMetalServerNetworkAttachment in BareMetalServer : %s\n%s", err, response) + } + modelMap["allow_ip_spoofing"] = vniDetails.AllowIPSpoofing + modelMap["auto_delete"] = vniDetails.AutoDelete + modelMap["enable_infrastructure_nat"] = vniDetails.EnableInfrastructureNat + modelMap["resource_group"] = vniDetails.ResourceGroup.ID + primaryipId := *vniDetails.PrimaryIP.ID + if !core.IsNil(vniDetails.Ips) { + ips := []map[string]interface{}{} + for _, ipsItem := range vniDetails.Ips { + if *ipsItem.ID != primaryipId { + ipsItemMap, err := resourceIBMIsVirtualNetworkInterfaceReservedIPReferenceToMap(&ipsItem, true) + if err != nil { + return nil, err + } + ips = append(ips, ipsItemMap) + } + } + modelMap["ips"] = ips + } + primaryIPMap, err := resourceIBMIsBareMetalServerReservedIPReferenceToMap(vniDetails.PrimaryIP) + if err != nil { + return modelMap, err + } + modelMap["primary_ip"] = []map[string]interface{}{primaryIPMap} + + if !core.IsNil(vniDetails.SecurityGroups) { + securityGroups := make([]string, 0) + for _, securityGroupsItem := range vniDetails.SecurityGroups { + if securityGroupsItem.ID != nil { + securityGroups = append(securityGroups, *securityGroupsItem.ID) + } + } + modelMap["security_groups"] = securityGroups + } + if model.ResourceType != nil { + modelMap["resource_type"] = *model.ResourceType + } + if vniDetails.Subnet != nil { + modelMap["subnet"] = *vniDetails.Subnet.ID + } + modelMap["id"] = model.ID + modelMap["name"] = model.Name + modelMap["resource_type"] = model.ResourceType + return modelMap, nil +} diff --git a/ibm/service/vpc/resource_ibm_is_bare_metal_server_network_attachment_test.go b/ibm/service/vpc/resource_ibm_is_bare_metal_server_network_attachment_test.go new file mode 100644 index 0000000000..4302347a42 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_bare_metal_server_network_attachment_test.go @@ -0,0 +1,197 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func TestAccIBMIsBareMetalServerNetworkAttachmentPci(t *testing.T) { + var conf vpcv1.BareMetalServerNetworkAttachment + 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)) + vniname := fmt.Sprintf("tf-vni-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIsBareMetalServerNetworkAttachmentDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsBareMetalServerNetworkAttachmentConfigPci(vpcname, subnetname, sshname, publicKey, vniname, name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIsBareMetalServerNetworkAttachmentExists("ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", conf), + resource.TestCheckResourceAttrSet("ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "allowed_vlans.#"), + resource.TestCheckResourceAttrSet("ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "created_at"), + resource.TestCheckResourceAttrSet("ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "href"), + resource.TestCheckResourceAttrSet("ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "id"), + resource.TestCheckResourceAttrSet("ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "interface_type"), + resource.TestCheckResourceAttrSet("ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "name"), + resource.TestCheckResourceAttrSet("ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "port_speed"), + resource.TestCheckResourceAttrSet("ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "virtual_network_interface.#"), + resource.TestCheckResourceAttrSet("ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "virtual_network_interface.0.primary_ip.#"), + resource.TestCheckResourceAttr("ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "allowed_vlans.#", "3"), + resource.TestCheckResourceAttr("ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "type", "secondary"), + resource.TestCheckResourceAttr("ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "lifecycle_state", "stable"), + resource.TestCheckResourceAttr("ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "resource_type", "bare_metal_server_network_attachment"), + ), + }, + }, + }) +} +func TestAccIBMIsBareMetalServerNetworkAttachmentVlan(t *testing.T) { + var conf vpcv1.BareMetalServerNetworkAttachment + 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)) + vniname := fmt.Sprintf("tf-vni-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIsBareMetalServerNetworkAttachmentDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsBareMetalServerNetworkAttachmentConfigVlan(vpcname, subnetname, sshname, publicKey, vniname, name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIsBareMetalServerNetworkAttachmentExists("ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", conf), + resource.TestCheckResourceAttrSet("ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "vlan"), + resource.TestCheckResourceAttrSet("ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "created_at"), + resource.TestCheckResourceAttrSet("ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "href"), + resource.TestCheckResourceAttrSet("ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "id"), + resource.TestCheckResourceAttrSet("ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "interface_type"), + resource.TestCheckResourceAttrSet("ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "name"), + resource.TestCheckResourceAttrSet("ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "port_speed"), + resource.TestCheckResourceAttrSet("ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "virtual_network_interface.#"), + resource.TestCheckResourceAttrSet("ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "virtual_network_interface.0.primary_ip.#"), + resource.TestCheckResourceAttr("ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "vlan", "100"), + resource.TestCheckResourceAttr("ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "type", "secondary"), + resource.TestCheckResourceAttr("ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "lifecycle_state", "stable"), + resource.TestCheckResourceAttr("ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment", "resource_type", "bare_metal_server_network_attachment"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsBareMetalServerNetworkAttachmentConfigVlan(vpcname, subnetname, sshname, publicKey, vniname, name string) string { + return testAccCheckIBMISBareMetalServerVNIConfig(vpcname, subnetname, sshname, publicKey, vniname, name) + fmt.Sprintf(` + resource "ibm_is_virtual_network_interface" "testacc_vni1"{ + name = "test-vni-na" + subnet = "0717-a68ebc16-d63c-44e7-aa37-4b3791415b1d" + enable_infrastructure_nat = true + allow_ip_spoofing = true + } + resource "ibm_is_bare_metal_server_network_attachment" "is_bare_metal_server_network_attachment" { + bare_metal_server = "0717-0579cb7c-5ca7-4cb2-9792-7dcf06de25ca" + vlan = 100 + virtual_network_interface { + id = ibm_is_virtual_network_interface.testacc_vni1.id + } + } + `) +} +func testAccCheckIBMIsBareMetalServerNetworkAttachmentConfigPci(vpcname, subnetname, sshname, publicKey, vniname, name string) string { + return testAccCheckIBMISBareMetalServerVNIConfig(vpcname, subnetname, sshname, publicKey, vniname, name) + fmt.Sprintf(` + resource "ibm_is_virtual_network_interface" "testacc_vni1"{ + name = "test-vni-na" + subnet = ibm_is_subnet.testacc_subnet.id + enable_infrastructure_nat = true + allow_ip_spoofing = true + } + resource "ibm_is_bare_metal_server_network_attachment" "is_bare_metal_server_network_attachment" { + bare_metal_server = ibm_is_bare_metal_server.testacc_bms.id + allowed_vlans = [300, 302, 303] + virtual_network_interface { + id = ibm_is_virtual_network_interface.testacc_vni1.id + } + } + `) +} + +func testAccCheckIBMIsBareMetalServerNetworkAttachmentExists(n string, obj vpcv1.BareMetalServerNetworkAttachment) 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 := vpcClient(acc.TestAccProvider.Meta()) + if err != nil { + return err + } + + getBareMetalServerNetworkAttachmentOptions := &vpcv1.GetBareMetalServerNetworkAttachmentOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getBareMetalServerNetworkAttachmentOptions.SetBareMetalServerID(parts[0]) + getBareMetalServerNetworkAttachmentOptions.SetID(parts[1]) + + bareMetalServerNetworkAttachmentIntf, _, err := vpcClient.GetBareMetalServerNetworkAttachment(getBareMetalServerNetworkAttachmentOptions) + if err != nil { + return err + } + + bareMetalServerNetworkAttachment := bareMetalServerNetworkAttachmentIntf.(*vpcv1.BareMetalServerNetworkAttachment) + obj = *bareMetalServerNetworkAttachment + return nil + } +} + +func testAccCheckIBMIsBareMetalServerNetworkAttachmentDestroy(s *terraform.State) error { + vpcClient, err := vpcClient(acc.TestAccProvider.Meta()) + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_bare_metal_server_network_attachment" { + continue + } + + getBareMetalServerNetworkAttachmentOptions := &vpcv1.GetBareMetalServerNetworkAttachmentOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getBareMetalServerNetworkAttachmentOptions.SetBareMetalServerID(parts[0]) + getBareMetalServerNetworkAttachmentOptions.SetID(parts[1]) + + // Try to find the key + _, response, err := vpcClient.GetBareMetalServerNetworkAttachment(getBareMetalServerNetworkAttachmentOptions) + + if err == nil { + return fmt.Errorf("is_bare_metal_server_network_attachment still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for is_bare_metal_server_network_attachment (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} 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 3558a5c8ce..dfd18946c2 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 @@ -46,6 +46,35 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE }, }) } +func TestAccIBMISBareMetalServerVNI_basic(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)) + vniname := fmt.Sprintf("tfip-vni-%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: testAccCheckIBMISBareMetalServerVNIConfig(vpcname, subnetname, sshname, publicKey, vniname, 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), + ), + }, + }, + }) +} func TestAccIBMISBareMetalServer_sg_update(t *testing.T) { var server string vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) @@ -405,6 +434,46 @@ func testAccCheckIBMISBareMetalServerConfig(vpcname, subnetname, sshname, public } `, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, acc.IsBareMetalServerProfileName, name, acc.IsBareMetalServerImage, acc.ISZoneName) } +func testAccCheckIBMISBareMetalServerVNIConfig(vpcname, subnetname, sshname, publicKey, vniname, 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_virtual_network_interface" "testacc_vni"{ + name = "%s" + subnet = ibm_is_subnet.testacc_subnet.id + enable_infrastructure_nat = true + allow_ip_spoofing = true + } + 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_attachment { + name = "test-vni-100-102" + virtual_network_interface { + id = ibm_is_virtual_network_interface.testacc_vni.id + } + allowed_vlans = [100, 102] + } + vpc = ibm_is_vpc.testacc_vpc.id + } +`, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, vniname, acc.IsBareMetalServerProfileName, name, acc.IsBareMetalServerImage, acc.ISZoneName) +} func testAccCheckIBMISBareMetalServerSgUpdateConfig(vpcname, subnetname, sshname, publicKey, name string) string { return fmt.Sprintf(` resource "ibm_is_vpc" "testacc_vpc" { diff --git a/ibm/service/vpc/resource_ibm_is_flow_log_test.go b/ibm/service/vpc/resource_ibm_is_flow_log_test.go index bb1e572b3c..2ae5a35881 100644 --- a/ibm/service/vpc/resource_ibm_is_flow_log_test.go +++ b/ibm/service/vpc/resource_ibm_is_flow_log_test.go @@ -64,6 +64,37 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE }, ) } +func TestAccIBMISFlowLog_vni(t *testing.T) { + var instance string + vpcname := fmt.Sprintf("flowlog-vpc-%d", acctest.RandIntRange(10, 100)) + flowlogname := fmt.Sprintf("flowlog-instance-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("flowlog-subnet-%d", acctest.RandIntRange(10, 100)) + + vniname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) + bucketRegion := "us-south" + bucketClass := "standard" + bucketRegionType := "cross_region_location" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISFlowLogDestroy, + Steps: []resource.TestStep{ + + { + //Create test case + Config: testAccCheckIBMISFlowLogVniConfig(vpcname, vniname, flowlogname, subnetname, bucketName, bucketRegionType, bucketRegion, bucketClass, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISFlowLogExists("ibm_is_flow_log.test_flow_log", instance), + resource.TestCheckResourceAttr("ibm_is_flow_log.test_flow_log", "name", flowlogname), + resource.TestCheckResourceAttr("data.ibm_is_flow_log.is_flow_log_name", "target.0.resource_type", "virtual_network_interface"), + ), + }, + }, + }, + ) +} func testAccCheckIBMISFlowLogConfig(vpcname, name, flowlogname, sshname, publicKey, subnetname, serviceName, bucketName, bucketRegionType, bucketRegion, bucketClass string, isActive bool) string { return fmt.Sprintf(` @@ -125,6 +156,46 @@ func testAccCheckIBMISFlowLogConfig(vpcname, name, flowlogname, sshname, publicK `, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName, serviceName, bucketName, bucketRegion, bucketClass, flowlogname, isActive) +} +func testAccCheckIBMISFlowLogVniConfig(vpcname, vniname, flowlogname, subnetname, bucketName, bucketRegionType, bucketRegion, bucketClass string, isActive bool) 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_virtual_network_interface" "testacc_vni"{ + name = "%s" + subnet = ibm_is_subnet.testacc_subnet.id + } + + resource "ibm_cos_bucket" "bucket2" { + bucket_name = "%s" + resource_instance_id = "%s" + region_location = "%s" + storage_class = "%s" + } + // Authorisation policy is required between vpc Flowlogs and Object Storage + + resource "ibm_is_flow_log" "test_flow_log" { + name = "%s" + target = ibm_is_virtual_network_interface.testacc_vni.id + storage_bucket = ibm_cos_bucket.bucket2.bucket_name + active = %v + } + data "ibm_is_flow_log" "is_flow_log_name" { + name = ibm_is_flow_log.test_flow_log.name + } + + `, vpcname, subnetname, acc.ISZoneName, vniname, bucketName, acc.ISResourceCrn, bucketRegion, bucketClass, flowlogname, isActive) + } func vpcClient(meta interface{}) (*vpcv1.VpcV1, error) { sess, err := meta.(conns.ClientSession).VpcV1API() diff --git a/ibm/service/vpc/resource_ibm_is_instance.go b/ibm/service/vpc/resource_ibm_is_instance.go index 2debbf2734..9d7deef928 100644 --- a/ibm/service/vpc/resource_ibm_is_instance.go +++ b/ibm/service/vpc/resource_ibm_is_instance.go @@ -14,6 +14,7 @@ import ( "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" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -399,12 +400,13 @@ func ResourceIBMISInstance() *schema.Resource { }, isInstancePrimaryNetworkInterface: { - Type: schema.TypeList, - MinItems: 1, - MaxItems: 1, - Optional: true, - Computed: true, - Description: "Primary Network interface info", + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Optional: true, + Computed: true, + ConflictsWith: []string{"primary_network_attachment", "network_attachments"}, + Description: "Primary Network interface info", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "id": { @@ -503,10 +505,258 @@ func ResourceIBMISInstance() *schema.Resource { }, }, + "primary_network_attachment": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "The primary network attachment for this virtual server instance.", + ExactlyOneOf: []string{"primary_network_attachment", "primary_network_interface"}, + ConflictsWith: []string{"primary_network_interface", "network_interfaces"}, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + + // pna can accept either vni id or prototype + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_instance_network_attachment", "name"), + Description: "The name for this instance 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 network attachment.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this instance network attachment.", + }, + "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.", + }, + }, + }, + }, + + // vni properties + "virtual_network_interface": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Computed: true, + Description: "A virtual network interface for the instance network attachment. This can be specified using an existing virtual network interface, or a prototype object for a new virtual network interface.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The virtual network interface id for this instance network attachment.", + }, + "allow_ip_spoofing": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + ConflictsWith: []string{"primary_network_attachment.0.virtual_network_interface.0.id"}, + Computed: true, + Description: "Indicates whether source IP spoofing is allowed on this interface. If `false`, source IP spoofing is prevented on this interface. If `true`, source IP spoofing is allowed on this interface.", + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + ConflictsWith: []string{"primary_network_attachment.0.virtual_network_interface.0.id"}, + Computed: true, + Description: "Indicates whether this virtual network interface will be automatically deleted when`target` is deleted.", + }, + "enable_infrastructure_nat": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + ConflictsWith: []string{"primary_network_attachment.0.virtual_network_interface.0.id"}, + 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 network interface, allowing the workload to perform any needed NAT operations.- `allow_ip_spoofing` must be `false`.- If the virtual network interface is attached: - The target `resource_type` must be `bare_metal_server_network_attachment`. - The target `interface_type` must not be `hipersocket`.", + }, + "ips": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + ConflictsWith: []string{"primary_network_attachment.0.virtual_network_interface.0.id"}, + Computed: true, + Set: hashIpsList, + Description: "The reserved IPs bound to this virtual network interface.May be empty when `lifecycle_state` is `pending`.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + // Optional: true, + Computed: true, + Description: "The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "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.", + }, + }, + }, + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + // Optional: true, + Computed: true, + Description: "Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP.", + }, + "reserved_ip": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + // Optional: true, + Computed: true, + Description: "The name for this reserved IP. The name is unique across all reserved IPs in a subnet.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"primary_network_attachment.0.virtual_network_interface.0.id"}, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_virtual_network_interface", "vni_name"), + Description: "The name for this virtual network interface. The name is unique across all virtual network interfaces in the VPC.", + }, + "primary_ip": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + ConflictsWith: []string{"primary_network_attachment.0.virtual_network_interface.0.id"}, + Computed: true, + Description: "The primary IP address of the virtual network interface for the instance networkattachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "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 reserved IP.", + }, + "reserved_ip": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The name for this reserved IP. The name is unique across all reserved IPs in a subnet.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: "Indicates whether this reserved ip will be automatically deleted when `target` is deleted.", + }, + }, + }, + }, + "resource_group": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"primary_network_attachment.0.virtual_network_interface.0.id"}, + Computed: true, + Description: "The resource group id for this virtual network interface.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "security_groups": { + Type: schema.TypeSet, + Optional: true, + ConflictsWith: []string{"primary_network_attachment.0.virtual_network_interface.0.id"}, + Computed: true, + ForceNew: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "The security groups for this virtual network interface.", + }, + "subnet": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"primary_network_attachment.0.virtual_network_interface.0.id"}, + Computed: true, + ForceNew: true, + Description: "The associated subnet id.", + }, + }, + }, + }, + }, + }, + }, + isInstanceNetworkInterfaces: { - Type: schema.TypeList, - Optional: true, - Computed: true, + Type: schema.TypeList, + Optional: true, + Computed: true, + ConflictsWith: []string{"primary_network_attachment", "network_attachments"}, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "id": { @@ -594,6 +844,240 @@ func ResourceIBMISInstance() *schema.Resource { }, }, + "network_attachments": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Computed: true, + ConflictsWith: []string{"primary_network_interface", "network_interfaces"}, + Description: "The network attachments for this virtual server instance, including the primary network attachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + + // pna can accept either vni id or prototype + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_instance_network_attachment", "name"), + Description: "The name for this instance 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 network attachment.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this instance network attachment.", + }, + "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.", + }, + }, + }, + }, + + "virtual_network_interface": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "A virtual network interface for the instance network attachment. This can be specified using an existing virtual network interface, or a prototype object for a new virtual network interface.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The virtual network interface id for this instance network attachment.", + }, + "allow_ip_spoofing": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Indicates whether source IP spoofing is allowed on this interface. If `false`, source IP spoofing is prevented on this interface. If `true`, source IP spoofing is allowed on this interface.", + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Indicates whether this virtual network interface will be automatically deleted when`target` is deleted.", + }, + "enable_infrastructure_nat": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + 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 network interface, allowing the workload to perform any needed NAT operations.- `allow_ip_spoofing` must be `false`.- If the virtual network interface is attached: - The target `resource_type` must be `bare_metal_server_network_attachment`. - The target `interface_type` must not be `hipersocket`.", + }, + "ips": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Computed: true, + Set: hashIpsList, + Description: "The reserved IPs bound to this virtual network interface.May be empty when `lifecycle_state` is `pending`.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + // Optional: true, + Computed: true, + Description: "The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "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.", + }, + }, + }, + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + // Optional: true, + Computed: true, + Description: "Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP.", + }, + "reserved_ip": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + // Optional: true, + Computed: true, + Description: "The name for this reserved IP. The name is unique across all reserved IPs in a subnet.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_virtual_network_interface", "vni_name"), + Description: "The name for this virtual network interface. The name is unique across all virtual network interfaces in the VPC.", + }, + "primary_ip": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Computed: true, + Description: "The primary IP address of the virtual network interface for the instance networkattachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: "Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound.", + }, + "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 reserved IP.", + }, + "reserved_ip": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The name for this reserved IP. The name is unique across all reserved IPs in a subnet.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "resource_group": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The resource group id for this virtual network interface.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "security_groups": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "The security groups for this virtual network interface.", + }, + "subnet": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The associated subnet id.", + }, + }, + }, + }, + }, + }, + }, + isInstanceUserData: { Type: schema.TypeString, ForceNew: true, @@ -608,7 +1092,7 @@ func ResourceIBMISInstance() *schema.Resource { Optional: true, ConflictsWith: []string{"boot_volume.0.snapshot", "catalog_offering.0.offering_crn", "catalog_offering.0.version_crn", "boot_volume.0.volume_id"}, AtLeastOneOf: []string{isInstanceImage, isInstanceSourceTemplate, "boot_volume.0.snapshot", "catalog_offering.0.offering_crn", "catalog_offering.0.version_crn", "boot_volume.0.volume_id"}, - RequiredWith: []string{isInstanceZone, isInstancePrimaryNetworkInterface, isInstanceKeys, isInstanceVPC, isInstanceProfile}, + RequiredWith: []string{isInstanceZone, isInstanceKeys, isInstanceVPC, isInstanceProfile}, Description: "image id", }, @@ -624,7 +1108,7 @@ func ResourceIBMISInstance() *schema.Resource { Optional: true, ForceNew: true, Computed: true, - RequiredWith: []string{isInstanceZone, isInstancePrimaryNetworkInterface, isInstanceProfile, isInstanceKeys, isInstanceVPC}, + RequiredWith: []string{isInstanceZone, isInstanceProfile, isInstanceKeys, isInstanceVPC}, AtLeastOneOf: []string{isInstanceImage, isInstanceSourceTemplate, "boot_volume.0.volume_id", "boot_volume.0.snapshot", "catalog_offering.0.offering_crn", "catalog_offering.0.version_crn"}, ConflictsWith: []string{isInstanceImage, isInstanceSourceTemplate, "boot_volume.0.snapshot", "boot_volume.0.name", "boot_volume.0.encryption", "catalog_offering.0.offering_crn", "catalog_offering.0.version_crn"}, Description: "The unique identifier for this volume", @@ -644,7 +1128,7 @@ func ResourceIBMISInstance() *schema.Resource { isInstanceVolumeSnapshot: { Type: schema.TypeString, - RequiredWith: []string{isInstanceZone, isInstancePrimaryNetworkInterface, isInstanceProfile, isInstanceKeys, isInstanceVPC}, + RequiredWith: []string{isInstanceZone, isInstanceProfile, isInstanceKeys, isInstanceVPC}, AtLeastOneOf: []string{isInstanceImage, isInstanceSourceTemplate, "boot_volume.0.snapshot", "catalog_offering.0.offering_crn", "catalog_offering.0.version_crn", "boot_volume.0.volume_id"}, ConflictsWith: []string{isInstanceImage, isInstanceSourceTemplate, "catalog_offering.0.offering_crn", "catalog_offering.0.version_crn", "boot_volume.0.volume_id"}, Optional: true, @@ -1000,6 +1484,119 @@ func ResourceIBMISInstance() *schema.Resource { }, }, }, + isInstanceReservation: { + Type: schema.TypeList, + Computed: true, + Description: "The reservation used by this virtual server instance", + 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 virtual server instance.", + }, + isReservationAffinityPool: &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Computed: true, + Description: "The pool of reservations available for use by this virtual server instance.", + 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.", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, }, } } @@ -1214,8 +1811,62 @@ func instanceCreateByImage(d *schema.ResourceData, meta interface{}, profile, na } - if primnicintf, ok := d.GetOk(isInstancePrimaryNetworkInterface); ok { - primnic := primnicintf.([]interface{})[0].(map[string]interface{}) + if networkattachmentsintf, ok := d.GetOk("network_attachments"); ok { + networkAttachments := []vpcv1.InstanceNetworkAttachmentPrototype{} + for i, networkAttachmentsItem := range networkattachmentsintf.([]interface{}) { + allowipspoofing := fmt.Sprintf("network_attachments.%d.virtual_network_interface.0.allow_ip_spoofing", i) + autodelete := fmt.Sprintf("network_attachments.%d.virtual_network_interface.0.auto_delete", i) + enablenat := fmt.Sprintf("network_attachments.%d.virtual_network_interface.0.enable_infrastructure_nat", i) + // allowipspoofing := "primary_network_attachment.0.allow_ip_spoofing" + // autodelete := "primary_network_attachment.0.autodelete" + // enablenat := "primary_network_attachment.0.enable_infrastructure_nat" + networkAttachmentsItemModel, err := resourceIBMIsInstanceMapToInstanceNetworkAttachmentPrototype(allowipspoofing, autodelete, enablenat, d, networkAttachmentsItem.(map[string]interface{})) + if err != nil { + return err + } + networkAttachments = append(networkAttachments, *networkAttachmentsItemModel) + } + instanceproto.NetworkAttachments = networkAttachments + } + if primnetworkattachmentintf, ok := d.GetOk("primary_network_attachment"); ok && len(primnetworkattachmentintf.([]interface{})) > 0 { + i := 0 + allowipspoofing := fmt.Sprintf("primary_network_attachment.%d.virtual_network_interface.0.allow_ip_spoofing", i) + autodelete := fmt.Sprintf("primary_network_attachment.%d.virtual_network_interface.0.auto_delete", i) + enablenat := fmt.Sprintf("primary_network_attachment.%d.virtual_network_interface.0.enable_infrastructure_nat", i) + primaryNetworkAttachmentModel, err := resourceIBMIsInstanceMapToInstanceNetworkAttachmentPrototype(allowipspoofing, autodelete, enablenat, d, primnetworkattachmentintf.([]interface{})[0].(map[string]interface{})) + if err != nil { + return err + } + instanceproto.PrimaryNetworkAttachment = primaryNetworkAttachmentModel + } + if resAffinity, ok := d.GetOk(isReservationAffinity); ok { + resAff := resAffinity.([]interface{})[0].(map[string]interface{}) + var resAffinity = &vpcv1.InstanceReservationAffinityPrototype{} + policy, ok := resAff["policy"] + policyStr := policy.(string) + if policyStr != "" && ok { + resAffinity.Policy = &policyStr + } + poolIntf, okPool := resAff[isReservationAffinityPool] + if okPool { + 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 + } + } + } + instanceproto.ReservationAffinity = resAffinity + } + + if primnicintf, ok := d.GetOk(isInstancePrimaryNetworkInterface); ok { + primnic := primnicintf.([]interface{})[0].(map[string]interface{}) subnetintf, _ := primnic[isInstanceNicSubnet] subnetintfstr := subnetintf.(string) var primnicobj = &vpcv1.NetworkInterfacePrototype{} @@ -1455,7 +2106,7 @@ func instanceCreateByImage(d *schema.ResourceData, meta interface{}, profile, na err = flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, *instance.CRN, "", isInstanceUserTagType) if err != nil { log.Printf( - "Error on create of resource instance (%s) tags: %s", d.Id(), err) + "[ERROR] Error on create of resource instance (%s) tags: %s", d.Id(), err) } } if _, ok := d.GetOk(isInstanceAccessTags); ok { @@ -1463,7 +2114,7 @@ func instanceCreateByImage(d *schema.ResourceData, meta interface{}, profile, na err = flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, *instance.CRN, "", isInstanceAccessTagType) if err != nil { log.Printf( - "Error on create of resource instance (%s) access tags: %s", d.Id(), err) + "[ERROR] Error on create of resource instance (%s) access tags: %s", d.Id(), err) } } return nil @@ -1587,6 +2238,60 @@ func instanceCreateByCatalogOffering(d *schema.ResourceData, meta interface{}, p } + if networkattachmentsintf, ok := d.GetOk("network_attachments"); ok { + networkAttachments := []vpcv1.InstanceNetworkAttachmentPrototype{} + for i, networkAttachmentsItem := range networkattachmentsintf.([]interface{}) { + allowipspoofing := fmt.Sprintf("network_attachments.%d.virtual_network_interface.0.allow_ip_spoofing", i) + autodelete := fmt.Sprintf("network_attachments.%d.virtual_network_interface.0.auto_delete", i) + enablenat := fmt.Sprintf("network_attachments.%d.virtual_network_interface.0.enable_infrastructure_nat", i) + // allowipspoofing := "primary_network_attachment.0.allow_ip_spoofing" + // autodelete := "primary_network_attachment.0.autodelete" + // enablenat := "primary_network_attachment.0.enable_infrastructure_nat" + networkAttachmentsItemModel, err := resourceIBMIsInstanceMapToInstanceNetworkAttachmentPrototype(allowipspoofing, autodelete, enablenat, d, networkAttachmentsItem.(map[string]interface{})) + if err != nil { + return err + } + networkAttachments = append(networkAttachments, *networkAttachmentsItemModel) + } + instanceproto.NetworkAttachments = networkAttachments + } + if primnetworkattachmentintf, ok := d.GetOk("primary_network_attachment"); ok && len(primnetworkattachmentintf.([]interface{})) > 0 { + i := 0 + allowipspoofing := fmt.Sprintf("primary_network_attachment.%d.virtual_network_interface.0.allow_ip_spoofing", i) + autodelete := fmt.Sprintf("primary_network_attachment.%d.virtual_network_interface.0.auto_delete", i) + enablenat := fmt.Sprintf("primary_network_attachment.%d.virtual_network_interface.0.enable_infrastructure_nat", i) + primaryNetworkAttachmentModel, err := resourceIBMIsInstanceMapToInstanceNetworkAttachmentPrototype(allowipspoofing, autodelete, enablenat, d, primnetworkattachmentintf.([]interface{})[0].(map[string]interface{})) + if err != nil { + return err + } + instanceproto.PrimaryNetworkAttachment = primaryNetworkAttachmentModel + } + if resAffinity, ok := d.GetOk(isReservationAffinity); ok { + resAff := resAffinity.([]interface{})[0].(map[string]interface{}) + var resAffinity = &vpcv1.InstanceReservationAffinityPrototype{} + policy, ok := resAff["policy"] + policyStr := policy.(string) + if policyStr != "" && ok { + resAffinity.Policy = &policyStr + } + poolIntf, okPool := resAff[isReservationAffinityPool] + if okPool { + 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 + } + } + } + instanceproto.ReservationAffinity = resAffinity + } + if primnicintf, ok := d.GetOk(isInstancePrimaryNetworkInterface); ok { primnic := primnicintf.([]interface{})[0].(map[string]interface{}) subnetintf, _ := primnic[isInstanceNicSubnet] @@ -1828,7 +2533,7 @@ func instanceCreateByCatalogOffering(d *schema.ResourceData, meta interface{}, p 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) + "[ERROR] Error on create of resource instance (%s) tags: %s", d.Id(), err) } } return nil @@ -1958,6 +2663,57 @@ func instanceCreateByTemplate(d *schema.ResourceData, meta interface{}, profile, } } + if networkattachmentsintf, ok := d.GetOk("network_attachments"); ok { + networkAttachments := []vpcv1.InstanceNetworkAttachmentPrototype{} + for i, networkAttachmentsItem := range networkattachmentsintf.([]interface{}) { + allowipspoofing := fmt.Sprintf("network_attachments.%d.allow_ip_spoofing", i) + autodelete := fmt.Sprintf("network_attachments.%d.autodelete", i) + enablenat := fmt.Sprintf("network_attachments.%d.enable_infrastructure_nat", i) + networkAttachmentsItemModel, err := resourceIBMIsInstanceMapToInstanceNetworkAttachmentPrototype(allowipspoofing, autodelete, enablenat, d, networkAttachmentsItem.(map[string]interface{})) + if err != nil { + return err + } + networkAttachments = append(networkAttachments, *networkAttachmentsItemModel) + } + instanceproto.NetworkAttachments = networkAttachments + } + if primnetworkattachmentintf, ok := d.GetOk("primary_network_attachment"); ok && len(primnetworkattachmentintf.([]interface{})) > 0 { + i := 0 + allowipspoofing := fmt.Sprintf("primary_network_attachment.%d.virtual_network_interface.0.allow_ip_spoofing", i) + autodelete := fmt.Sprintf("primary_network_attachment.%d.virtual_network_interface.0.auto_delete", i) + enablenat := fmt.Sprintf("primary_network_attachment.%d.virtual_network_interface.0.enable_infrastructure_nat", i) + primaryNetworkAttachmentModel, err := resourceIBMIsInstanceMapToInstanceNetworkAttachmentPrototype(allowipspoofing, autodelete, enablenat, d, primnetworkattachmentintf.([]interface{})[0].(map[string]interface{})) + if err != nil { + return err + } + instanceproto.PrimaryNetworkAttachment = primaryNetworkAttachmentModel + } + if resAffinity, ok := d.GetOk(isReservationAffinity); ok { + resAff := resAffinity.([]interface{})[0].(map[string]interface{}) + var resAffinity = &vpcv1.InstanceReservationAffinityPrototype{} + policy, ok := resAff["policy"] + policyStr := policy.(string) + if policyStr != "" && ok { + resAffinity.Policy = &policyStr + } + poolIntf, okPool := resAff[isReservationAffinityPool] + if okPool { + 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 + } + } + } + instanceproto.ReservationAffinity = resAffinity + } + if primnicintf, ok := d.GetOk(isInstancePrimaryNetworkInterface); ok { primnic := primnicintf.([]interface{})[0].(map[string]interface{}) subnetintf, _ := primnic[isInstanceNicSubnet] @@ -2198,7 +2954,7 @@ func instanceCreateByTemplate(d *schema.ResourceData, meta interface{}, profile, 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) + "[ERROR] Error on create of resource instance (%s) tags: %s", d.Id(), err) } } if _, ok := d.GetOk(isInstanceAccessTags); ok { @@ -2206,7 +2962,7 @@ func instanceCreateByTemplate(d *schema.ResourceData, meta interface{}, profile, err = flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, *instance.CRN, "", isInstanceAccessTagType) if err != nil { log.Printf( - "Error on create of resource instance (%s) access tags: %s", d.Id(), err) + "[ERROR] Error on create of resource instance (%s) access tags: %s", d.Id(), err) } } return nil @@ -2321,11 +3077,64 @@ func instanceCreateBySnapshot(d *schema.ResourceData, meta interface{}, profile, Volume: volTemplate, } } + + if resAffinity, ok := d.GetOk(isReservationAffinity); ok { + resAff := resAffinity.([]interface{})[0].(map[string]interface{}) + var resAffinity = &vpcv1.InstanceReservationAffinityPrototype{} + policy, ok := resAff["policy"] + policyStr := policy.(string) + if policyStr != "" && ok { + resAffinity.Policy = &policyStr + } + poolIntf, okPool := resAff[isReservationAffinityPool] + if okPool { + 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 + } + } + } + instanceproto.ReservationAffinity = resAffinity + } + if totalVolBandwidthIntf, ok := d.GetOk(isInstanceTotalVolumeBandwidth); ok { totalVolBandwidthStr := int64(totalVolBandwidthIntf.(int)) instanceproto.TotalVolumeBandwidth = &totalVolBandwidthStr } + if networkattachmentsintf, ok := d.GetOk("network_attachments"); ok { + networkAttachments := []vpcv1.InstanceNetworkAttachmentPrototype{} + for i, networkAttachmentsItem := range networkattachmentsintf.([]interface{}) { + allowipspoofing := fmt.Sprintf("network_attachments.%d.allow_ip_spoofing", i) + autodelete := fmt.Sprintf("network_attachments.%d.autodelete", i) + enablenat := fmt.Sprintf("network_attachments.%d.enable_infrastructure_nat", i) + networkAttachmentsItemModel, err := resourceIBMIsInstanceMapToInstanceNetworkAttachmentPrototype(allowipspoofing, autodelete, enablenat, d, networkAttachmentsItem.(map[string]interface{})) + if err != nil { + return err + } + networkAttachments = append(networkAttachments, *networkAttachmentsItemModel) + } + instanceproto.NetworkAttachments = networkAttachments + } + if primnetworkattachmentintf, ok := d.GetOk("primary_network_attachment"); ok && len(primnetworkattachmentintf.([]interface{})) > 0 { + i := 0 + allowipspoofing := fmt.Sprintf("primary_network_attachment.%d.virtual_network_interface.0.allow_ip_spoofing", i) + autodelete := fmt.Sprintf("primary_network_attachment.%d.virtual_network_interface.0.auto_delete", i) + enablenat := fmt.Sprintf("primary_network_attachment.%d.virtual_network_interface.0.enable_infrastructure_nat", i) + primaryNetworkAttachmentModel, err := resourceIBMIsInstanceMapToInstanceNetworkAttachmentPrototype(allowipspoofing, autodelete, enablenat, d, primnetworkattachmentintf.([]interface{})[0].(map[string]interface{})) + if err != nil { + return err + } + instanceproto.PrimaryNetworkAttachment = primaryNetworkAttachmentModel + } + if primnicintf, ok := d.GetOk(isInstancePrimaryNetworkInterface); ok { primnic := primnicintf.([]interface{})[0].(map[string]interface{}) subnetintf, _ := primnic[isInstanceNicSubnet] @@ -2571,7 +3380,7 @@ func instanceCreateBySnapshot(d *schema.ResourceData, meta interface{}, profile, err = flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, *instance.CRN, "", isInstanceUserTagType) if err != nil { log.Printf( - "Error on create of resource instance (%s) tags: %s", d.Id(), err) + "[ERROR] Error on create of resource instance (%s) tags: %s", d.Id(), err) } } if _, ok := d.GetOk(isInstanceAccessTags); ok { @@ -2579,7 +3388,7 @@ func instanceCreateBySnapshot(d *schema.ResourceData, meta interface{}, profile, err = flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, *instance.CRN, "", isInstanceAccessTagType) if err != nil { log.Printf( - "Error on create of resource instance (%s) access tags: %s", d.Id(), err) + "[ERROR] Error on create of resource instance (%s) access tags: %s", d.Id(), err) } } return nil @@ -2660,10 +3469,65 @@ func instanceCreateByVolume(d *schema.ResourceData, meta interface{}, profile, n } instanceproto.BootVolumeAttachment = bootVolAttachment } + + if resAffinity, ok := d.GetOk(isReservationAffinity); ok { + resAff := resAffinity.([]interface{})[0].(map[string]interface{}) + var resAffinity = &vpcv1.InstanceReservationAffinityPrototype{} + policy, ok := resAff["policy"] + policyStr := policy.(string) + if policyStr != "" && ok { + resAffinity.Policy = &policyStr + } + poolIntf, okPool := resAff[isReservationAffinityPool] + if okPool { + 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 + } + } + } + instanceproto.ReservationAffinity = resAffinity + } + if totalVolBandwidthIntf, ok := d.GetOk(isInstanceTotalVolumeBandwidth); ok { totalVolBandwidthStr := int64(totalVolBandwidthIntf.(int)) instanceproto.TotalVolumeBandwidth = &totalVolBandwidthStr } + if networkattachmentsintf, ok := d.GetOk("network_attachments"); ok { + networkAttachments := []vpcv1.InstanceNetworkAttachmentPrototype{} + for i, networkAttachmentsItem := range networkattachmentsintf.([]interface{}) { + allowipspoofing := fmt.Sprintf("network_attachments.%d.virtual_network_interface.0.allow_ip_spoofing", i) + autodelete := fmt.Sprintf("network_attachments.%d.virtual_network_interface.0.auto_delete", i) + enablenat := fmt.Sprintf("network_attachments.%d.virtual_network_interface.0.enable_infrastructure_nat", i) + // allowipspoofing := "primary_network_attachment.0.allow_ip_spoofing" + // autodelete := "primary_network_attachment.0.autodelete" + // enablenat := "primary_network_attachment.0.enable_infrastructure_nat" + networkAttachmentsItemModel, err := resourceIBMIsInstanceMapToInstanceNetworkAttachmentPrototype(allowipspoofing, autodelete, enablenat, d, networkAttachmentsItem.(map[string]interface{})) + if err != nil { + return err + } + networkAttachments = append(networkAttachments, *networkAttachmentsItemModel) + } + instanceproto.NetworkAttachments = networkAttachments + } + if primnetworkattachmentintf, ok := d.GetOk("primary_network_attachment"); ok && len(primnetworkattachmentintf.([]interface{})) > 0 { + i := 0 + allowipspoofing := fmt.Sprintf("primary_network_attachment.%d.virtual_network_interface.0.allow_ip_spoofing", i) + autodelete := fmt.Sprintf("primary_network_attachment.%d.virtual_network_interface.0.auto_delete", i) + enablenat := fmt.Sprintf("primary_network_attachment.%d.virtual_network_interface.0.enable_infrastructure_nat", i) + primaryNetworkAttachmentModel, err := resourceIBMIsInstanceMapToInstanceNetworkAttachmentPrototype(allowipspoofing, autodelete, enablenat, d, primnetworkattachmentintf.([]interface{})[0].(map[string]interface{})) + if err != nil { + return err + } + instanceproto.PrimaryNetworkAttachment = primaryNetworkAttachmentModel + } if primnicintf, ok := d.GetOk(isInstancePrimaryNetworkInterface); ok { primnic := primnicintf.([]interface{})[0].(map[string]interface{}) @@ -2909,7 +3773,7 @@ func instanceCreateByVolume(d *schema.ResourceData, meta interface{}, profile, n 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) + "[ERROR] Error on create of resource instance (%s) tags: %s", d.Id(), err) } } if _, ok := d.GetOk(isInstanceAccessTags); ok { @@ -2917,7 +3781,7 @@ func instanceCreateByVolume(d *schema.ResourceData, meta interface{}, profile, n err = flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, *instance.CRN, "", isInstanceAccessTagType) if err != nil { log.Printf( - "Error on create of resource instance (%s) access tags: %s", d.Id(), err) + "[ERROR] Error on create of resource instance (%s) access tags: %s", d.Id(), err) } } return nil @@ -3236,6 +4100,76 @@ func instanceGet(d *schema.ResourceData, meta interface{}, id string) error { primaryNicList = append(primaryNicList, currentPrimNic) d.Set(isInstancePrimaryNetworkInterface, primaryNicList) } + if instance.ReservationAffinity != nil { + reservationAffinity := []map[string]interface{}{} + reservationAffinityMap := map[string]interface{}{} + + reservationAffinityMap[isReservationAffinityPolicyResp] = instance.ReservationAffinity.Policy + if instance.ReservationAffinity.Pool != nil && len(instance.ReservationAffinity.Pool) > 0 { + poolList := make([]map[string]interface{}, 0) + for _, pool := range instance.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 := dataSourceInstanceReservationDeletedToMap(*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 instance.Reservation != nil { + res := map[string]interface{}{} + + res[isReservationId] = *instance.Reservation.ID + res[isReservationHref] = *instance.Reservation.Href + res[isReservationName] = *instance.Reservation.Name + res[isReservationCrn] = *instance.Reservation.CRN + res[isReservationResourceType] = *instance.Reservation.ResourceType + if instance.Reservation.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceInstanceReservationDeletedToMap(*instance.Reservation.Deleted) + deletedList = append(deletedList, deletedMap) + res[isReservationDeleted] = deletedList + } + resList = append(resList, res) + } + d.Set(isInstanceReservation, resList) + + if !core.IsNil(instance.PrimaryNetworkAttachment) { + + pnaId := *instance.PrimaryNetworkAttachment.ID + getInstanceNetworkAttachment := &vpcv1.GetInstanceNetworkAttachmentOptions{ + InstanceID: &id, + ID: &pnaId, + } + autoDelete := true + if autoDeleteOk, ok := d.GetOkExists("primary_network_attachment.0.virtual_network_interface.0.primary_ip.0.auto_delete"); ok { + autoDelete = autoDeleteOk.(bool) + } + pna, response, err := instanceC.GetInstanceNetworkAttachment(getInstanceNetworkAttachment) + if err != nil { + return fmt.Errorf("[ERROR] Error on GetInstanceNetworkAttachment in instance : %s\n%s", err, response) + } + primaryNetworkAttachmentMap, err := resourceIBMIsInstanceInstanceNetworkAttachmentReferenceToMap(instance.PrimaryNetworkAttachment, pna, instanceC, autoDelete) + if err != nil { + return err + } + if err = d.Set("primary_network_attachment", []map[string]interface{}{primaryNetworkAttachmentMap}); err != nil { + return fmt.Errorf("[ERROR] Error setting primary_network_attachment: %s", err) + } + } if instance.NetworkInterfaces != nil { interfacesList := make([]map[string]interface{}, 0) @@ -3304,6 +4238,34 @@ func instanceGet(d *schema.ResourceData, meta interface{}, id string) error { d.Set(isInstanceNetworkInterfaces, interfacesList) } + if !core.IsNil(instance.NetworkAttachments) { + networkAttachments := []map[string]interface{}{} + for i, networkAttachmentsItem := range instance.NetworkAttachments { + naId := *networkAttachmentsItem.ID + if *instance.PrimaryNetworkAttachment.ID != naId { + autoDelete := true + if autoDeleteOk, ok := d.GetOkExists(fmt.Sprintf("network_attachments.%d.virtual_network_interface.0.primary_ip.0.auto_delete", i)); ok { + autoDelete = autoDeleteOk.(bool) + } + getInstanceNetworkAttachment := &vpcv1.GetInstanceNetworkAttachmentOptions{ + InstanceID: &id, + ID: &naId, + } + na, response, err := instanceC.GetInstanceNetworkAttachment(getInstanceNetworkAttachment) + if err != nil { + return fmt.Errorf("[ERROR] Error on GetInstanceNetworkAttachment in instance : %s\n%s", err, response) + } + networkAttachmentsItemMap, err := resourceIBMIsInstanceInstanceNetworkAttachmentReferenceToMap(&networkAttachmentsItem, na, instanceC, autoDelete) + if err != nil { + return err + } + networkAttachments = append(networkAttachments, networkAttachmentsItemMap) + } + } + if err = d.Set("network_attachments", networkAttachments); err != nil { + return fmt.Errorf("[ERROR] Error setting network_attachments: %s", err) + } + } if instance.Image != nil { d.Set(isInstanceImage, *instance.Image.ID) } @@ -3323,152 +4285,675 @@ func instanceGet(d *schema.ResourceData, meta interface{}, id string) error { if sr.MoreInfo != nil { currentSR[isInstanceStatusReasonsMoreInfo] = *sr.MoreInfo } - statusReasonsList = append(statusReasonsList, currentSR) + statusReasonsList = append(statusReasonsList, currentSR) + } + } + d.Set(isInstanceStatusReasons, statusReasonsList) + } + + //set the lifecycle status, reasons + if instance.LifecycleState != nil { + d.Set(isInstanceLifecycleState, *instance.LifecycleState) + } + if instance.LifecycleReasons != nil { + d.Set(isInstanceLifecycleReasons, dataSourceInstanceFlattenLifecycleReasons(instance.LifecycleReasons)) + } + + d.Set(isInstanceVPC, *instance.VPC.ID) + d.Set(isInstanceZone, *instance.Zone.Name) + + if instance.VolumeAttachments != nil { + volList := make([]map[string]interface{}, 0) + for _, volume := range instance.VolumeAttachments { + vol := map[string]interface{}{} + if volume.Volume != 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 + volList = append(volList, vol) + } + } + d.Set(isInstanceVolumeAttachments, volList) + } + + if instance.BootVolumeAttachment != nil { + bootVolList := make([]map[string]interface{}, 0) + bootVol := map[string]interface{}{} + if instance.BootVolumeAttachment.Volume != nil { + bootVol[isInstanceBootAttachmentName] = *instance.BootVolumeAttachment.Volume.Name + bootVol[isInstanceBootVolumeId] = *instance.BootVolumeAttachment.Volume.ID + + instanceId := *instance.ID + bootVolID := *instance.BootVolumeAttachment.ID + getinsVolAttOptions := &vpcv1.GetInstanceVolumeAttachmentOptions{ + InstanceID: &instanceId, + ID: &bootVolID, + } + bootVolumeAtt, response, err := instanceC.GetInstanceVolumeAttachment(getinsVolAttOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error getting Instance boot volume attachment : %s\n%s", err, response) + } + + bootVol[isInstanceVolAttVolAutoDelete] = *bootVolumeAtt.DeleteVolumeOnInstanceDelete + options := &vpcv1.GetVolumeOptions{ + ID: instance.BootVolumeAttachment.Volume.ID, + } + vol, response, err := instanceC.GetVolume(options) + if err != nil { + log.Printf("[ERROR] Error Getting Boot Volume (%s): %s\n%s", id, err, response) + } + if vol != nil { + bootVol[isInstanceBootSize] = *vol.Capacity + bootVol[isInstanceBootIOPS] = *vol.Iops + bootVol[isInstanceBootProfile] = *vol.Profile.Name + if vol.EncryptionKey != nil { + bootVol[isInstanceBootEncryption] = *vol.EncryptionKey.CRN + } + if vol.SourceSnapshot != nil { + bootVol[isInstanceVolumeSnapshot] = vol.SourceSnapshot.ID + } + if vol.UserTags != nil { + bootVol[isInstanceBootVolumeTags] = vol.UserTags + } + } + } + bootVolList = append(bootVolList, bootVol) + d.Set(isInstanceBootVolume, bootVolList) + } + tags, err := flex.GetGlobalTagsUsingCRN(meta, *instance.CRN, "", isInstanceUserTagType) + if err != nil { + log.Printf( + "[ERROR] Error on get of resource Instance (%s) tags: %s", d.Id(), err) + } + d.Set(isInstanceTags, tags) + accesstags, err := flex.GetGlobalTagsUsingCRN(meta, *instance.CRN, "", isInstanceAccessTagType) + if err != nil { + log.Printf( + "[ERROR] Error on get of resource Instance (%s) access tags: %s", d.Id(), err) + } + d.Set(isInstanceAccessTags, accesstags) + controller, err := flex.GetBaseController(meta) + if err != nil { + return err + } + d.Set(flex.ResourceControllerURL, controller+"/vpc-ext/compute/vs") + d.Set(flex.ResourceName, *instance.Name) + d.Set(flex.ResourceCRN, *instance.CRN) + d.Set(IsInstanceCRN, *instance.CRN) + d.Set(flex.ResourceStatus, *instance.Status) + if instance.ResourceGroup != nil { + d.Set(isInstanceResourceGroup, *instance.ResourceGroup.ID) + d.Set(flex.ResourceGroupName, *instance.ResourceGroup.Name) + } + if instance.MetadataService != nil { + d.Set(isInstanceMetadataServiceEnabled, instance.MetadataService.Enabled) + metadataService := []map[string]interface{}{} + metadataServiceMap := map[string]interface{}{} + + metadataServiceMap[isInstanceMetadataServiceEnabled1] = instance.MetadataService.Enabled + if instance.MetadataService.Protocol != nil { + metadataServiceMap[isInstanceMetadataServiceProtocol] = instance.MetadataService.Protocol + } + if instance.MetadataService.ResponseHopLimit != nil { + metadataServiceMap[isInstanceMetadataServiceRespHopLimit] = instance.MetadataService.ResponseHopLimit + } + metadataService = append(metadataService, metadataServiceMap) + d.Set(isInstanceMetadataService, metadataService) + } + + if instance.Disks != nil { + disks := []map[string]interface{}{} + for _, disksItem := range instance.Disks { + disksItemMap := resourceIbmIsInstanceInstanceDiskToMap(disksItem) + disks = append(disks, disksItemMap) + } + if err = d.Set(isInstanceDisks, disks); err != nil { + return fmt.Errorf("[ERROR] Error setting disks: %s", err) + } + } + + placementTarget := []map[string]interface{}{} + if instance.PlacementTarget != nil { + placementTargetMap := resourceIbmIsInstanceInstancePlacementToMap(*instance.PlacementTarget.(*vpcv1.InstancePlacementTarget)) + placementTarget = append(placementTarget, placementTargetMap) + } + if err = d.Set(isInstancePlacementTarget, placementTarget); err != nil { + return fmt.Errorf("[ERROR] Error setting placement_target: %s", err) + } + return nil +} + +func instanceUpdate(d *schema.ResourceData, meta interface{}) error { + instanceC, err := vpcClient(meta) + if err != nil { + return err + } + id := d.Id() + // network attachments + + if d.HasChange("network_attachments") && !d.IsNewResource() { + nacs := d.Get("network_attachments").([]interface{}) + ots, nts := d.GetChange("network_attachments") + otsIntf := ots.([]interface{}) + ntsIntf := nts.([]interface{}) + out := make([]string, len(otsIntf)) + j := 0 + for _, currOtsG := range otsIntf { + currOts := currOtsG.(map[string]interface{}) + flag := false + for _, currNtsG := range ntsIntf { + currNts := currNtsG.(map[string]interface{}) + if currOts["id"].(string) == currNts["id"].(string) { + flag = true + } + } + if !flag { + log.Printf("[INFO] Nac with name (%s) will be deleted", currOts["name"].(string)) + nacId := currOts["id"] + if nacId != nil && nacId.(string) != "" { + nacIdStr := nacId.(string) + if !containsNacId(out, nacIdStr) { + out[j] = nacIdStr + j = j + 1 + deleteInstanceNetworkAttachmentOptions := &vpcv1.DeleteInstanceNetworkAttachmentOptions{ + InstanceID: &id, + ID: &nacIdStr, + } + res, err := instanceC.DeleteInstanceNetworkAttachment(deleteInstanceNetworkAttachmentOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error while deleting network attachment(%s) of instance(%s) \n%s: %q", nacIdStr, d.Id(), err, res) + } + } + } + } + } + + for i, nac := range nacs { + nacIdKey := fmt.Sprintf("network_attachments.%d.id", i) + nacId := d.Get(nacIdKey).(string) + // if nacId is empty, then create + // if nacId == "" || containsNacId(out, nacId) { + + if nacId == "" { + log.Printf("[DEBUG] nacId is empty") + allowipspoofing := fmt.Sprintf("network_attachments.%d.virtual_network_interface.0.allow_ip_spoofing", i) + autodelete := fmt.Sprintf("network_attachments.%d.virtual_network_interface.0.auto_delete", i) + enablenat := fmt.Sprintf("network_attachments.%d.virtual_network_interface.0.enable_infrastructure_nat", i) + nacMap := nac.(map[string]interface{}) + VirtualNetworkInterfaceModel, err := resourceIBMIsInstanceMapToVirtualNetworkInterfacePrototypeAttachmentContext(allowipspoofing, autodelete, enablenat, d, nacMap["virtual_network_interface"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return err + } + nacNameStr := nacMap["name"].(string) + createInstanceNetworkAttachmentOptions := &vpcv1.CreateInstanceNetworkAttachmentOptions{ + InstanceID: &id, + Name: &nacNameStr, + VirtualNetworkInterface: VirtualNetworkInterfaceModel, + } + _, res, err := instanceC.CreateInstanceNetworkAttachment(createInstanceNetworkAttachmentOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error while creating network attachment(%s) of instance(%s) \n%s: %q", nacNameStr, d.Id(), err, res) + } + } else { + log.Printf("[DEBUG] nacId is not empty") + nacName := fmt.Sprintf("network_attachments.%d.name", i) + nacVniName := fmt.Sprintf("network_attachments.%d.virtual_network_interface", i) + primaryipName := fmt.Sprintf("%s.%s", nacVniName, "0.primary_ip") + sgName := fmt.Sprintf("%s.%s", nacVniName, "0.security_groups") + if d.HasChange(nacName) { + networkName := d.Get(nacName).(string) + updateInstanceNetworkAttachmentOptions := &vpcv1.UpdateInstanceNetworkAttachmentOptions{ + InstanceID: &id, + ID: &nacId, + } + instanceNetworkAttachmentPatch := &vpcv1.InstanceNetworkAttachmentPatch{ + Name: &networkName, + } + instanceNetworkAttachmentPatchAsPatch, err := instanceNetworkAttachmentPatch.AsPatch() + if err != nil { + return (fmt.Errorf("[ERROR] Error encountered while apply as patch for instanceNetworkAttachmentPatchAsPatch of network attachment(%s) of instance(%s) %s", nacId, id, err)) + } + updateInstanceNetworkAttachmentOptions.InstanceNetworkAttachmentPatch = instanceNetworkAttachmentPatchAsPatch + _, res, err := instanceC.UpdateInstanceNetworkAttachment(updateInstanceNetworkAttachmentOptions) + if err != nil { + return (fmt.Errorf("[ERROR] Error encountered while updating network attachment(%s) name of instance(%s) %s/n%s", nacId, id, err, res)) + } + // output, err := json.MarshalIndent(updateInstanceNetworkAttachmentOptions, "", " ") + // if err == nil { + // log.Printf("%+v\n", string(output)) + // } else { + // log.Printf("Error : %#v", updateInstanceNetworkAttachmentOptions) + // } + } + if d.HasChange(nacVniName) { + vniId := d.Get(fmt.Sprintf("%s.%s", nacVniName, "0.id")).(string) + updateVirtualNetworkInterfaceOptions := &vpcv1.UpdateVirtualNetworkInterfaceOptions{ + ID: &vniId, + } + virtualNetworkInterfacePatch := &vpcv1.VirtualNetworkInterfacePatch{} + autoDeleteName := fmt.Sprintf("%s.%s", nacVniName, "0.auto_delete") + nameName := fmt.Sprintf("%s.%s", nacVniName, "0.name") + ipsName := fmt.Sprintf("%s.%s", nacVniName, "0.ips") + enableNatName := fmt.Sprintf("%s.%s", nacVniName, "0.enable_infrastructure_nat") + allowIpSpoofingName := fmt.Sprintf("%s.%s", nacVniName, "0.allow_ip_spoofing") + if d.HasChange(autoDeleteName) { + autodelete := d.Get(autoDeleteName).(bool) + virtualNetworkInterfacePatch.AutoDelete = &autodelete + } + if d.HasChange(nameName) { + name := d.Get(nameName).(string) + virtualNetworkInterfacePatch.Name = &name + } + if d.HasChange(enableNatName) { + enableNat := d.Get(enableNatName).(bool) + virtualNetworkInterfacePatch.EnableInfrastructureNat = &enableNat + } + if d.HasChange(allowIpSpoofingName) { + allIpSpoofing := d.Get(allowIpSpoofingName).(bool) + virtualNetworkInterfacePatch.AllowIPSpoofing = &allIpSpoofing + } + virtualNetworkInterfacePatchAsPatch, err := virtualNetworkInterfacePatch.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error encountered while apply as patch for virtualNetworkInterfacePatch of instance(%s) vni (%s) %s", d.Id(), vniId, err) + } + updateVirtualNetworkInterfaceOptions.VirtualNetworkInterfacePatch = virtualNetworkInterfacePatchAsPatch + _, response, err := instanceC.UpdateVirtualNetworkInterface(updateVirtualNetworkInterfaceOptions) + if err != nil { + log.Printf("[DEBUG] UpdateVirtualNetworkInterfaceWithContext failed %s\n%s", err, response) + return fmt.Errorf("UpdateVirtualNetworkInterfaceWithContext failed during instance(%s) network attachment patch %s\n%s", d.Id(), err, response) + } + + if d.HasChange(ipsName) { + oldips, newips := d.GetChange(ipsName) + os := oldips.(*schema.Set) + ns := newips.(*schema.Set) + var oldset, newset *schema.Set + + var out = make([]interface{}, ns.Len(), ns.Len()) + for i, nA := range ns.List() { + newPack := nA.(map[string]interface{}) + out[i] = newPack["reserved_ip"].(string) + } + newset = schema.NewSet(schema.HashString, out) + + out = make([]interface{}, os.Len(), os.Len()) + for i, oA := range os.List() { + oldPack := oA.(map[string]interface{}) + out[i] = oldPack["reserved_ip"].(string) + } + oldset = schema.NewSet(schema.HashString, out) + + remove := flex.ExpandStringList(oldset.Difference(newset).List()) + add := flex.ExpandStringList(newset.Difference(oldset).List()) + + if add != nil && len(add) > 0 { + for _, ipItem := range add { + if ipItem != "" { + addVirtualNetworkInterfaceIPOptions := &vpcv1.AddVirtualNetworkInterfaceIPOptions{} + addVirtualNetworkInterfaceIPOptions.SetVirtualNetworkInterfaceID(vniId) + addVirtualNetworkInterfaceIPOptions.SetID(ipItem) + _, response, err := instanceC.AddVirtualNetworkInterfaceIP(addVirtualNetworkInterfaceIPOptions) + if err != nil { + log.Printf("[DEBUG] AddVirtualNetworkInterfaceIPWithContext failed in VirtualNetworkInterface patch during instance nac patch %s\n%s", err, response) + return fmt.Errorf("AddVirtualNetworkInterfaceIPWithContext failed in VirtualNetworkInterface patch during instance nac patch %s\n%s", err, response) + } + } + } + } + if remove != nil && len(remove) > 0 { + for _, ipItem := range remove { + if ipItem != "" { + removeVirtualNetworkInterfaceIPOptions := &vpcv1.RemoveVirtualNetworkInterfaceIPOptions{} + removeVirtualNetworkInterfaceIPOptions.SetVirtualNetworkInterfaceID(vniId) + removeVirtualNetworkInterfaceIPOptions.SetID(ipItem) + response, err := instanceC.RemoveVirtualNetworkInterfaceIP(removeVirtualNetworkInterfaceIPOptions) + if err != nil { + log.Printf("[DEBUG] RemoveVirtualNetworkInterfaceIPWithContext failed in VirtualNetworkInterface patch during instance nac patch %s\n%s", err, response) + return fmt.Errorf("RemoveVirtualNetworkInterfaceIPWithContext failed in VirtualNetworkInterface patch during instance nac patch %s\n%s", err, response) + } + } + } + } + } + + if d.HasChange(primaryipName) { + subnetIdName := fmt.Sprintf("%s.%s", nacVniName, "0.subnet") + ripIdName := fmt.Sprintf("%s.%s", primaryipName, "0.reserved_ip") + subnetId := d.Get(subnetIdName).(string) + primaryipNameName := fmt.Sprintf("%s.%s", primaryipName, "0.name") + primaryipAutoDeleteName := fmt.Sprintf("%s.%s", primaryipName, "0.name") + ripId := d.Get(ripIdName).(string) + updateripoptions := &vpcv1.UpdateSubnetReservedIPOptions{ + SubnetID: &subnetId, + ID: &ripId, + } + reservedIpPath := &vpcv1.ReservedIPPatch{} + if d.HasChange(primaryipNameName) { + name := d.Get(primaryipNameName).(string) + reservedIpPath.Name = &name + } + if d.HasChange(primaryipAutoDeleteName) { + auto := d.Get(primaryipAutoDeleteName).(bool) + reservedIpPath.AutoDelete = &auto + } + reservedIpPathAsPatch, err := reservedIpPath.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error calling reserved ip as patch on vni patch \n%s", err) + } + updateripoptions.ReservedIPPatch = reservedIpPathAsPatch + _, response, err := instanceC.UpdateSubnetReservedIP(updateripoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error updating vni reserved ip(%s): %s\n%s", ripId, err, response) + } + } + if d.HasChange(sgName) { + ovs, nvs := d.GetChange(sgName) + ov := ovs.(*schema.Set) + nv := nvs.(*schema.Set) + remove := flex.ExpandStringList(ov.Difference(nv).List()) + add := flex.ExpandStringList(nv.Difference(ov).List()) + if len(add) > 0 { + for i := range add { + createsgnicoptions := &vpcv1.CreateSecurityGroupTargetBindingOptions{ + SecurityGroupID: &add[i], + ID: &vniId, + } + _, response, err := instanceC.CreateSecurityGroupTargetBinding(createsgnicoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error while creating security group %q for virtual network interface %s\n%s: %q", add[i], vniId, err, response) + } + _, err = isWaitForVirtualNetworkInterfaceAvailable(instanceC, vniId, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return err + } + } + + } + if len(remove) > 0 { + for i := range remove { + deletesgnicoptions := &vpcv1.DeleteSecurityGroupTargetBindingOptions{ + SecurityGroupID: &remove[i], + ID: &vniId, + } + response, err := instanceC.DeleteSecurityGroupTargetBinding(deletesgnicoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error while removing security group %q for virtual network interface %s\n%s: %q", remove[i], d.Id(), err, response) + } + _, err = isWaitForVirtualNetworkInterfaceAvailable(instanceC, vniId, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return err + } + } + } + } + + } + + } + // } + } + + } + + //primary_network_attachment + if d.HasChange("primary_network_attachment") && !d.IsNewResource() { + networkID := d.Get("primary_network_attachment.0.id").(string) + networkName := "primary_network_attachment.0.name" + nacVniName := "primary_network_attachment.0.virtual_network_interface" + if d.HasChange(networkName) { + networkNameString := d.Get(networkName).(string) + updateInstanceNetworkAttachmentOptions := &vpcv1.UpdateInstanceNetworkAttachmentOptions{ + InstanceID: &id, + ID: &networkID, + } + instanceNetworkAttachmentPatch := &vpcv1.InstanceNetworkAttachmentPatch{ + Name: &networkNameString, + } + instanceNetworkAttachmentPatchAsPatch, err := instanceNetworkAttachmentPatch.AsPatch() + if err != nil { + return (fmt.Errorf("[ERROR] Error encountered while apply as patch for instanceNetworkAttachmentPatchAsPatch of pna of instance(%s) %s", id, err)) + } + updateInstanceNetworkAttachmentOptions.InstanceNetworkAttachmentPatch = instanceNetworkAttachmentPatchAsPatch + _, res, err := instanceC.UpdateInstanceNetworkAttachment(updateInstanceNetworkAttachmentOptions) + if err != nil { + return (fmt.Errorf("[ERROR] Error encountered while updating pna name of instance(%s) %s/n%s", id, err, res)) + } + } + if d.HasChange(nacVniName) { + vniId := d.Get(fmt.Sprintf("%s.%s", nacVniName, "0.id")).(string) + updateVirtualNetworkInterfaceOptions := &vpcv1.UpdateVirtualNetworkInterfaceOptions{ + ID: &vniId, + } + virtualNetworkInterfacePatch := &vpcv1.VirtualNetworkInterfacePatch{} + autoDeleteName := fmt.Sprintf("%s.%s", nacVniName, "0.auto_delete") + nameName := fmt.Sprintf("%s.%s", nacVniName, "0.name") + ipsName := fmt.Sprintf("%s.%s", nacVniName, "0.ips") + primaryipName := fmt.Sprintf("%s.%s", nacVniName, "0.primary_ip") + sgName := fmt.Sprintf("%s.%s", nacVniName, "0.security_groups") + enableNatName := fmt.Sprintf("%s.%s", nacVniName, "0.enable_infrastructure_nat") + allowIpSpoofingName := fmt.Sprintf("%s.%s", nacVniName, "0.allow_ip_spoofing") + if d.HasChange(autoDeleteName) { + autodelete := d.Get(autoDeleteName).(bool) + virtualNetworkInterfacePatch.AutoDelete = &autodelete + } + if d.HasChange(nameName) { + name := d.Get(nameName).(string) + virtualNetworkInterfacePatch.Name = &name + } + if d.HasChange(enableNatName) { + enableNat := d.Get(enableNatName).(bool) + virtualNetworkInterfacePatch.EnableInfrastructureNat = &enableNat + } + if d.HasChange(allowIpSpoofingName) { + allIpSpoofing := d.Get(allowIpSpoofingName).(bool) + virtualNetworkInterfacePatch.AllowIPSpoofing = &allIpSpoofing + } + virtualNetworkInterfacePatchAsPatch, err := virtualNetworkInterfacePatch.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error encountered while apply as patch for virtualNetworkInterfacePatch of instance(%s) vni (%s) %s", d.Id(), vniId, err) + } + updateVirtualNetworkInterfaceOptions.VirtualNetworkInterfacePatch = virtualNetworkInterfacePatchAsPatch + _, response, err := instanceC.UpdateVirtualNetworkInterface(updateVirtualNetworkInterfaceOptions) + if err != nil { + log.Printf("[DEBUG] UpdateVirtualNetworkInterfaceWithContext failed %s\n%s", err, response) + return fmt.Errorf("UpdateVirtualNetworkInterfaceWithContext failed during instance(%s) network attachment patch %s\n%s", d.Id(), err, response) + } + + if d.HasChange(ipsName) { + oldips, newips := d.GetChange(ipsName) + os := oldips.(*schema.Set) + ns := newips.(*schema.Set) + var oldset, newset *schema.Set + + var out = make([]interface{}, ns.Len(), ns.Len()) + for i, nA := range ns.List() { + newPack := nA.(map[string]interface{}) + out[i] = newPack["reserved_ip"].(string) + } + newset = schema.NewSet(schema.HashString, out) + + out = make([]interface{}, os.Len(), os.Len()) + for i, oA := range os.List() { + oldPack := oA.(map[string]interface{}) + out[i] = oldPack["reserved_ip"].(string) + } + oldset = schema.NewSet(schema.HashString, out) + + remove := flex.ExpandStringList(oldset.Difference(newset).List()) + add := flex.ExpandStringList(newset.Difference(oldset).List()) + + if add != nil && len(add) > 0 { + for _, ipItem := range add { + if ipItem != "" { + addVirtualNetworkInterfaceIPOptions := &vpcv1.AddVirtualNetworkInterfaceIPOptions{} + addVirtualNetworkInterfaceIPOptions.SetVirtualNetworkInterfaceID(vniId) + addVirtualNetworkInterfaceIPOptions.SetID(ipItem) + _, response, err := instanceC.AddVirtualNetworkInterfaceIP(addVirtualNetworkInterfaceIPOptions) + if err != nil { + log.Printf("[DEBUG] AddVirtualNetworkInterfaceIPWithContext failed in VirtualNetworkInterface patch during instance nac patch %s\n%s", err, response) + return fmt.Errorf("AddVirtualNetworkInterfaceIPWithContext failed in VirtualNetworkInterface patch during instance nac patch %s\n%s", err, response) + } + } + } + } + if remove != nil && len(remove) > 0 { + for _, ipItem := range remove { + if ipItem != "" { + removeVirtualNetworkInterfaceIPOptions := &vpcv1.RemoveVirtualNetworkInterfaceIPOptions{} + removeVirtualNetworkInterfaceIPOptions.SetVirtualNetworkInterfaceID(vniId) + removeVirtualNetworkInterfaceIPOptions.SetID(ipItem) + response, err := instanceC.RemoveVirtualNetworkInterfaceIP(removeVirtualNetworkInterfaceIPOptions) + if err != nil { + log.Printf("[DEBUG] RemoveVirtualNetworkInterfaceIPWithContext failed in VirtualNetworkInterface patch during instance nac patch %s\n%s", err, response) + return fmt.Errorf("RemoveVirtualNetworkInterfaceIPWithContext failed in VirtualNetworkInterface patch during instance nac patch %s\n%s", err, response) + } + } + } + } + } + + if d.HasChange(primaryipName) { + subnetIdName := fmt.Sprintf("%s.%s", nacVniName, "0.subnet") + ripIdName := fmt.Sprintf("%s.%s", primaryipName, "0.reserved_ip") + subnetId := d.Get(subnetIdName).(string) + primaryipNameName := fmt.Sprintf("%s.%s", primaryipName, "0.name") + primaryipAutoDeleteName := fmt.Sprintf("%s.%s", primaryipName, "0.name") + ripId := d.Get(ripIdName).(string) + updateripoptions := &vpcv1.UpdateSubnetReservedIPOptions{ + SubnetID: &subnetId, + ID: &ripId, + } + reservedIpPath := &vpcv1.ReservedIPPatch{} + if d.HasChange(primaryipNameName) { + name := d.Get(primaryipNameName).(string) + reservedIpPath.Name = &name + } + if d.HasChange(primaryipAutoDeleteName) { + auto := d.Get(primaryipAutoDeleteName).(bool) + reservedIpPath.AutoDelete = &auto + } + reservedIpPathAsPatch, err := reservedIpPath.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error calling reserved ip as patch on vni patch \n%s", err) + } + updateripoptions.ReservedIPPatch = reservedIpPathAsPatch + _, response, err := instanceC.UpdateSubnetReservedIP(updateripoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error updating vni reserved ip(%s): %s\n%s", ripId, err, response) + } + } + if d.HasChange(sgName) { + ovs, nvs := d.GetChange(sgName) + ov := ovs.(*schema.Set) + nv := nvs.(*schema.Set) + remove := flex.ExpandStringList(ov.Difference(nv).List()) + add := flex.ExpandStringList(nv.Difference(ov).List()) + if len(add) > 0 { + for i := range add { + createsgnicoptions := &vpcv1.CreateSecurityGroupTargetBindingOptions{ + SecurityGroupID: &add[i], + ID: &vniId, + } + _, response, err := instanceC.CreateSecurityGroupTargetBinding(createsgnicoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error while creating security group %q for virtual network interface %s\n%s: %q", add[i], vniId, err, response) + } + _, err = isWaitForVirtualNetworkInterfaceAvailable(instanceC, vniId, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return err + } + } + + } + if len(remove) > 0 { + for i := range remove { + deletesgnicoptions := &vpcv1.DeleteSecurityGroupTargetBindingOptions{ + SecurityGroupID: &remove[i], + ID: &vniId, + } + response, err := instanceC.DeleteSecurityGroupTargetBinding(deletesgnicoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error while removing security group %q for virtual network interface %s\n%s: %q", remove[i], d.Id(), err, response) + } + _, err = isWaitForVirtualNetworkInterfaceAvailable(instanceC, vniId, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return err + } + } + } } + } - d.Set(isInstanceStatusReasons, statusReasonsList) - } - //set the lifecycle status, reasons - if instance.LifecycleState != nil { - d.Set(isInstanceLifecycleState, *instance.LifecycleState) - } - if instance.LifecycleReasons != nil { - d.Set(isInstanceLifecycleReasons, dataSourceInstanceFlattenLifecycleReasons(instance.LifecycleReasons)) } - d.Set(isInstanceVPC, *instance.VPC.ID) - d.Set(isInstanceZone, *instance.Zone.Name) + resPol := "reservation_affinity.0.policy" + resPool := "reservation_affinity.0.pool" - if instance.VolumeAttachments != nil { - volList := make([]map[string]interface{}, 0) - for _, volume := range instance.VolumeAttachments { - vol := map[string]interface{}{} - if volume.Volume != 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 - volList = append(volList, vol) + if (d.HasChange(resPol) || d.HasChange(resPool)) && !d.IsNewResource() { + if resAffinity, ok := d.GetOk(isReservationAffinity); ok { + getinsOptions := &vpcv1.GetInstanceOptions{ + ID: &id, } - } - d.Set(isInstanceVolumeAttachments, volList) - } + _, response, err := instanceC.GetInstance(getinsOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error getting instance (%s): %s\n%s", id, err, response) + } + eTag := response.Headers.Get("ETag") + + resAff := resAffinity.([]interface{})[0].(map[string]interface{}) + var resAffinityPatch = &vpcv1.InstanceReservationAffinityPatch{} + policy, ok := resAff["policy"] + policyStr := policy.(string) + idStr := "" + if policyStr != "" && ok { + resAffinityPatch.Policy = &policyStr + } + if d.HasChange(resPool) { + poolIntf, okPool := resAff[isReservationAffinityPool] + if okPool { + 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 instance.BootVolumeAttachment != nil { - bootVolList := make([]map[string]interface{}, 0) - bootVol := map[string]interface{}{} - if instance.BootVolumeAttachment.Volume != nil { - bootVol[isInstanceBootAttachmentName] = *instance.BootVolumeAttachment.Volume.Name - bootVol[isInstanceBootVolumeId] = *instance.BootVolumeAttachment.Volume.ID + } + } - instanceId := *instance.ID - bootVolID := *instance.BootVolumeAttachment.ID - getinsVolAttOptions := &vpcv1.GetInstanceVolumeAttachmentOptions{ - InstanceID: &instanceId, - ID: &bootVolID, + instancePatchModel := &vpcv1.InstancePatch{ + ReservationAffinity: resAffinityPatch, } - bootVolumeAtt, response, err := instanceC.GetInstanceVolumeAttachment(getinsVolAttOptions) + mpatch, err := instancePatchModel.AsPatch() if err != nil { - return fmt.Errorf("[ERROR] Error getting Instance boot volume attachment : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error calling asPatch with reservation affinity: %s", err) } - - bootVol[isInstanceVolAttVolAutoDelete] = *bootVolumeAtt.DeleteVolumeOnInstanceDelete - options := &vpcv1.GetVolumeOptions{ - ID: instance.BootVolumeAttachment.Volume.ID, + //Detaching the reservation from the reserved instance + if policyStr == "disabled" && idStr == "" { + resAffMap := mpatch["reservation_affinity"].(map[string]interface{}) + resAffMap["pool"] = nil + mpatch["reservation_affinity"] = resAffMap } - vol, response, err := instanceC.GetVolume(options) - if err != nil { - log.Printf("Error Getting Boot Volume (%s): %s\n%s", id, err, response) + param := &vpcv1.UpdateInstanceOptions{ + InstancePatch: mpatch, + ID: &id, } - if vol != nil { - bootVol[isInstanceBootSize] = *vol.Capacity - bootVol[isInstanceBootIOPS] = *vol.Iops - bootVol[isInstanceBootProfile] = *vol.Profile.Name - if vol.EncryptionKey != nil { - bootVol[isInstanceBootEncryption] = *vol.EncryptionKey.CRN - } - if vol.SourceSnapshot != nil { - bootVol[isInstanceVolumeSnapshot] = vol.SourceSnapshot.ID - } - if vol.UserTags != nil { - bootVol[isInstanceBootVolumeTags] = vol.UserTags - } + param.IfMatch = &eTag + _, _, err = instanceC.UpdateInstance(param) + if err != nil { + return err } } - bootVolList = append(bootVolList, bootVol) - d.Set(isInstanceBootVolume, bootVolList) - } - tags, err := flex.GetGlobalTagsUsingCRN(meta, *instance.CRN, "", isInstanceUserTagType) - if err != nil { - log.Printf( - "Error on get of resource Instance (%s) tags: %s", d.Id(), err) - } - d.Set(isInstanceTags, tags) - accesstags, err := flex.GetGlobalTagsUsingCRN(meta, *instance.CRN, "", isInstanceAccessTagType) - if err != nil { - log.Printf( - "Error on get of resource Instance (%s) access tags: %s", d.Id(), err) - } - d.Set(isInstanceAccessTags, accesstags) - controller, err := flex.GetBaseController(meta) - if err != nil { - return err - } - d.Set(flex.ResourceControllerURL, controller+"/vpc-ext/compute/vs") - d.Set(flex.ResourceName, *instance.Name) - d.Set(flex.ResourceCRN, *instance.CRN) - d.Set(IsInstanceCRN, *instance.CRN) - d.Set(flex.ResourceStatus, *instance.Status) - if instance.ResourceGroup != nil { - d.Set(isInstanceResourceGroup, *instance.ResourceGroup.ID) - d.Set(flex.ResourceGroupName, *instance.ResourceGroup.Name) - } - if instance.MetadataService != nil { - d.Set(isInstanceMetadataServiceEnabled, instance.MetadataService.Enabled) - metadataService := []map[string]interface{}{} - metadataServiceMap := map[string]interface{}{} - - metadataServiceMap[isInstanceMetadataServiceEnabled1] = instance.MetadataService.Enabled - if instance.MetadataService.Protocol != nil { - metadataServiceMap[isInstanceMetadataServiceProtocol] = instance.MetadataService.Protocol - } - if instance.MetadataService.ResponseHopLimit != nil { - metadataServiceMap[isInstanceMetadataServiceRespHopLimit] = instance.MetadataService.ResponseHopLimit - } - metadataService = append(metadataService, metadataServiceMap) - d.Set(isInstanceMetadataService, metadataService) - } - - if instance.Disks != nil { - disks := []map[string]interface{}{} - for _, disksItem := range instance.Disks { - disksItemMap := resourceIbmIsInstanceInstanceDiskToMap(disksItem) - disks = append(disks, disksItemMap) - } - if err = d.Set(isInstanceDisks, disks); err != nil { - return fmt.Errorf("[ERROR] Error setting disks: %s", err) - } - } - - placementTarget := []map[string]interface{}{} - if instance.PlacementTarget != nil { - placementTargetMap := resourceIbmIsInstanceInstancePlacementToMap(*instance.PlacementTarget.(*vpcv1.InstancePlacementTarget)) - placementTarget = append(placementTarget, placementTargetMap) - } - if err = d.Set(isInstancePlacementTarget, placementTarget); err != nil { - return fmt.Errorf("[ERROR] Error setting placement_target: %s", err) - } - return nil -} - -func instanceUpdate(d *schema.ResourceData, meta interface{}) error { - instanceC, err := vpcClient(meta) - if err != nil { - return err } - id := d.Id() bootVolSize := "boot_volume.0.size" if d.HasChange(bootVolSize) && !d.IsNewResource() { @@ -3545,6 +5030,30 @@ func instanceUpdate(d *schema.ResourceData, meta interface{}) error { } } } + bootVolName := "boot_volume.0.name" + if d.HasChange(bootVolName) && !d.IsNewResource() { + volId := d.Get("boot_volume.0.volume_id").(string) + volName := d.Get(bootVolName).(string) + updateVolumeOptions := &vpcv1.UpdateVolumeOptions{ + ID: &volId, + } + volPatchModel := &vpcv1.VolumePatch{ + Name: &volName, + } + volPatchModelAsPatch, err := volPatchModel.AsPatch() + + if err != nil { + return (fmt.Errorf("[ERROR] Error encountered while apply as patch for boot volume name update of instance %s", err)) + } + + updateVolumeOptions.VolumePatch = volPatchModelAsPatch + + vol, res, err := instanceC.UpdateVolume(updateVolumeOptions) + + if vol == nil || err != nil { + return (fmt.Errorf("[ERROR] Error encountered while updating name of boot volume of instance %s/n%s", err, res)) + } + } bootVolAutoDel := "boot_volume.0.auto_delete_volume" if d.HasChange(bootVolAutoDel) && !d.IsNewResource() { listvolattoptions := &vpcv1.ListInstanceVolumeAttachmentsOptions{ @@ -4035,7 +5544,7 @@ func instanceUpdate(d *schema.ResourceData, meta interface{}) error { } instancePatch, err := instancePatchModel.AsPatch() if err != nil { - return fmt.Errorf("Error calling asPatch for InstancePatch: %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for InstancePatch: %s", err) } updatedoptions.InstancePatch = instancePatch @@ -4078,7 +5587,7 @@ func instanceUpdate(d *schema.ResourceData, meta interface{}) error { instancePatch, err := instancePatchModel.AsPatch() if err != nil { - return fmt.Errorf("Error calling asPatch for InstancePatch: %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for InstancePatch: %s", err) } updatedoptions.InstancePatch = instancePatch @@ -4101,7 +5610,7 @@ func instanceUpdate(d *schema.ResourceData, meta interface{}) error { } instancePatch, err := instancePatchModel.AsPatch() if err != nil { - return fmt.Errorf("Error calling asPatch for InstancePatch: %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for InstancePatch: %s", err) } updatedoptions.InstancePatch = instancePatch @@ -4197,7 +5706,7 @@ func instanceUpdate(d *schema.ResourceData, meta interface{}) error { err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *instance.CRN) if err != nil { log.Printf( - "Error on update of resource Instance (%s) tags: %s", d.Id(), err) + "[ERROR] Error on update of resource Instance (%s) tags: %s", d.Id(), err) } } if d.HasChange(isInstanceAccessTags) { @@ -4205,7 +5714,7 @@ func instanceUpdate(d *schema.ResourceData, meta interface{}) error { err = flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, *instance.CRN, "", isInstanceAccessTagType) if err != nil { log.Printf( - "Error on update of resource Instance (%s) access tags: %s", d.Id(), err) + "[ERROR] Error on update of resource Instance (%s) access tags: %s", d.Id(), err) } } return nil @@ -4586,6 +6095,15 @@ 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.DedicatedHostGroupReferenceDeleted) map[string]interface{} { dedicatedHostGroupReferenceDeletedMap := map[string]interface{}{} @@ -4619,3 +6137,231 @@ func GetInstanceMetadataServiceOptions(d *schema.ResourceData) (metadataService } return nil } + +func resourceIBMIsInstanceInstanceNetworkAttachmentReferenceToMap(model *vpcv1.InstanceNetworkAttachmentReference, pna *vpcv1.InstanceNetworkAttachment, instanceC *vpcv1.VpcV1, autoDelete bool) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Deleted != nil { + deletedMap, err := resourceIBMIsInstanceInstanceNetworkAttachmentReferenceDeletedToMap(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 + } + vniMap := make(map[string]interface{}) + if pna.VirtualNetworkInterface != nil { + vniMap["id"] = *pna.VirtualNetworkInterface.ID + vniMap["name"] = pna.VirtualNetworkInterface.Name + vniMap["resource_type"] = pna.VirtualNetworkInterface.ResourceType + } + getVirtualNetworkInterfaceOptions := &vpcv1.GetVirtualNetworkInterfaceOptions{ + ID: pna.VirtualNetworkInterface.ID, + } + vniDetails, response, err := instanceC.GetVirtualNetworkInterface(getVirtualNetworkInterfaceOptions) + if err != nil { + return nil, fmt.Errorf("[ERROR] Error on GetInstanceNetworkAttachment in instance : %s\n%s", err, response) + } + vniMap["allow_ip_spoofing"] = vniDetails.AllowIPSpoofing + vniMap["auto_delete"] = vniDetails.AutoDelete + vniMap["enable_infrastructure_nat"] = vniDetails.EnableInfrastructureNat + vniMap["resource_group"] = vniDetails.ResourceGroup.ID + primaryipId := *vniDetails.PrimaryIP.ID + if !core.IsNil(vniDetails.Ips) { + ips := []map[string]interface{}{} + for _, ipsItem := range vniDetails.Ips { + if *ipsItem.ID != primaryipId { + ipsItemMap, err := resourceIBMIsVirtualNetworkInterfaceReservedIPReferenceToMap(&ipsItem, autoDelete) + if err != nil { + return nil, err + } + ips = append(ips, ipsItemMap) + } + } + vniMap["ips"] = ips + } + + if !core.IsNil(vniDetails.SecurityGroups) { + securityGroups := make([]string, 0) + for _, securityGroupsItem := range vniDetails.SecurityGroups { + if securityGroupsItem.ID != nil { + securityGroups = append(securityGroups, *securityGroupsItem.ID) + } + } + vniMap["security_groups"] = securityGroups + } + primaryIPMap, err := resourceIBMIsInstanceReservedIPReferenceToMap(model.PrimaryIP, autoDelete) + if err != nil { + return modelMap, err + } + vniMap["primary_ip"] = []map[string]interface{}{primaryIPMap} + if model.ResourceType != nil { + modelMap["resource_type"] = *model.ResourceType + } + if model.Subnet != nil { + vniMap["subnet"] = *model.Subnet.ID + } + modelMap["virtual_network_interface"] = []map[string]interface{}{vniMap} + return modelMap, nil +} + +func resourceIBMIsInstanceInstanceNetworkAttachmentReferenceDeletedToMap(model *vpcv1.InstanceNetworkAttachmentReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = model.MoreInfo + return modelMap, nil +} + +func resourceIBMIsInstanceReservedIPReferenceToMap(model *vpcv1.ReservedIPReference, autoDelete bool) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["address"] = model.Address + if model.Deleted != nil { + deletedMap, err := resourceIBMIsInstanceReservedIPReferenceDeletedToMap(model.Deleted) + if err != nil { + return modelMap, err + } + modelMap["deleted"] = []map[string]interface{}{deletedMap} + } + modelMap["href"] = model.Href + modelMap["auto_delete"] = autoDelete + modelMap["reserved_ip"] = model.ID + modelMap["name"] = model.Name + if model.ResourceType != nil { + modelMap["resource_type"] = *model.ResourceType + } + return modelMap, nil +} + +func resourceIBMIsInstanceReservedIPReferenceDeletedToMap(model *vpcv1.ReservedIPReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = model.MoreInfo + return modelMap, nil +} + +func resourceIBMIsInstanceMapToInstanceNetworkAttachmentPrototype(allowipspoofing, autodelete, enablenat string, d *schema.ResourceData, modelMap map[string]interface{}) (*vpcv1.InstanceNetworkAttachmentPrototype, error) { + model := &vpcv1.InstanceNetworkAttachmentPrototype{} + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + VirtualNetworkInterfaceModel, err := resourceIBMIsInstanceMapToVirtualNetworkInterfacePrototypeAttachmentContext(allowipspoofing, autodelete, enablenat, d, modelMap["virtual_network_interface"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.VirtualNetworkInterface = VirtualNetworkInterfaceModel + return model, nil +} +func resourceIBMIsInstanceMapToVirtualNetworkInterfacePrototypeAttachmentContext(allowipspoofing, autodelete, enablenat string, d *schema.ResourceData, modelMap map[string]interface{}) (vpcv1.InstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceIntf, error) { + model := &vpcv1.InstanceNetworkAttachmentPrototypeVirtualNetworkInterface{} + if allowipspoofingOk, ok := d.GetOkExists(allowipspoofing); ok { + model.AllowIPSpoofing = core.BoolPtr(allowipspoofingOk.(bool)) + } + if autodeleteOk, ok := d.GetOkExists(autodelete); ok { + model.AutoDelete = core.BoolPtr(autodeleteOk.(bool)) + } + if enablenatok, ok := d.GetOkExists(enablenat); ok { + model.EnableInfrastructureNat = core.BoolPtr(enablenatok.(bool)) + } + if modelMap["ips"] != nil { + ips := []vpcv1.VirtualNetworkInterfaceIPPrototypeIntf{} + for _, ipsItem := range modelMap["ips"].(*schema.Set).List() { + ipsItemModel, err := resourceIBMIsInstanceMapToVirtualNetworkInterfaceIPsReservedIPPrototype(ipsItem.(map[string]interface{})) + if err != nil { + return model, err + } + ips = append(ips, ipsItemModel) + } + model.Ips = ips + } + 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 := resourceIBMIsInstanceMapToVirtualNetworkInterfacePrimaryIPReservedIPPrototype(modelMap["primary_ip"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.PrimaryIP = PrimaryIPModel + } + if modelMap["resource_group"] != nil && modelMap["resource_group"].(string) != "" { + resourcegroupid := modelMap["resource_group"].(string) + model.ResourceGroup = &vpcv1.ResourceGroupIdentity{ + ID: &resourcegroupid, + } + } + if modelMap["security_groups"] != nil { + securityGroups := []vpcv1.SecurityGroupIdentityIntf{} + sg := modelMap["security_groups"].(*schema.Set) + for _, v := range sg.List() { + value := v.(string) + securityGroupsItem := &vpcv1.SecurityGroupIdentity{ + ID: &value, + } + securityGroups = append(securityGroups, securityGroupsItem) + } + model.SecurityGroups = securityGroups + } + if modelMap["subnet"] != nil && modelMap["subnet"].(string) != "" { + subnetId := modelMap["subnet"].(string) + model.Subnet = &vpcv1.SubnetIdentityByID{ + ID: &subnetId, + } + } + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + return model, nil +} + +func resourceIBMIsInstanceMapToVirtualNetworkInterfaceIPsReservedIPPrototype(modelMap map[string]interface{}) (vpcv1.VirtualNetworkInterfaceIPPrototypeIntf, error) { + model := &vpcv1.VirtualNetworkInterfaceIPPrototype{} + if modelMap["reserved_ip"] != nil && modelMap["reserved_ip"].(string) != "" { + model.ID = core.StringPtr(modelMap["reserved_ip"].(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 resourceIBMIsInstanceMapToVirtualNetworkInterfacePrimaryIPReservedIPPrototype(modelMap map[string]interface{}) (vpcv1.VirtualNetworkInterfacePrimaryIPPrototypeIntf, error) { + model := &vpcv1.VirtualNetworkInterfacePrimaryIPPrototype{} + if modelMap["reserved_ip"] != nil && modelMap["reserved_ip"].(string) != "" { + model.ID = core.StringPtr(modelMap["reserved_ip"].(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 containsNacId(s []string, e string) bool { + for _, a := range s { + if a == e { + return true + } + } + return false +} diff --git a/ibm/service/vpc/resource_ibm_is_instance_network_attachment.go b/ibm/service/vpc/resource_ibm_is_instance_network_attachment.go new file mode 100644 index 0000000000..0a0c1ae4a6 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_instance_network_attachment.go @@ -0,0 +1,1063 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "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 ResourceIBMIsInstanceNetworkAttachment() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMIsInstanceNetworkAttachmentCreate, + ReadContext: resourceIBMIsInstanceNetworkAttachmentRead, + UpdateContext: resourceIBMIsInstanceNetworkAttachmentUpdate, + DeleteContext: resourceIBMIsInstanceNetworkAttachmentDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "instance": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_is_instance_network_attachment", "instance"), + Description: "The virtual server instance identifier.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_instance_network_attachment", "name"), + Description: "The name for this instance network attachment. The name is unique across all network attachments for the instance.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the instance network attachment was created.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this instance network attachment.", + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the instance network attachment.", + }, + "port_speed": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The port speed for this instance network attachment in Mbps.", + }, + + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The instance network attachment type.", + }, + "network_attachment": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this instance network attachment.", + }, + // vni properties + "virtual_network_interface": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "A virtual network interface for the instance network attachment. This can be specified using an existing virtual network interface, or a prototype object for a new virtual network interface.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ConflictsWith: []string{"virtual_network_interface.0.allow_ip_spoofing", "virtual_network_interface.0.auto_delete", "virtual_network_interface.0.enable_infrastructure_nat", "virtual_network_interface.0.ips", "virtual_network_interface.0.name", "virtual_network_interface.0.primary_ip", "virtual_network_interface.0.resource_group", "virtual_network_interface.0.security_groups", "virtual_network_interface.0.security_groups"}, + Description: "The virtual network interface id for this instance network attachment.", + }, + "allow_ip_spoofing": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + ConflictsWith: []string{"virtual_network_interface.0.id"}, + Description: "Indicates whether source IP spoofing is allowed on this interface. If `false`, source IP spoofing is prevented on this interface. If `true`, source IP spoofing is allowed on this interface.", + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + ConflictsWith: []string{"virtual_network_interface.0.id"}, + Description: "Indicates whether this virtual network interface will be automatically deleted when`target` is deleted.", + }, + "enable_infrastructure_nat": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + ConflictsWith: []string{"virtual_network_interface.0.id"}, + 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 network interface, allowing the workload to perform any needed NAT operations.- `allow_ip_spoofing` must be `false`.- If the virtual network interface is attached: - The target `resource_type` must be `bare_metal_server_network_attachment`. - The target `interface_type` must not be `hipersocket`.", + }, + "ips": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Computed: true, + Set: hashIpsList, + ConflictsWith: []string{"virtual_network_interface.0.id"}, + Description: "The reserved IPs bound to this virtual network interface.May be empty when `lifecycle_state` is `pending`.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + // Optional: true, + Computed: true, + Description: "The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "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.", + }, + }, + }, + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + // Optional: true, + Computed: true, + Description: "Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP.", + }, + "reserved_ip": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + // Optional: true, + Computed: true, + Description: "The name for this reserved IP. The name is unique across all reserved IPs in a subnet.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ConflictsWith: []string{"virtual_network_interface.0.id"}, + ValidateFunc: validate.InvokeValidator("ibm_is_virtual_network_interface", "name"), + Description: "The name for this virtual network interface. The name is unique across all virtual network interfaces in the VPC.", + }, + "primary_ip": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + ConflictsWith: []string{"virtual_network_interface.0.id"}, + Computed: true, + Description: "The primary IP address of the virtual network interface for the instance networkattachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: "Indicates whether this primary_ip will be automatically deleted when `vni` is deleted.", + }, + "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 reserved IP.", + }, + "reserved_ip": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The name for this reserved IP. The name is unique across all reserved IPs in a subnet.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "resource_group": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"virtual_network_interface.0.id"}, + Computed: true, + Description: "The resource group id for this virtual network interface.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "security_groups": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + ForceNew: true, + ConflictsWith: []string{"virtual_network_interface.0.id"}, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "The security groups for this virtual network interface.", + }, + "subnet": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ConflictsWith: []string{"virtual_network_interface.0.id"}, + ForceNew: true, + Description: "The associated subnet id.", + }, + }, + }, + }, + }, + } +} + +func ResourceIBMIsInstanceNetworkAttachmentValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "instance", + 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_network_attachment", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMIsInstanceNetworkAttachmentCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + createInstanceNetworkAttachmentOptions := &vpcv1.CreateInstanceNetworkAttachmentOptions{} + + createInstanceNetworkAttachmentOptions.SetInstanceID(d.Get("instance").(string)) + virtualNetworkInterfaceModel, err := resourceIBMIsInstanceNetworkAttachmentMapToInstanceNetworkAttachmentPrototypeVirtualNetworkInterface(d.Get("virtual_network_interface.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + createInstanceNetworkAttachmentOptions.SetVirtualNetworkInterface(virtualNetworkInterfaceModel) + if _, ok := d.GetOk("name"); ok { + createInstanceNetworkAttachmentOptions.SetName(d.Get("name").(string)) + } + + instanceNetworkAttachment, response, err := vpcClient.CreateInstanceNetworkAttachmentWithContext(context, createInstanceNetworkAttachmentOptions) + if err != nil { + log.Printf("[DEBUG] CreateInstanceNetworkAttachmentWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateInstanceNetworkAttachmentWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *createInstanceNetworkAttachmentOptions.InstanceID, *instanceNetworkAttachment.ID)) + _, err = isWaitForInstanceNetworkAttachmentStable(vpcClient, *createInstanceNetworkAttachmentOptions.InstanceID, *instanceNetworkAttachment.ID, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(fmt.Errorf("isWaitForInstanceNetworkAttachmentStable failed %s", err)) + } + return resourceIBMIsInstanceNetworkAttachmentRead(context, d, meta) +} + +func resourceIBMIsInstanceNetworkAttachmentRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + getInstanceNetworkAttachmentOptions := &vpcv1.GetInstanceNetworkAttachmentOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getInstanceNetworkAttachmentOptions.SetInstanceID(parts[0]) + getInstanceNetworkAttachmentOptions.SetID(parts[1]) + + instanceNetworkAttachment, response, err := vpcClient.GetInstanceNetworkAttachmentWithContext(context, getInstanceNetworkAttachmentOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetInstanceNetworkAttachmentWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetInstanceNetworkAttachmentWithContext failed %s\n%s", err, response)) + } + // attachment details + if !core.IsNil(instanceNetworkAttachment.Name) { + if err = d.Set("name", instanceNetworkAttachment.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + } + if err = d.Set("created_at", flex.DateTimeToString(instanceNetworkAttachment.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + + if err = d.Set("href", instanceNetworkAttachment.Href); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting href: %s", err)) + } + if err = d.Set("lifecycle_state", instanceNetworkAttachment.LifecycleState); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting lifecycle_state: %s", err)) + } + if err = d.Set("port_speed", flex.IntValue(instanceNetworkAttachment.PortSpeed)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting port_speed: %s", err)) + } + if err = d.Set("resource_type", instanceNetworkAttachment.ResourceType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_type: %s", err)) + } + if err = d.Set("type", instanceNetworkAttachment.Type); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting type: %s", err)) + } + if err = d.Set("network_attachment", instanceNetworkAttachment.ID); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting network_attachment: %s", err)) + } + // vni details + vniId := *instanceNetworkAttachment.VirtualNetworkInterface.ID + vniMap := make(map[string]interface{}) + vniMap["id"] = vniId + getVniOptions := &vpcv1.GetVirtualNetworkInterfaceOptions{ + ID: &vniId, + } + vniDetails, response, err := vpcClient.GetVirtualNetworkInterface(getVniOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetVirtualNetworkInterface failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetVirtualNetworkInterface failed %s\n%s", err, response)) + } + vniMap["allow_ip_spoofing"] = vniDetails.AllowIPSpoofing + vniMap["auto_delete"] = vniDetails.AutoDelete + vniMap["enable_infrastructure_nat"] = vniDetails.EnableInfrastructureNat + vniMap["name"] = vniDetails.Name + vniMap["resource_group"] = vniDetails.ResourceGroup.ID + vniMap["resource_type"] = vniDetails.ResourceType + primaryipId := *instanceNetworkAttachment.PrimaryIP.ID + if !core.IsNil(vniDetails.Ips) { + ips := []map[string]interface{}{} + for _, ipsItem := range vniDetails.Ips { + if *ipsItem.ID != primaryipId { + ipsItemMap, err := resourceIBMIsVirtualNetworkInterfaceReservedIPReferenceToMap(&ipsItem, true) + if err != nil { + return diag.FromErr(err) + } + ips = append(ips, ipsItemMap) + } + } + vniMap["ips"] = ips + } + + if !core.IsNil(vniDetails.SecurityGroups) { + securityGroups := make([]string, 0) + for _, securityGroupsItem := range vniDetails.SecurityGroups { + if securityGroupsItem.ID != nil { + securityGroups = append(securityGroups, *securityGroupsItem.ID) + } + } + vniMap["security_groups"] = securityGroups + } + autoDelete := true + if autoDeleteOk, ok := d.GetOkExists("virtual_network_interface.0.primary_ip.0.auto_delete"); ok { + autoDelete = autoDeleteOk.(bool) + } + primaryIPMap, err := resourceIBMIsInstanceNetworkAttachmentReservedIPReferenceToMap(instanceNetworkAttachment.PrimaryIP, autoDelete) + if err != nil { + return diag.FromErr(err) + } + vniMap["primary_ip"] = []map[string]interface{}{primaryIPMap} + + vniMap["subnet"] = *instanceNetworkAttachment.Subnet.ID + if err = d.Set("virtual_network_interface", []map[string]interface{}{vniMap}); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting virtual_network_interface: %s", err)) + } + + return nil +} + +func resourceIBMIsInstanceNetworkAttachmentUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + updateInstanceNetworkAttachmentOptions := &vpcv1.UpdateInstanceNetworkAttachmentOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + updateInstanceNetworkAttachmentOptions.SetInstanceID(parts[0]) + updateInstanceNetworkAttachmentOptions.SetID(parts[1]) + + hasChange := false + + patchVals := &vpcv1.InstanceNetworkAttachmentPatch{} + if d.HasChange("instance") { + return diag.FromErr(fmt.Errorf("[ERROR] Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "instance")) + } + if d.HasChange("virtual_network_interface") && !d.IsNewResource() { + vniId := d.Get("virtual_network_interface.0.id").(string) + updateVirtualNetworkInterfaceOptions := &vpcv1.UpdateVirtualNetworkInterfaceOptions{ + ID: &vniId, + } + virtualNetworkInterfacePatch := &vpcv1.VirtualNetworkInterfacePatch{} + if d.HasChange("virtual_network_interface.0.auto_delete") { + autodelete := d.Get("virtual_network_interface.0.auto_delete").(bool) + virtualNetworkInterfacePatch.AutoDelete = &autodelete + } + if d.HasChange("virtual_network_interface.0.name") { + name := d.Get("virtual_network_interface.0.name").(string) + virtualNetworkInterfacePatch.Name = &name + } + if d.HasChange("virtual_network_interface.0.enable_infrastructure_nat") { + enableNat := d.Get("virtual_network_interface.0.enable_infrastructure_nat").(bool) + virtualNetworkInterfacePatch.EnableInfrastructureNat = &enableNat + } + if d.HasChange("virtual_network_interface.0.allow_ip_spoofing") { + allIpSpoofing := d.Get("virtual_network_interface.0.allow_ip_spoofing").(bool) + virtualNetworkInterfacePatch.AllowIPSpoofing = &allIpSpoofing + } + virtualNetworkInterfacePatchAsPatch, err := virtualNetworkInterfacePatch.AsPatch() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error encountered while apply as patch for virtualNetworkInterfacePatch of instance(%s) vni (%s) %s", d.Id(), vniId, err)) + } + updateVirtualNetworkInterfaceOptions.VirtualNetworkInterfacePatch = virtualNetworkInterfacePatchAsPatch + _, response, err := vpcClient.UpdateVirtualNetworkInterfaceWithContext(context, updateVirtualNetworkInterfaceOptions) + if err != nil { + log.Printf("[DEBUG] UpdateVirtualNetworkInterfaceWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateVirtualNetworkInterfaceWithContext failed during instance(%s) network attachment patch %s\n%s", d.Id(), err, response)) + } + + if d.HasChange("virtual_network_interface.0.ips") { + oldips, newips := d.GetChange("virtual_network_interface.0.ips") + os := oldips.(*schema.Set) + ns := newips.(*schema.Set) + var oldset, newset *schema.Set + + var out = make([]interface{}, ns.Len(), ns.Len()) + for i, nA := range ns.List() { + newPack := nA.(map[string]interface{}) + out[i] = newPack["reserved_ip"].(string) + } + newset = schema.NewSet(schema.HashString, out) + + out = make([]interface{}, os.Len(), os.Len()) + for i, oA := range os.List() { + oldPack := oA.(map[string]interface{}) + out[i] = oldPack["reserved_ip"].(string) + } + oldset = schema.NewSet(schema.HashString, out) + + remove := flex.ExpandStringList(oldset.Difference(newset).List()) + add := flex.ExpandStringList(newset.Difference(oldset).List()) + + if add != nil && len(add) > 0 { + for _, ipItem := range add { + if ipItem != "" { + + addVirtualNetworkInterfaceIPOptions := &vpcv1.AddVirtualNetworkInterfaceIPOptions{} + addVirtualNetworkInterfaceIPOptions.SetVirtualNetworkInterfaceID(vniId) + addVirtualNetworkInterfaceIPOptions.SetID(ipItem) + _, response, err := vpcClient.AddVirtualNetworkInterfaceIPWithContext(context, addVirtualNetworkInterfaceIPOptions) + if err != nil { + log.Printf("[DEBUG] AddVirtualNetworkInterfaceIPWithContext failed in VirtualNetworkInterface patch during instance nac patch %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("AddVirtualNetworkInterfaceIPWithContext failed in VirtualNetworkInterface patch during instance nac patch %s\n%s", err, response)) + } + } + } + } + if remove != nil && len(remove) > 0 { + for _, ipItem := range remove { + if ipItem != "" { + + removeVirtualNetworkInterfaceIPOptions := &vpcv1.RemoveVirtualNetworkInterfaceIPOptions{} + removeVirtualNetworkInterfaceIPOptions.SetVirtualNetworkInterfaceID(vniId) + removeVirtualNetworkInterfaceIPOptions.SetID(ipItem) + response, err := vpcClient.RemoveVirtualNetworkInterfaceIPWithContext(context, removeVirtualNetworkInterfaceIPOptions) + if err != nil { + log.Printf("[DEBUG] RemoveVirtualNetworkInterfaceIPWithContext failed in VirtualNetworkInterface patch during instance nac patch %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("RemoveVirtualNetworkInterfaceIPWithContext failed in VirtualNetworkInterface patch during instance nac patch %s\n%s", err, response)) + } + } + } + } + + } + if d.HasChange("virtual_network_interface.0.primary_ip") { + subnetId := d.Get("virtual_network_interface.0.subnet").(string) + ripId := d.Get("virtual_network_interface.0.primary_ip.0.reserved_ip").(string) + updateripoptions := &vpcv1.UpdateSubnetReservedIPOptions{ + SubnetID: &subnetId, + ID: &ripId, + } + reservedIpPath := &vpcv1.ReservedIPPatch{} + if d.HasChange("virtual_network_interface.0.primary_ip.0.name") { + name := d.Get("virtual_network_interface.0.primary_ip.0.name").(string) + reservedIpPath.Name = &name + } + if d.HasChange("virtual_network_interface.0.primary_ip.0.auto_delete") { + auto := d.Get("virtual_network_interface.0.primary_ip.0.auto_delete").(bool) + reservedIpPath.AutoDelete = &auto + } + reservedIpPathAsPatch, err := reservedIpPath.AsPatch() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error calling reserved ip as patch on vni patch \n%s", err)) + } + updateripoptions.ReservedIPPatch = reservedIpPathAsPatch + _, response, err := vpcClient.UpdateSubnetReservedIP(updateripoptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating vni reserved ip(%s): %s\n%s", ripId, err, response)) + } + } + if d.HasChange("virtual_network_interface.0.security_groups") { + ovs, nvs := d.GetChange("virtual_network_interface.0.security_groups") + ov := ovs.(*schema.Set) + nv := nvs.(*schema.Set) + remove := flex.ExpandStringList(ov.Difference(nv).List()) + add := flex.ExpandStringList(nv.Difference(ov).List()) + if len(add) > 0 { + for i := range add { + createsgnicoptions := &vpcv1.CreateSecurityGroupTargetBindingOptions{ + SecurityGroupID: &add[i], + ID: &vniId, + } + _, response, err := vpcClient.CreateSecurityGroupTargetBinding(createsgnicoptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error while creating security group %q for virtual network interface %s\n%s: %q", add[i], d.Id(), err, response)) + } + _, err = isWaitForVirtualNetworkInterfaceAvailable(vpcClient, vniId, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return diag.FromErr(err) + } + } + + } + if len(remove) > 0 { + for i := range remove { + deletesgnicoptions := &vpcv1.DeleteSecurityGroupTargetBindingOptions{ + SecurityGroupID: &remove[i], + ID: &vniId, + } + response, err := vpcClient.DeleteSecurityGroupTargetBinding(deletesgnicoptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error while removing security group %q for virtual network interface %s\n%s: %q", remove[i], d.Id(), err, response)) + } + _, err = isWaitForVirtualNetworkInterfaceAvailable(vpcClient, vniId, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return diag.FromErr(err) + } + } + } + } + + } + + if d.HasChange("name") { + newName := d.Get("name").(string) + patchVals.Name = &newName + hasChange = true + } + + if hasChange { + updateInstanceNetworkAttachmentOptions.InstanceNetworkAttachmentPatch, _ = patchVals.AsPatch() + _, response, err := vpcClient.UpdateInstanceNetworkAttachmentWithContext(context, updateInstanceNetworkAttachmentOptions) + if err != nil { + log.Printf("[DEBUG] UpdateInstanceNetworkAttachmentWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateInstanceNetworkAttachmentWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMIsInstanceNetworkAttachmentRead(context, d, meta) +} + +func resourceIBMIsInstanceNetworkAttachmentDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + getInstanceNetworkAttachmentOptions := &vpcv1.GetInstanceNetworkAttachmentOptions{} + getInstanceNetworkAttachmentOptions.SetInstanceID(parts[0]) + getInstanceNetworkAttachmentOptions.SetID(parts[1]) + + ina, response, err := vpcClient.GetInstanceNetworkAttachmentWithContext(context, getInstanceNetworkAttachmentOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetInstanceNetworkAttachmentWithContext failed while deleting %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetInstanceNetworkAttachmentWithContext failed %s\n%s", err, response)) + } + + deleteInstanceNetworkAttachmentOptions := &vpcv1.DeleteInstanceNetworkAttachmentOptions{} + deleteInstanceNetworkAttachmentOptions.SetInstanceID(parts[0]) + deleteInstanceNetworkAttachmentOptions.SetID(parts[1]) + + response, err = vpcClient.DeleteInstanceNetworkAttachmentWithContext(context, deleteInstanceNetworkAttachmentOptions) + if err != nil { + log.Printf("[DEBUG] DeleteInstanceNetworkAttachmentWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteInstanceNetworkAttachmentWithContext failed %s\n%s", err, response)) + } + _, err = isWaitForInstanceNetworkAttachmentDeleted(vpcClient, parts[0], parts[1], ina, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return diag.FromErr(fmt.Errorf("isWaitForInstanceNetworkAttachmentDeleted failed %s", err)) + } + + d.SetId("") + + return nil +} + +func resourceIBMIsInstanceNetworkAttachmentMapToInstanceNetworkAttachmentPrototypeVirtualNetworkInterface(modelMap map[string]interface{}) (vpcv1.InstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceIntf, error) { + model := &vpcv1.InstanceNetworkAttachmentPrototypeVirtualNetworkInterface{} + if modelMap["allow_ip_spoofing"] != nil { + model.AllowIPSpoofing = core.BoolPtr(modelMap["allow_ip_spoofing"].(bool)) + } + if modelMap["auto_delete"] != nil { + model.AutoDelete = core.BoolPtr(modelMap["auto_delete"].(bool)) + } + if modelMap["enable_infrastructure_nat"] != nil { + model.EnableInfrastructureNat = core.BoolPtr(modelMap["enable_infrastructure_nat"].(bool)) + } + if modelMap["ips"] != nil { + ips := []vpcv1.VirtualNetworkInterfaceIPPrototypeIntf{} + for _, ipsItem := range modelMap["ips"].(*schema.Set).List() { + ipsItemModel, err := resourceIBMIsInstanceNetworkAttachmentMapToVirtualNetworkInterfaceIPPrototype(ipsItem.(map[string]interface{})) + if err != nil { + return model, err + } + ips = append(ips, ipsItemModel) + } + model.Ips = ips + } + 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 := resourceIBMIsInstanceNetworkAttachmentMapToVirtualNetworkInterfacePrimaryIPPrototype(modelMap["primary_ip"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.PrimaryIP = PrimaryIPModel + } + if modelMap["resource_group"] != nil && modelMap["resource_group"].(string) != "" { + rgId := modelMap["resource_group"].(string) + model.ResourceGroup = &vpcv1.ResourceGroupIdentity{ + ID: &rgId, + } + } + if modelMap["security_groups"] != nil && modelMap["security_groups"].(*schema.Set).Len() > 0 { + securityGroups := []vpcv1.SecurityGroupIdentityIntf{} + sg := modelMap["security_groups"].(*schema.Set) + for _, v := range sg.List() { + value := v.(string) + securityGroupsItem := &vpcv1.SecurityGroupIdentity{ + ID: &value, + } + securityGroups = append(securityGroups, securityGroupsItem) + } + model.SecurityGroups = securityGroups + } + if modelMap["subnet"] != nil && modelMap["subnet"].(string) != "" { + subnetid := modelMap["subnet"].(string) + model.Subnet = &vpcv1.SubnetIdentity{ + ID: &subnetid, + } + } + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + return model, nil +} + +func resourceIBMIsInstanceNetworkAttachmentMapToVirtualNetworkInterfaceIPPrototype(modelMap map[string]interface{}) (vpcv1.VirtualNetworkInterfaceIPPrototypeIntf, error) { + model := &vpcv1.VirtualNetworkInterfaceIPPrototype{} + 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 resourceIBMIsInstanceNetworkAttachmentMapToVirtualNetworkInterfaceIPPrototypeReservedIPIdentityVirtualNetworkInterfaceIPsContext(modelMap map[string]interface{}) (vpcv1.VirtualNetworkInterfaceIPPrototypeReservedIPIdentityVirtualNetworkInterfaceIPsContextIntf, error) { + model := &vpcv1.VirtualNetworkInterfaceIPPrototypeReservedIPIdentityVirtualNetworkInterfaceIPsContext{} + 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 resourceIBMIsInstanceNetworkAttachmentMapToVirtualNetworkInterfaceIPPrototypeReservedIPIdentityVirtualNetworkInterfaceIPsContextByID(modelMap map[string]interface{}) (*vpcv1.VirtualNetworkInterfaceIPPrototypeReservedIPIdentityVirtualNetworkInterfaceIPsContextByID, error) { + model := &vpcv1.VirtualNetworkInterfaceIPPrototypeReservedIPIdentityVirtualNetworkInterfaceIPsContextByID{} + model.ID = core.StringPtr(modelMap["id"].(string)) + return model, nil +} + +func resourceIBMIsInstanceNetworkAttachmentMapToVirtualNetworkInterfaceIPPrototypeReservedIPIdentityVirtualNetworkInterfaceIPsContextByHref(modelMap map[string]interface{}) (*vpcv1.VirtualNetworkInterfaceIPPrototypeReservedIPIdentityVirtualNetworkInterfaceIPsContextByHref, error) { + model := &vpcv1.VirtualNetworkInterfaceIPPrototypeReservedIPIdentityVirtualNetworkInterfaceIPsContextByHref{} + model.Href = core.StringPtr(modelMap["href"].(string)) + return model, nil +} + +func resourceIBMIsInstanceNetworkAttachmentMapToVirtualNetworkInterfaceIPPrototypeReservedIPPrototypeVirtualNetworkInterfaceIPsContext(modelMap map[string]interface{}) (*vpcv1.VirtualNetworkInterfaceIPPrototypeReservedIPPrototypeVirtualNetworkInterfaceIPsContext, error) { + model := &vpcv1.VirtualNetworkInterfaceIPPrototypeReservedIPPrototypeVirtualNetworkInterfaceIPsContext{} + 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 resourceIBMIsInstanceNetworkAttachmentMapToVirtualNetworkInterfacePrimaryIPPrototype(modelMap map[string]interface{}) (vpcv1.VirtualNetworkInterfacePrimaryIPPrototypeIntf, error) { + model := &vpcv1.VirtualNetworkInterfacePrimaryIPPrototype{} + 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 resourceIBMIsInstanceNetworkAttachmentMapToVirtualNetworkInterfacePrimaryIPPrototypeReservedIPIdentityVirtualNetworkInterfacePrimaryIPContext(modelMap map[string]interface{}) (vpcv1.VirtualNetworkInterfacePrimaryIPPrototypeReservedIPIdentityVirtualNetworkInterfacePrimaryIPContextIntf, error) { + model := &vpcv1.VirtualNetworkInterfacePrimaryIPPrototypeReservedIPIdentityVirtualNetworkInterfacePrimaryIPContext{} + 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 resourceIBMIsInstanceNetworkAttachmentMapToVirtualNetworkInterfacePrimaryIPPrototypeReservedIPIdentityVirtualNetworkInterfacePrimaryIPContextByID(modelMap map[string]interface{}) (*vpcv1.VirtualNetworkInterfacePrimaryIPPrototypeReservedIPIdentityVirtualNetworkInterfacePrimaryIPContextByID, error) { + model := &vpcv1.VirtualNetworkInterfacePrimaryIPPrototypeReservedIPIdentityVirtualNetworkInterfacePrimaryIPContextByID{} + model.ID = core.StringPtr(modelMap["id"].(string)) + return model, nil +} + +func resourceIBMIsInstanceNetworkAttachmentMapToVirtualNetworkInterfacePrimaryIPPrototypeReservedIPIdentityVirtualNetworkInterfacePrimaryIPContextByHref(modelMap map[string]interface{}) (*vpcv1.VirtualNetworkInterfacePrimaryIPPrototypeReservedIPIdentityVirtualNetworkInterfacePrimaryIPContextByHref, error) { + model := &vpcv1.VirtualNetworkInterfacePrimaryIPPrototypeReservedIPIdentityVirtualNetworkInterfacePrimaryIPContextByHref{} + model.Href = core.StringPtr(modelMap["href"].(string)) + return model, nil +} + +func resourceIBMIsInstanceNetworkAttachmentMapToVirtualNetworkInterfacePrimaryIPPrototypeReservedIPPrototypeVirtualNetworkInterfacePrimaryIPContext(modelMap map[string]interface{}) (*vpcv1.VirtualNetworkInterfacePrimaryIPPrototypeReservedIPPrototypeVirtualNetworkInterfacePrimaryIPContext, error) { + model := &vpcv1.VirtualNetworkInterfacePrimaryIPPrototypeReservedIPPrototypeVirtualNetworkInterfacePrimaryIPContext{} + 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 resourceIBMIsInstanceNetworkAttachmentMapToSubnetIdentityByID(modelMap map[string]interface{}) (*vpcv1.SubnetIdentityByID, error) { + model := &vpcv1.SubnetIdentityByID{} + model.ID = core.StringPtr(modelMap["id"].(string)) + return model, nil +} + +func resourceIBMIsInstanceNetworkAttachmentMapToSubnetIdentityByCRN(modelMap map[string]interface{}) (*vpcv1.SubnetIdentityByCRN, error) { + model := &vpcv1.SubnetIdentityByCRN{} + model.CRN = core.StringPtr(modelMap["crn"].(string)) + return model, nil +} + +func resourceIBMIsInstanceNetworkAttachmentMapToSubnetIdentityByHref(modelMap map[string]interface{}) (*vpcv1.SubnetIdentityByHref, error) { + model := &vpcv1.SubnetIdentityByHref{} + model.Href = core.StringPtr(modelMap["href"].(string)) + return model, nil +} + +func resourceIBMIsInstanceNetworkAttachmentMapToInstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceVirtualNetworkInterfacePrototypeInstanceNetworkAttachmentContext(modelMap map[string]interface{}) (*vpcv1.InstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceVirtualNetworkInterfacePrototypeInstanceNetworkAttachmentContext, error) { + model := &vpcv1.InstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceVirtualNetworkInterfacePrototypeInstanceNetworkAttachmentContext{} + if modelMap["allow_ip_spoofing"] != nil { + model.AllowIPSpoofing = core.BoolPtr(modelMap["allow_ip_spoofing"].(bool)) + } + if modelMap["auto_delete"] != nil { + model.AutoDelete = core.BoolPtr(modelMap["auto_delete"].(bool)) + } + if modelMap["enable_infrastructure_nat"] != nil { + model.EnableInfrastructureNat = core.BoolPtr(modelMap["enable_infrastructure_nat"].(bool)) + } + if modelMap["ips"] != nil { + ips := []vpcv1.VirtualNetworkInterfaceIPPrototypeIntf{} + for _, ipsItem := range modelMap["ips"].(*schema.Set).List() { + ipsItemModel, err := resourceIBMIsInstanceNetworkAttachmentMapToVirtualNetworkInterfaceIPPrototype(ipsItem.(map[string]interface{})) + if err != nil { + return model, err + } + ips = append(ips, ipsItemModel) + } + model.Ips = ips + } + 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 := resourceIBMIsInstanceNetworkAttachmentMapToVirtualNetworkInterfacePrimaryIPPrototype(modelMap["primary_ip"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.PrimaryIP = PrimaryIPModel + } + if modelMap["resource_group"] != nil && modelMap["resource_group"].(string) != "" { + rgId := modelMap["resource_group"].(string) + model.ResourceGroup = &vpcv1.ResourceGroupIdentity{ + ID: &rgId, + } + } + if modelMap["security_groups"] != nil && modelMap["security_groups"].(*schema.Set).Len() > 0 { + securityGroups := []vpcv1.SecurityGroupIdentityIntf{} + sg := modelMap["security_groups"].(*schema.Set) + for _, v := range sg.List() { + value := v.(string) + securityGroupsItem := &vpcv1.SecurityGroupIdentity{ + ID: &value, + } + securityGroups = append(securityGroups, securityGroupsItem) + } + model.SecurityGroups = securityGroups + } + if modelMap["subnet"] != nil && modelMap["subnet"].(string) != "" { + subnetid := modelMap["subnet"].(string) + model.Subnet = &vpcv1.SubnetIdentity{ + ID: &subnetid, + } + } + return model, nil +} + +func resourceIBMIsInstanceNetworkAttachmentReservedIPReferenceToMap(model *vpcv1.ReservedIPReference, autodelete bool) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["address"] = model.Address + if model.Deleted != nil { + deletedMap, err := resourceIBMIsInstanceNetworkAttachmentReservedIPReferenceDeletedToMap(model.Deleted) + if err != nil { + return modelMap, err + } + modelMap["deleted"] = []map[string]interface{}{deletedMap} + } + modelMap["href"] = model.Href + modelMap["auto_delete"] = autodelete + modelMap["reserved_ip"] = model.ID + modelMap["name"] = model.Name + modelMap["resource_type"] = model.ResourceType + return modelMap, nil +} + +func resourceIBMIsInstanceNetworkAttachmentReservedIPReferenceDeletedToMap(model *vpcv1.ReservedIPReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = model.MoreInfo + return modelMap, nil +} + +func resourceIBMIsInstanceNetworkAttachmentSubnetReferenceToMap(model *vpcv1.SubnetReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = model.CRN + if model.Deleted != nil { + deletedMap, err := resourceIBMIsInstanceNetworkAttachmentSubnetReferenceDeletedToMap(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 resourceIBMIsInstanceNetworkAttachmentSubnetReferenceDeletedToMap(model *vpcv1.SubnetReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = model.MoreInfo + return modelMap, nil +} + +func isWaitForInstanceNetworkAttachmentStable(instanceC *vpcv1.VpcV1, instanceId, id string, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for instance network attachment (%s) to be stable.", id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"deleting", "waiting", "updating", "pending"}, + Target: []string{"stable", "failed", "suspended", ""}, + Refresh: isInstanceNetworkAttachmentRefreshFunc(instanceC, instanceId, id), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} +func isInstanceNetworkAttachmentRefreshFunc(instanceC *vpcv1.VpcV1, instanceId, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + getInstanceNetworkAttachmentOptions := &vpcv1.GetInstanceNetworkAttachmentOptions{ + InstanceID: &instanceId, + ID: &id, + } + networkAttachment, response, err := instanceC.GetInstanceNetworkAttachment(getInstanceNetworkAttachmentOptions) + if err != nil { + return nil, "", fmt.Errorf("[ERROR] Error getting network attachment: %s\n%s", err, response) + } + + if *networkAttachment.LifecycleState == "failed" || *networkAttachment.LifecycleState == "suspended" { + return networkAttachment, *networkAttachment.LifecycleState, fmt.Errorf("[ERROR] Error network attachment(%s) in (%s) state", id, *networkAttachment.LifecycleState) + } + + return networkAttachment, *networkAttachment.LifecycleState, nil + } +} +func isWaitForInstanceNetworkAttachmentDeleted(instanceC *vpcv1.VpcV1, instanceId, id string, ina *vpcv1.InstanceNetworkAttachment, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for instance network attachment (%s) to be deleted.", id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"deleting", "waiting", "updating", "pending"}, + Target: []string{"deleted", "failed", "suspended", ""}, + Refresh: isInstanceNetworkAttachmentDeleteRefreshFunc(instanceC, instanceId, id, ina), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} +func isInstanceNetworkAttachmentDeleteRefreshFunc(instanceC *vpcv1.VpcV1, instanceId, id string, ina *vpcv1.InstanceNetworkAttachment) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + getInstanceNetworkAttachmentOptions := &vpcv1.GetInstanceNetworkAttachmentOptions{ + InstanceID: &instanceId, + ID: &id, + } + networkAttachment, response, err := instanceC.GetInstanceNetworkAttachment(getInstanceNetworkAttachmentOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return ina, "deleted", nil + } + return ina, "", fmt.Errorf("[ERROR] Error deleting network attachment: %s\n%s", err, response) + } + + if *networkAttachment.LifecycleState == "failed" || *networkAttachment.LifecycleState == "suspended" { + return networkAttachment, *networkAttachment.LifecycleState, fmt.Errorf("[ERROR] Error network attachment(%s) in (%s) state", id, *networkAttachment.LifecycleState) + } + + return networkAttachment, *networkAttachment.LifecycleState, nil + } +} diff --git a/ibm/service/vpc/resource_ibm_is_instance_network_attachment_test.go b/ibm/service/vpc/resource_ibm_is_instance_network_attachment_test.go new file mode 100644 index 0000000000..3ea2973088 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_instance_network_attachment_test.go @@ -0,0 +1,413 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func TestAccIBMIsInstanceNetworkAttachmentBasic(t *testing.T) { + var conf vpcv1.InstanceNetworkAttachment + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-vsi-%d", acctest.RandIntRange(10, 100)) + vniname := fmt.Sprintf("tf-vni-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tvni-subnet-%d", acctest.RandIntRange(10, 100)) + naname := fmt.Sprintf("tvni-na-%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: testAccCheckIBMIsInstanceNetworkAttachmentDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsInstanceNetworkAttachmentConfigBasic(vpcname, subnetname, sshname, publicKey, vniname, name, naname), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIsInstanceNetworkAttachmentExists("ibm_is_instance_network_attachment.is_instance_network_attachment", conf), + resource.TestCheckResourceAttr("ibm_is_instance_network_attachment.is_instance_network_attachment", "resource_type", "instance_network_attachment"), + resource.TestCheckResourceAttr("ibm_is_instance_network_attachment.is_instance_network_attachment", "type", "secondary"), + resource.TestCheckResourceAttr("ibm_is_instance_network_attachment.is_instance_network_attachment", "lifecycle_state", "stable"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "created_at"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "href"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "id"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "instance"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "network_attachment"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "name"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "port_speed"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.#"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.0.id"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.0.primary_ip.#"), + ), + }, + }, + }) +} + +func TestAccIBMIsInstanceNetworkAttachmentAllArgs(t *testing.T) { + var conf vpcv1.InstanceNetworkAttachment + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-vsi-%d", acctest.RandIntRange(10, 100)) + vniname := fmt.Sprintf("tf-vni-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tvni-subnet-%d", acctest.RandIntRange(10, 100)) + naname := fmt.Sprintf("tvni-na-%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: testAccCheckIBMIsInstanceNetworkAttachmentDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsInstanceNetworkAttachmentConfig(vpcname, subnetname, sshname, publicKey, vniname, name, naname), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIsInstanceNetworkAttachmentExists("ibm_is_instance_network_attachment.is_instance_network_attachment", conf), + resource.TestCheckResourceAttr("ibm_is_instance_network_attachment.is_instance_network_attachment", "resource_type", "instance_network_attachment"), + resource.TestCheckResourceAttr("ibm_is_instance_network_attachment.is_instance_network_attachment", "type", "secondary"), + resource.TestCheckResourceAttr("ibm_is_instance_network_attachment.is_instance_network_attachment", "lifecycle_state", "stable"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "created_at"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "href"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "id"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "instance"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "network_attachment"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "name"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "port_speed"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.#"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.0.id"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.0.allow_ip_spoofing"), + resource.TestCheckResourceAttr("ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.0.allow_ip_spoofing", "true"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.0.enable_infrastructure_nat"), + resource.TestCheckResourceAttr("ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.0.enable_infrastructure_nat", "true"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.0.name"), + resource.TestCheckResourceAttr("ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.0.name", vniname+"-inline"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.0.primary_ip.#"), + resource.TestCheckResourceAttr("ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.0.primary_ip.0.address", "10.240.64.12"), + ), + }, + }, + }) +} +func TestAccIBMIsInstanceNetworkAttachmentAllArgsUpdate(t *testing.T) { + var conf vpcv1.InstanceNetworkAttachment + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-vsi-%d", acctest.RandIntRange(10, 100)) + vniname := fmt.Sprintf("tf-vni-%d", acctest.RandIntRange(10, 100)) + vninameupdated := fmt.Sprintf("tf-vni-upd-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tvni-subnet-%d", acctest.RandIntRange(10, 100)) + naname := fmt.Sprintf("tvni-na-%d", acctest.RandIntRange(10, 100)) + nanameupdated := fmt.Sprintf("tvni-na-upd-%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: testAccCheckIBMIsInstanceNetworkAttachmentDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsInstanceNetworkAttachmentUpdateConfig(vpcname, subnetname, sshname, publicKey, vniname, name, naname), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIsInstanceNetworkAttachmentExists("ibm_is_instance_network_attachment.is_instance_network_attachment", conf), + resource.TestCheckResourceAttr("ibm_is_instance_network_attachment.is_instance_network_attachment", "resource_type", "instance_network_attachment"), + resource.TestCheckResourceAttr("ibm_is_instance_network_attachment.is_instance_network_attachment", "type", "secondary"), + resource.TestCheckResourceAttr("ibm_is_instance_network_attachment.is_instance_network_attachment", "lifecycle_state", "stable"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "created_at"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "href"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "id"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "instance"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "network_attachment"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "name"), + resource.TestCheckResourceAttr("ibm_is_instance_network_attachment.is_instance_network_attachment", "name", naname), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "port_speed"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.#"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.0.id"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.0.allow_ip_spoofing"), + resource.TestCheckResourceAttr("ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.0.allow_ip_spoofing", "true"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.0.enable_infrastructure_nat"), + resource.TestCheckResourceAttr("ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.0.enable_infrastructure_nat", "true"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.0.name"), + resource.TestCheckResourceAttr("ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.0.name", vniname+"-inline"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.0.primary_ip.#"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.0.primary_ip.0.address"), + ), + }, + resource.TestStep{ + Config: testAccCheckIBMIsInstanceNetworkAttachmentUpdateConfig(vpcname, subnetname, sshname, publicKey, vninameupdated, name, nanameupdated), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIsInstanceNetworkAttachmentExists("ibm_is_instance_network_attachment.is_instance_network_attachment", conf), + resource.TestCheckResourceAttr("ibm_is_instance_network_attachment.is_instance_network_attachment", "resource_type", "instance_network_attachment"), + resource.TestCheckResourceAttr("ibm_is_instance_network_attachment.is_instance_network_attachment", "type", "secondary"), + resource.TestCheckResourceAttr("ibm_is_instance_network_attachment.is_instance_network_attachment", "lifecycle_state", "stable"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "created_at"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "href"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "id"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "instance"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "network_attachment"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "name"), + resource.TestCheckResourceAttr("ibm_is_instance_network_attachment.is_instance_network_attachment", "name", nanameupdated), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "port_speed"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.#"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.0.id"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.0.allow_ip_spoofing"), + resource.TestCheckResourceAttr("ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.0.allow_ip_spoofing", "true"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.0.enable_infrastructure_nat"), + resource.TestCheckResourceAttr("ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.0.enable_infrastructure_nat", "true"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.0.name"), + resource.TestCheckResourceAttr("ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.0.name", vninameupdated+"-inline"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.0.primary_ip.#"), + resource.TestCheckResourceAttrSet("ibm_is_instance_network_attachment.is_instance_network_attachment", "virtual_network_interface.0.primary_ip.0.address"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsInstanceNetworkAttachmentConfigBasic(vpcname, subnetname, sshname, publicKey, vniname, name, naname 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_virtual_network_interface" "testacc_vni" { + name = "%s" + subnet = ibm_is_subnet.testacc_subnet.id + enable_infrastructure_nat = true + allow_ip_spoofing = %t + } + resource "ibm_is_virtual_network_interface" "testacc_vni2" { + name = "%s2" + subnet = ibm_is_subnet.testacc_subnet.id + enable_infrastructure_nat = true + allow_ip_spoofing = %t + } + resource "ibm_is_instance" "testacc_vsi" { + profile = "%s" + name = "%s" + image = "%s" + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + primary_network_attachment { + name = "vni-2" + virtual_network_interface { + id = ibm_is_virtual_network_interface.testacc_vni.id + } + } + vpc = ibm_is_vpc.testacc_vpc.id + } + + resource "ibm_is_instance_network_attachment" "is_instance_network_attachment" { + instance = ibm_is_instance.testacc_vsi.id + name = "%s" + virtual_network_interface { + id = ibm_is_virtual_network_interface.testacc_vni2.id + } + } + `, vpcname, subnetname, acc.ISZoneName2, sshname, publicKey, vniname, true, vniname, true, acc.InstanceProfileName, name, acc.IsImage, acc.ISZoneName2, naname) +} + +func testAccCheckIBMIsInstanceNetworkAttachmentConfig(vpcname, subnetname, sshname, publicKey, vniname, name, naname 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_virtual_network_interface" "testacc_vni" { + name = "%s" + subnet = ibm_is_subnet.testacc_subnet.id + enable_infrastructure_nat = true + allow_ip_spoofing = %t + } + + resource "ibm_is_instance" "testacc_vsi" { + profile = "%s" + name = "%s" + image = "%s" + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + primary_network_attachment { + name = "vni-2" + virtual_network_interface { + id = ibm_is_virtual_network_interface.testacc_vni.id + } + } + vpc = ibm_is_vpc.testacc_vpc.id + } + + resource "ibm_is_instance_network_attachment" "is_instance_network_attachment" { + instance = ibm_is_instance.testacc_vsi.id + name = "%s" + virtual_network_interface { + name = "%s-inline" + allow_ip_spoofing = %t + enable_infrastructure_nat = true + primary_ip { + auto_delete = true + address = "10.240.64.12" + } + subnet = ibm_is_subnet.testacc_subnet.id + } + } + `, vpcname, subnetname, acc.ISZoneName2, sshname, publicKey, vniname, true, acc.InstanceProfileName, name, acc.IsImage, acc.ISZoneName2, naname, vniname, true) +} +func testAccCheckIBMIsInstanceNetworkAttachmentUpdateConfig(vpcname, subnetname, sshname, publicKey, vniname, name, naname 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_virtual_network_interface" "testacc_vni" { + name = "%s" + subnet = ibm_is_subnet.testacc_subnet.id + enable_infrastructure_nat = true + allow_ip_spoofing = %t + } + + resource "ibm_is_instance" "testacc_vsi" { + profile = "%s" + name = "%s" + image = "%s" + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + primary_network_attachment { + name = "vni-2" + virtual_network_interface { + id = ibm_is_virtual_network_interface.testacc_vni.id + } + } + vpc = ibm_is_vpc.testacc_vpc.id + } + + resource "ibm_is_instance_network_attachment" "is_instance_network_attachment" { + instance = ibm_is_instance.testacc_vsi.id + name = "%s" + virtual_network_interface { + auto_delete = true + name = "%s-inline" + allow_ip_spoofing = %t + enable_infrastructure_nat = true + primary_ip { + auto_delete = true + address = cidrhost(ibm_is_subnet.testacc_subnet.ipv4_cidr_block, 11) + } + subnet = ibm_is_subnet.testacc_subnet.id + } + } + `, vpcname, subnetname, acc.ISZoneName2, sshname, publicKey, vniname, true, acc.InstanceProfileName, name, acc.IsImage, acc.ISZoneName2, naname, vniname, true) +} + +func testAccCheckIBMIsInstanceNetworkAttachmentExists(n string, obj vpcv1.InstanceNetworkAttachment) 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 := vpcClient(acc.TestAccProvider.Meta()) + if err != nil { + return err + } + + getInstanceNetworkAttachmentOptions := &vpcv1.GetInstanceNetworkAttachmentOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getInstanceNetworkAttachmentOptions.SetInstanceID(parts[0]) + getInstanceNetworkAttachmentOptions.SetID(parts[1]) + + instanceByNetworkAttachment, _, err := vpcClient.GetInstanceNetworkAttachment(getInstanceNetworkAttachmentOptions) + if err != nil { + return err + } + + obj = *instanceByNetworkAttachment + return nil + } +} + +func testAccCheckIBMIsInstanceNetworkAttachmentDestroy(s *terraform.State) error { + vpcClient, err := vpcClient(acc.TestAccProvider.Meta()) + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_instance_network_attachment" { + continue + } + + getInstanceNetworkAttachmentOptions := &vpcv1.GetInstanceNetworkAttachmentOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getInstanceNetworkAttachmentOptions.SetInstanceID(parts[0]) + getInstanceNetworkAttachmentOptions.SetID(parts[1]) + + // Try to find the key + _, response, err := vpcClient.GetInstanceNetworkAttachment(getInstanceNetworkAttachmentOptions) + + if err == nil { + return fmt.Errorf("InstanceByNetworkAttachment still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("[ERROR] Error checking for InstanceByNetworkAttachment (%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 65f01f51c5..a2ffc31f58 100644 --- a/ibm/service/vpc/resource_ibm_is_instance_template.go +++ b/ibm/service/vpc/resource_ibm_is_instance_template.go @@ -4,14 +4,17 @@ package vpc import ( + "bytes" "context" "fmt" "log" "reflect" "strings" + "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" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -328,11 +331,13 @@ func ResourceIBMISInstanceTemplate() *schema.Resource { }, isInstanceTemplatePrimaryNetworkInterface: { - Type: schema.TypeList, - MinItems: 1, - MaxItems: 1, - Required: true, - Description: "Primary Network interface info", + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Optional: true, + ExactlyOneOf: []string{"primary_network_attachment", "primary_network_interface"}, + ConflictsWith: []string{"primary_network_attachment", "network_attachments"}, + Description: "Primary Network interface info", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ isInstanceTemplateNicAllowIPSpoofing: { @@ -410,8 +415,9 @@ func ResourceIBMISInstanceTemplate() *schema.Resource { }, isInstanceTemplateNetworkInterfaces: { - Type: schema.TypeList, - Optional: true, + Type: schema.TypeList, + Optional: true, + ConflictsWith: []string{"primary_network_attachment", "network_attachments"}, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ isInstanceTemplateNicAllowIPSpoofing: { @@ -485,6 +491,481 @@ func ResourceIBMISInstanceTemplate() *schema.Resource { }, }, + // vni + + "primary_network_attachment": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + ForceNew: true, + Description: "The primary network attachment for this virtual server instance.", + ExactlyOneOf: []string{"primary_network_attachment", "primary_network_interface"}, + ConflictsWith: []string{"primary_network_interface", "network_interfaces"}, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + + // pna can accept either vni id or prototype + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_instance_network_attachment", "name"), + Description: "The name for this instance 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 network attachment.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this instance network attachment.", + }, + "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.", + }, + }, + }, + }, + + // vni properties + "virtual_network_interface": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Computed: true, + Description: "A virtual network interface for the instance network attachment. This can be specified using an existing virtual network interface, or a prototype object for a new virtual network interface.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The virtual network interface id for this instance network attachment.", + }, + "allow_ip_spoofing": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Indicates whether source IP spoofing is allowed on this interface. If `false`, source IP spoofing is prevented on this interface. If `true`, source IP spoofing is allowed on this interface.", + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Indicates whether this virtual network interface will be automatically deleted when`target` is deleted.", + }, + "enable_infrastructure_nat": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + 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 network interface, allowing the workload to perform any needed NAT operations.- `allow_ip_spoofing` must be `false`.- If the virtual network interface is attached: - The target `resource_type` must be `bare_metal_server_network_attachment`. - The target `interface_type` must not be `hipersocket`.", + }, + "ips": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Computed: true, + Description: "The reserved IPs bound to this virtual network interface.May be empty when `lifecycle_state` is `pending`.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "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.", + }, + }, + }, + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP.", + }, + "reserved_ip": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The name for this reserved IP. The name is unique across all reserved IPs in a subnet.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_virtual_network_interface", "vni_name"), + Description: "The name for this virtual network interface. The name is unique across all virtual network interfaces in the VPC.", + }, + "primary_ip": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Computed: true, + Description: "The primary IP address of the virtual network interface for the instance networkattachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "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 reserved IP.", + }, + "reserved_ip": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The name for this reserved IP. The name is unique across all reserved IPs in a subnet.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: "Indicates whether this reserved ip will be automatically deleted when `target` is deleted.", + }, + }, + }, + }, + "resource_group": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The resource group id for this virtual network interface.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "security_groups": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + ForceNew: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "The security groups for this virtual network interface.", + }, + "subnet": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + Description: "The associated subnet id.", + }, + }, + }, + }, + }, + }, + }, + + "network_attachments": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + ForceNew: true, + ConflictsWith: []string{"primary_network_interface", "network_interfaces"}, + Description: "The network attachments for this virtual server instance, including the primary network attachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + + // pna can accept either vni id or prototype + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_instance_network_attachment", "name"), + Description: "The name for this instance 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 network attachment.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this instance network attachment.", + }, + "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.", + }, + }, + }, + }, + + "virtual_network_interface": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "A virtual network interface for the instance network attachment. This can be specified using an existing virtual network interface, or a prototype object for a new virtual network interface.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The virtual network interface id for this instance network attachment.", + }, + "allow_ip_spoofing": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Indicates whether source IP spoofing is allowed on this interface. If `false`, source IP spoofing is prevented on this interface. If `true`, source IP spoofing is allowed on this interface.", + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Indicates whether this virtual network interface will be automatically deleted when`target` is deleted.", + }, + "enable_infrastructure_nat": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + 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 network interface, allowing the workload to perform any needed NAT operations.- `allow_ip_spoofing` must be `false`.- If the virtual network interface is attached: - The target `resource_type` must be `bare_metal_server_network_attachment`. - The target `interface_type` must not be `hipersocket`.", + }, + "ips": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Computed: true, + Description: "The reserved IPs bound to this virtual network interface.May be empty when `lifecycle_state` is `pending`.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "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.", + }, + }, + }, + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP.", + }, + "reserved_ip": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The name for this reserved IP. The name is unique across all reserved IPs in a subnet.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_virtual_network_interface", "vni_name"), + Description: "The name for this virtual network interface. The name is unique across all virtual network interfaces in the VPC.", + }, + "primary_ip": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Computed: true, + Description: "The primary IP address of the virtual network interface for the instance networkattachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: "Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound.", + }, + "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 reserved IP.", + }, + "reserved_ip": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The name for this reserved IP. The name is unique across all reserved IPs in a subnet.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "resource_group": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The resource group id for this virtual network interface.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "security_groups": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "The security groups for this virtual network interface.", + }, + "subnet": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The associated subnet id.", + }, + }, + }, + }, + }, + }, + }, + isInstanceTemplateUserData: { Type: schema.TypeString, ForceNew: true, @@ -581,6 +1062,37 @@ func ResourceIBMISInstanceTemplate() *schema.Resource { }, }, }, + isReservationAffinity: { + Type: schema.TypeList, + Optional: true, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isReservationAffinityPolicyResp: { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The reservation affinity policy to use for this virtual server instance.", + }, + isReservationAffinityPool: &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Computed: true, + Description: "The pool of reservations available for use by this virtual server instance.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isReservationId: { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The unique identifier for this reservation.", + }, + }, + }, + }, + }, + }, + }, }, } } @@ -725,6 +1237,33 @@ func instanceTemplateCreateByCatalogOffering(d *schema.ResourceData, meta interf instanceproto.Name = &name } + // vni + if networkattachmentsintf, ok := d.GetOk("network_attachments"); ok { + networkAttachments := []vpcv1.InstanceNetworkAttachmentPrototype{} + for i, networkAttachmentsItem := range networkattachmentsintf.([]interface{}) { + allowipspoofing := fmt.Sprintf("network_attachments.%d.allow_ip_spoofing", i) + autodelete := fmt.Sprintf("network_attachments.%d.auto_delete", i) + enablenat := fmt.Sprintf("network_attachments.%d.enable_infrastructure_nat", i) + networkAttachmentsItemModel, err := resourceIBMIsInstanceTemplateMapToInstanceNetworkAttachmentPrototype(allowipspoofing, autodelete, enablenat, d, networkAttachmentsItem.(map[string]interface{})) + if err != nil { + return err + } + networkAttachments = append(networkAttachments, *networkAttachmentsItemModel) + } + instanceproto.NetworkAttachments = networkAttachments + } + if primnetworkattachmentintf, ok := d.GetOk("primary_network_attachment"); ok && len(primnetworkattachmentintf.([]interface{})) > 0 { + i := 0 + allowipspoofing := fmt.Sprintf("primary_network_attachment.%d.virtual_network_interface.0.allow_ip_spoofing", i) + autodelete := fmt.Sprintf("primary_network_attachment.%d.virtual_network_interface.0.auto_delete", i) + enablenat := fmt.Sprintf("primary_network_attachment.%d.virtual_network_interface.0.enable_infrastructure_nat", i) + primaryNetworkAttachmentModel, err := resourceIBMIsInstanceTemplateMapToInstanceNetworkAttachmentPrototype(allowipspoofing, autodelete, enablenat, d, primnetworkattachmentintf.([]interface{})[0].(map[string]interface{})) + if err != nil { + return err + } + instanceproto.PrimaryNetworkAttachment = primaryNetworkAttachmentModel + } + metadataServiceEnabled := d.Get(isInstanceTemplateMetadataServiceEnabled).(bool) if metadataServiceEnabled { instanceproto.MetadataService = &vpcv1.InstanceMetadataServicePrototype{ @@ -1159,6 +1698,34 @@ func instanceTemplateCreate(d *schema.ResourceData, meta interface{}, profile, n instanceproto.MetadataService = metadataService } + // vni + + if networkattachmentsintf, ok := d.GetOk("network_attachments"); ok { + networkAttachments := []vpcv1.InstanceNetworkAttachmentPrototype{} + for i, networkAttachmentsItem := range networkattachmentsintf.([]interface{}) { + allowipspoofing := fmt.Sprintf("network_attachments.%d.virtual_network_interface.0.allow_ip_spoofing", i) + autodelete := fmt.Sprintf("network_attachments.%d.virtual_network_interface.0.auto_delete", i) + enablenat := fmt.Sprintf("network_attachments.%d.virtual_network_interface.0.enable_infrastructure_nat", i) + networkAttachmentsItemModel, err := resourceIBMIsInstanceTemplateMapToInstanceNetworkAttachmentPrototype(allowipspoofing, autodelete, enablenat, d, networkAttachmentsItem.(map[string]interface{})) + if err != nil { + return err + } + networkAttachments = append(networkAttachments, *networkAttachmentsItemModel) + } + instanceproto.NetworkAttachments = networkAttachments + } + if primnetworkattachmentintf, ok := d.GetOk("primary_network_attachment"); ok && len(primnetworkattachmentintf.([]interface{})) > 0 { + i := 0 + allowipspoofing := fmt.Sprintf("primary_network_attachment.%d.virtual_network_interface.0.allow_ip_spoofing", i) + autodelete := fmt.Sprintf("primary_network_attachment.%d.virtual_network_interface.0.auto_delete", i) + enablenat := fmt.Sprintf("primary_network_attachment.%d.virtual_network_interface.0.enable_infrastructure_nat", i) + primaryNetworkAttachmentModel, err := resourceIBMIsInstanceTemplateMapToInstanceNetworkAttachmentPrototype(allowipspoofing, autodelete, enablenat, d, primnetworkattachmentintf.([]interface{})[0].(map[string]interface{})) + if err != nil { + return err + } + instanceproto.PrimaryNetworkAttachment = primaryNetworkAttachmentModel + } + if defaultTrustedProfileTargetIntf, ok := d.GetOk(isInstanceDefaultTrustedProfileTarget); ok { defaultTrustedProfiletarget := defaultTrustedProfileTargetIntf.(string) @@ -1198,6 +1765,31 @@ func instanceTemplateCreate(d *schema.ResourceData, meta interface{}, profile, n } instanceproto.PlacementTarget = dHostGrpPlaementTarget } + if resAffinity, ok := d.GetOk(isReservationAffinity); ok { + resAff := resAffinity.([]interface{})[0].(map[string]interface{}) + var resAffinity = &vpcv1.InstanceReservationAffinityPrototype{} + policy, ok := resAff["policy"] + policyStr := policy.(string) + if policyStr != "" && ok { + resAffinity.Policy = &policyStr + } + poolIntf, okPool := resAff[isReservationAffinityPool] + if okPool { + 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 + } + } + } + instanceproto.ReservationAffinity = resAffinity + } if placementGroupInf, ok := d.GetOk(isPlacementTargetPlacementGroup); ok { placementGrpStr := placementGroupInf.(string) @@ -1567,6 +2159,31 @@ func instanceTemplateGet(d *schema.ResourceData, meta interface{}, ID string) er d.Set(isInstanceTemplateAvailablePolicyHostFailure, instance.AvailabilityPolicy.HostFailure) } + // vni if any + if !core.IsNil(instance.NetworkAttachments) { + networkAttachments := []map[string]interface{}{} + for _, networkAttachmentsItem := range instance.NetworkAttachments { + networkAttachmentsItemMap, err := resourceIBMIsInstanceTemplateNetworkAttachmentReferenceToMap(&networkAttachmentsItem, instanceC) + if err != nil { + return err + } + networkAttachments = append(networkAttachments, networkAttachmentsItemMap) + } + if err = d.Set("network_attachments", networkAttachments); err != nil { + return fmt.Errorf("[ERROR] Error setting network_attachments: %s", err) + } + } + + if !core.IsNil(instance.PrimaryNetworkAttachment) { + primaryNetworkAttachmentMap, err := resourceIBMIsInstanceTemplateNetworkAttachmentReferenceToMap(instance.PrimaryNetworkAttachment, instanceC) + if err != nil { + return err + } + if err = d.Set("primary_network_attachment", []map[string]interface{}{primaryNetworkAttachmentMap}); err != nil { + return fmt.Errorf("[ERROR] Error setting primary_network_attachment: %s", err) + } + } + // catalog offering if any if instance.CatalogOffering != nil { @@ -1587,6 +2204,27 @@ func instanceTemplateGet(d *schema.ResourceData, meta interface{}, ID string) er } + if instance.ReservationAffinity != nil { + reservationAffinity := []map[string]interface{}{} + reservationAffinityMap := map[string]interface{}{} + + reservationAffinityMap[isReservationAffinityPolicyResp] = instance.ReservationAffinity.Policy + if instance.ReservationAffinity.Pool != nil && len(instance.ReservationAffinity.Pool) > 0 { + pool := instance.ReservationAffinity.Pool[0] + res := "" + if idPool, ok := pool.(*vpcv1.ReservationIdentityByID); ok { + res = *idPool.ID + } else if crnPool, ok := pool.(*vpcv1.ReservationIdentityByCRN); ok { + res = *crnPool.CRN + } else if hrefPool, ok := pool.(*vpcv1.ReservationIdentityByHref); ok { + res = *hrefPool.Href + } + reservationAffinityMap[isReservationAffinityPool] = res + } + reservationAffinity = append(reservationAffinity, reservationAffinityMap) + d.Set(isReservationAffinity, reservationAffinity) + } + if instance.Profile != nil { instanceProfileIntf := instance.Profile identity := instanceProfileIntf.(*vpcv1.InstanceProfileIdentity) @@ -1936,3 +2574,217 @@ func GetInstanceTemplateMetadataServiceOptions(d *schema.ResourceData) (metadata } return nil } + +func resourceIBMIsInstanceTemplateNetworkAttachmentReferenceToMap(model *vpcv1.InstanceNetworkAttachmentPrototype, instanceC *vpcv1.VpcV1) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Name != nil { + modelMap["name"] = model.Name + } + vniMap := make(map[string]interface{}) + if model.VirtualNetworkInterface != nil { + pna := model.VirtualNetworkInterface.(*vpcv1.InstanceNetworkAttachmentPrototypeVirtualNetworkInterface) + if !core.IsNil(pna.Name) { + vniMap["name"] = pna.Name + } + if !core.IsNil(pna.ID) { + vniMap["id"] = pna.ID + } + if !core.IsNil(pna.AllowIPSpoofing) { + vniMap["allow_ip_spoofing"] = pna.AllowIPSpoofing + } + if !core.IsNil(pna.AutoDelete) { + vniMap["auto_delete"] = pna.AutoDelete + } + if !core.IsNil(pna.EnableInfrastructureNat) { + vniMap["enable_infrastructure_nat"] = pna.EnableInfrastructureNat + } + // primaryipId := *vniDetails.PrimaryIP.ID + if !core.IsNil(pna.Ips) { + ips := []map[string]interface{}{} + for _, ipsItem := range pna.Ips { + // if *ipsItem.ID != primaryipId { + ipsItemMap, err := resourceIBMIsInstanceTemplateVirtualNetworkInterfaceReservedIPReferenceToMap(ipsItem, false) + if err != nil { + return nil, err + } + ips = append(ips, ipsItemMap) + // } + } + vniMap["ips"] = ips + } + + if !core.IsNil(pna.SecurityGroups) { + securityGroups := make([]string, 0) + for _, securityGroup := range pna.SecurityGroups { + securityGroupsItem := securityGroup.(*vpcv1.SecurityGroupIdentity) + if securityGroupsItem.ID != nil { + securityGroups = append(securityGroups, *securityGroupsItem.ID) + } + } + vniMap["security_groups"] = securityGroups + } + if !core.IsNil(pna.PrimaryIP) { + primaryIPMap, err := resourceIBMIsInstanceTemplateReservedIPReferenceToMap(pna.PrimaryIP, true) + if err != nil { + return modelMap, err + } + vniMap["primary_ip"] = []map[string]interface{}{primaryIPMap} + } + if pna.Subnet != nil { + subnet := pna.Subnet.(*vpcv1.SubnetIdentity) + vniMap["subnet"] = subnet.ID + } + + modelMap["virtual_network_interface"] = []map[string]interface{}{vniMap} + } + + return modelMap, nil +} + +func resourceIBMIsInstanceTemplateVirtualNetworkInterfaceReservedIPReferenceToMap(modelIntf vpcv1.VirtualNetworkInterfaceIPPrototypeIntf, autodelete bool) (map[string]interface{}, error) { + model := modelIntf.(*vpcv1.VirtualNetworkInterfaceIPPrototype) + modelMap := make(map[string]interface{}) + modelMap["address"] = model.Address + modelMap["auto_delete"] = autodelete + modelMap["href"] = model.Href + modelMap["reserved_ip"] = model.ID + modelMap["name"] = model.Name + + return modelMap, nil +} + +func resourceIBMIsInstanceTemplateReservedIPReferenceToMap(modelIntf vpcv1.VirtualNetworkInterfacePrimaryIPPrototypeIntf, autoDelete bool) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + model := modelIntf.(*vpcv1.VirtualNetworkInterfacePrimaryIPPrototype) + modelMap["address"] = model.Address + modelMap["href"] = model.Href + modelMap["auto_delete"] = autoDelete + modelMap["reserved_ip"] = model.ID + modelMap["name"] = model.Name + return modelMap, nil +} + +func resourceIBMIsInstanceTemplateMapToInstanceNetworkAttachmentPrototype(allowipspoofing, autodelete, enablenat string, d *schema.ResourceData, modelMap map[string]interface{}) (*vpcv1.InstanceNetworkAttachmentPrototype, error) { + model := &vpcv1.InstanceNetworkAttachmentPrototype{} + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + + VirtualNetworkInterfaceModel, err := resourceIBMIsInstanceTemplateMapToVirtualNetworkInterfacePrototypeAttachmentContext(allowipspoofing, autodelete, enablenat, d, modelMap["virtual_network_interface"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.VirtualNetworkInterface = VirtualNetworkInterfaceModel + return model, nil +} + +func resourceIBMIsInstanceTemplateMapToVirtualNetworkInterfacePrototypeAttachmentContext(allowipspoofing, autodelete, enablenat string, d *schema.ResourceData, modelMap map[string]interface{}) (vpcv1.InstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceIntf, error) { + model := &vpcv1.InstanceNetworkAttachmentPrototypeVirtualNetworkInterface{} + if allowipspoofingOk, ok := d.GetOkExists(allowipspoofing); ok { + model.AllowIPSpoofing = core.BoolPtr(allowipspoofingOk.(bool)) + } + if autodeleteOk, ok := d.GetOkExists(autodelete); ok { + model.AutoDelete = core.BoolPtr(autodeleteOk.(bool)) + } + if enablenatok, ok := d.GetOkExists(enablenat); ok { + model.EnableInfrastructureNat = core.BoolPtr(enablenatok.(bool)) + } + if modelMap["ips"] != nil { + ips := []vpcv1.VirtualNetworkInterfaceIPPrototypeIntf{} + for _, ipsItem := range modelMap["ips"].([]interface{}) { + ipsItemModel, err := resourceIBMIsInstanceTemplateMapToVirtualNetworkInterfaceIPsReservedIPPrototype(ipsItem.(map[string]interface{})) + if err != nil { + return model, err + } + ips = append(ips, ipsItemModel) + } + model.Ips = ips + } + 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 := resourceIBMIsInstanceTemplateMapToVirtualNetworkInterfacePrimaryIPReservedIPPrototype(modelMap["primary_ip"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.PrimaryIP = PrimaryIPModel + } + if modelMap["resource_group"] != nil && modelMap["resource_group"].(string) != "" { + resourcegroupid := modelMap["resource_group"].(string) + model.ResourceGroup = &vpcv1.ResourceGroupIdentity{ + ID: &resourcegroupid, + } + } + if modelMap["security_groups"] != nil { + securityGroups := []vpcv1.SecurityGroupIdentityIntf{} + sg := modelMap["security_groups"].(*schema.Set) + for _, v := range sg.List() { + value := v.(string) + securityGroupsItem := &vpcv1.SecurityGroupIdentity{ + ID: &value, + } + securityGroups = append(securityGroups, securityGroupsItem) + } + model.SecurityGroups = securityGroups + } + if modelMap["subnet"] != nil && modelMap["subnet"].(string) != "" { + subnetId := modelMap["subnet"].(string) + model.Subnet = &vpcv1.SubnetIdentityByID{ + ID: &subnetId, + } + } + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + return model, nil +} + +func resourceIBMIsInstanceTemplateMapToVirtualNetworkInterfaceIPsReservedIPPrototype(modelMap map[string]interface{}) (vpcv1.VirtualNetworkInterfaceIPPrototypeIntf, error) { + model := &vpcv1.VirtualNetworkInterfaceIPPrototype{} + if modelMap["reserved_ip"] != nil && modelMap["reserved_ip"].(string) != "" { + model.ID = core.StringPtr(modelMap["reserved_ip"].(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 resourceIBMIsInstanceTemplateMapToVirtualNetworkInterfacePrimaryIPReservedIPPrototype(modelMap map[string]interface{}) (vpcv1.VirtualNetworkInterfacePrimaryIPPrototypeIntf, error) { + model := &vpcv1.VirtualNetworkInterfacePrimaryIPPrototype{} + if modelMap["reserved_ip"] != nil && modelMap["reserved_ip"].(string) != "" { + model.ID = core.StringPtr(modelMap["reserved_ip"].(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 hashIpsListForInstanceTemplate(v interface{}) int { + var buf bytes.Buffer + a := v.(map[string]interface{}) + // buf.WriteString(fmt.Sprintf("%s-", a["address"].(string))) + buf.WriteString(fmt.Sprintf("%s-", a["reserved_ip"].(string))) + buf.WriteString(fmt.Sprintf("%s-", a["address"].(string))) + return conns.String(buf.String()) +} 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 31af702aa8..c4054b4266 100644 --- a/ibm/service/vpc/resource_ibm_is_instance_template_test.go +++ b/ibm/service/vpc/resource_ibm_is_instance_template_test.go @@ -44,6 +44,37 @@ func TestAccIBMISInstanceTemplate_basic(t *testing.T) { }, }) } +func TestAccIBMISInstanceTemplate_vni(t *testing.T) { + randInt := 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 + `) + vpcName := fmt.Sprintf("tf-testvpc%d", randInt) + 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: testAccCheckIBMISInstanceTemplateVniConfig(vpcName, subnetName, sshKeyName, publicKey, templateName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_is_instance_template.instancetemplate1", "name", templateName), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_template.instancetemplate1", "profile"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_template.instancetemplate1", "primary_network_attachment"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_template.instancetemplate1", "primary_network_attachment.0.virtual_network_interface"), + ), + }, + }, + }) +} func TestAccIBMISInstanceTemplate_catalog_basic(t *testing.T) { randInt := acctest.RandIntRange(10, 100) @@ -77,6 +108,40 @@ func TestAccIBMISInstanceTemplate_catalog_basic(t *testing.T) { }, }) } + +func TestAccIBMISInstanceTemplate_Reservation(t *testing.T) { + randInt := 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 + `) + vpcName := fmt.Sprintf("tf-testvpc%d", randInt) + 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: testAccCheckIBMISInstanceTemplateReservationConfig(vpcName, subnetName, sshKeyName, publicKey, templateName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_is_instance_template.instancetemplate1", "name", templateName), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_template.instancetemplate1", "profile"), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "reservation_affinity.0.policy", "manual"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.testacc_instance", "reservation_affinity.0.pool"), + resource.TestCheckNoResourceAttr( + "ibm_is_instance_template.instancetemplate1", "image"), + ), + }, + }, + }) +} func TestAccIBMISInstanceTemplate_Reserved_IP_basic(t *testing.T) { randInt := acctest.RandIntRange(10, 100) @@ -290,6 +355,50 @@ func testAccCheckIBMISInstanceTemplateConfig(vpcName, subnetName, sshKeyName, pu `, vpcName, subnetName, sshKeyName, publicKey, templateName) +} +func testAccCheckIBMISInstanceTemplateVniConfig(vpcName, subnetName, sshKeyName, publicKey, templateName string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "vpc2" { + name = "%s" + } + + resource "ibm_is_subnet" "subnet2" { + name = "%s" + vpc = ibm_is_vpc.vpc2.id + zone = "us-south-2" + ipv4_cidr_block = "10.240.64.0/28" + } + + resource "ibm_is_ssh_key" "sshkey" { + name = "%s" + public_key = "%s" + } + + data "ibm_is_images" "is_images" { + } + + resource "ibm_is_instance_template" "instancetemplate1" { + name = "%s" + image = data.ibm_is_images.is_images.images.0.id + profile = "bx2-8x32" + + primary_network_attachment { + name = "vni-2-test" + virtual_network_interface { + primary_ip { + auto_delete = true + } + subnet = ibm_is_subnet.subnet2.id + } + } + vpc = ibm_is_vpc.vpc2.id + zone = "us-south-2" + keys = [ibm_is_ssh_key.sshkey.id] + } + + + `, vpcName, subnetName, sshKeyName, publicKey, templateName) + } func testAccCheckIBMISInstanceTemplateCatalogConfig(vpcName, subnetName, sshKeyName, publicKey, templateName string) string { return fmt.Sprintf(` @@ -332,6 +441,51 @@ func testAccCheckIBMISInstanceTemplateCatalogConfig(vpcName, subnetName, sshKeyN `, vpcName, subnetName, sshKeyName, publicKey, templateName) +} + +func testAccCheckIBMISInstanceTemplateReservationConfig(vpcName, subnetName, sshKeyName, publicKey, templateName string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "vpc2" { + name = "%s" + } + + resource "ibm_is_subnet" "subnet2" { + name = "%s" + vpc = ibm_is_vpc.vpc2.id + zone = "us-south-2" + ipv4_cidr_block = "10.240.64.0/28" + } + + resource "ibm_is_ssh_key" "sshkey" { + name = "%s" + public_key = "%s" + } + + data "ibm_is_images" "is_images" { + catalog_managed = true + } + + resource "ibm_is_instance_template" "instancetemplate1" { + name = "%s" + profile = "bx2-2x8" + + primary_network_interface { + subnet = ibm_is_subnet.subnet2.id + } + reservation_affinity { + policy = "manual" + pool { + id = "0735-b4a78f50-33bd-44f9-a3ff-4c33f444459d" + } + } + vpc = ibm_is_vpc.vpc2.id + zone = "us-south-2" + keys = [ibm_is_ssh_key.sshkey.id] + } + + + `, vpcName, subnetName, sshKeyName, publicKey, templateName) + } func testAccCheckIBMISInstanceTemplateRipConfig(vpcName, subnetName, sshKeyName, publicKey, templateName string) string { return fmt.Sprintf(` diff --git a/ibm/service/vpc/resource_ibm_is_instance_test.go b/ibm/service/vpc/resource_ibm_is_instance_test.go index 6d0b0055b8..9f3c74ac70 100644 --- a/ibm/service/vpc/resource_ibm_is_instance_test.go +++ b/ibm/service/vpc/resource_ibm_is_instance_test.go @@ -75,6 +75,125 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE }, }) } +func TestAccIBMISInstance_vni(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 +`) + vniname := fmt.Sprintf("tf-vni-%d", acctest.RandIntRange(10, 100)) + 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: testAccCheckIBMISInstanceVniConfig(vpcname, subnetname, sshname, publicKey, name, vniname, 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", "primary_network_attachment.#"), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "primary_network_attachment.#", "1"), + ), + }, + }, + }) +} +func TestAccIBMISInstance_vni_update(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 +`) + vniname := fmt.Sprintf("tf-vni-%d", acctest.RandIntRange(10, 100)) + inlinevniname := fmt.Sprintf("tf-inlinevni-%d", acctest.RandIntRange(10, 100)) + inlinevniupdatedname := fmt.Sprintf("tf-inlinevniupd-%d", acctest.RandIntRange(10, 100)) + pnaName := fmt.Sprintf("tf-pna-%d", acctest.RandIntRange(10, 100)) + snaName := fmt.Sprintf("tf-sna-%d", acctest.RandIntRange(10, 100)) + snaNameUpdated := fmt.Sprintf("tf-sna-upd-%d", acctest.RandIntRange(10, 100)) + pnaNameUpdated := fmt.Sprintf("tf-pna-upd-%d", acctest.RandIntRange(10, 100)) + 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: testAccCheckIBMISInstanceVniUpdateConfig(vpcname, subnetname, sshname, publicKey, name, vniname, inlinevniname, pnaName, snaName, 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", "primary_network_attachment.#"), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "primary_network_attachment.#", "1"), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "primary_network_attachment.0.name", pnaName), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "network_attachments.0.name", snaName), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "network_attachments.0.virtual_network_interface.0.name", inlinevniname), + ), + }, + { + Config: testAccCheckIBMISInstanceVniUpdateConfig(vpcname, subnetname, sshname, publicKey, name, vniname, inlinevniupdatedname, pnaNameUpdated, snaNameUpdated, 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", "primary_network_attachment.#"), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "primary_network_attachment.#", "1"), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "primary_network_attachment.0.name", pnaNameUpdated), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "network_attachments.0.name", snaNameUpdated), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "network_attachments.0.virtual_network_interface.0.name", inlinevniupdatedname), + ), + }, + }, + }) +} + func TestAccIBMISInstance_enc_catalog(t *testing.T) { var instance string vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) @@ -252,6 +371,54 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE }, }) } +func TestAccIBMISInstance_RenameBoot(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" + rename1 := fmt.Sprintf("tf-bootvol-%d", acctest.RandIntRange(10, 100)) + rename2 := fmt.Sprintf("tf-bootvol-update-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceRenameConfig(vpcname, subnetname, sshname, publicKey, name, userData1, rename1), + 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", "boot_volume.0.name", rename1), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "zone", acc.ISZoneName), + ), + }, + { + Config: testAccCheckIBMISInstanceRenameConfig(vpcname, subnetname, sshname, publicKey, name, userData1, rename2), + 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", "boot_volume.0.name", rename2), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "zone", acc.ISZoneName), + ), + }, + }, + }) +} func TestAccIBMISInstance_bootVolumeUserTags(t *testing.T) { var instance string @@ -895,6 +1062,39 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE }) } +func TestAccIBMISInstance_Reservation(t *testing.T) { + var instance string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instance-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceReservation(vpcname, subnetname, name, publicKey, sshname), + 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.ISZoneName3), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "reservation_affinity.0.policy", "manual"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.testacc_instance", "reservation_affinity.0.pool"), + ), + }, + }, + }) +} + func testAccCheckIBMISInstanceDestroy(s *terraform.State) error { instanceC, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() @@ -1090,6 +1290,98 @@ func testAccCheckIBMISInstanceConfig(vpcname, subnetname, sshname, publicKey, na } }`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, userData, acc.ISZoneName) } +func testAccCheckIBMISInstanceVniConfig(vpcname, subnetname, sshname, publicKey, name, vniname, 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_virtual_network_interface" "testacc_vni"{ + name = "%s" + allow_ip_spoofing = true + subnet = ibm_is_subnet.testacc_subnet.id +} + +resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_attachment { + name = "test-vni" + virtual_network_interface { + id = ibm_is_virtual_network_interface.testacc_vni.id + } + } + user_data = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] +}`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, vniname, name, acc.IsImage, acc.InstanceProfileName, userData, acc.ISZoneName) +} +func testAccCheckIBMISInstanceVniUpdateConfig(vpcname, subnetname, sshname, publicKey, name, vniname, inlinevniname, pnaName, snaName, 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_virtual_network_interface" "testacc_vni"{ + name = "%s" + allow_ip_spoofing = true + subnet = ibm_is_subnet.testacc_subnet.id +} + +resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_attachment { + name = "%s" + virtual_network_interface { + id = ibm_is_virtual_network_interface.testacc_vni.id + } + } + network_attachments { + name = "%s" + virtual_network_interface { + name = "%s" + primary_ip { + auto_delete = true + address = cidrhost(ibm_is_subnet.testacc_subnet.ipv4_cidr_block, 23) + } + 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] +}`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, vniname, name, acc.IsImage, acc.InstanceProfileName, pnaName, snaName, inlinevniname, userData, acc.ISZoneName) +} + func testAccCheckIBMISInstanceCatEncryptionConfig(vpcname, subnetname, sshname, publicKey, name, userData, resourceName, keyName string) string { return fmt.Sprintf(` resource "ibm_is_vpc" "testacc_vpc" { @@ -1219,6 +1511,41 @@ func testAccCheckIBMISInstanceResizeConfig(vpcname, subnetname, sshname, publicK keys = [ibm_is_ssh_key.testacc_sshkey.id] }`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, resize, userData, acc.ISZoneName) } +func testAccCheckIBMISInstanceRenameConfig(vpcname, subnetname, sshname, publicKey, name, userData, rename 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" + boot_volume { + name = "%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] + } + `, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, rename, userData, acc.ISZoneName) +} func testAccCheckIBMISInstanceBandwidthConfig(vpcname, subnetname, sshname, publicKey, name string, bandwidth int) string { return fmt.Sprintf(` @@ -1734,7 +2061,45 @@ func testAccCheckIBMISInstancePlacement(vpcname, subnetname, sshname, publicKey, name = "%s" } - `, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, volName, acc.ISZoneName, name, acc.IsImage, acc.InstanceProfileName, acc.DedicatedHostGroupID, acc.ISZoneName, acc.DedicatedHostName) + `, vpcname, subnetname, acc.ISZoneName3, acc.ISCIDR, sshname, publicKey, volName, acc.ISZoneName3, name, acc.IsImage, acc.InstanceProfileName, acc.DedicatedHostGroupID, acc.ISZoneName, acc.DedicatedHostName) +} + +func testAccCheckIBMISInstanceReservation(vpcname, subnetname, name, publickey, sshname string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + resource "ibm_is_ssh_key" "testacc_keyres" { + name = "%s" + public_key = "%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_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + reservation_affinity { + policy = "manual" + pool { + id = "0735-b4a78f50-33bd-44f9-a3ff-4c33f444459d" + } + } + keys = [ibm_is_ssh_key.testacc_keyres.id] + } + + `, vpcname, sshname, publickey, subnetname, acc.ISZoneName3, name, acc.IsImage2, acc.InstanceProfileName, acc.ISZoneName3) } func testAccCheckIBMISInstanceByVolume(vpcname, subnetname, sshname, publicKey, volName, name, name1, sname string) string { diff --git a/ibm/service/vpc/resource_ibm_is_lb_listener.go b/ibm/service/vpc/resource_ibm_is_lb_listener.go index 767a1d16ae..84ee4ee34e 100644 --- a/ibm/service/vpc/resource_ibm_is_lb_listener.go +++ b/ibm/service/vpc/resource_ibm_is_lb_listener.go @@ -4,6 +4,7 @@ package vpc import ( + "context" "fmt" "log" "strings" @@ -12,7 +13,9 @@ import ( "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" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -41,12 +44,12 @@ const ( func ResourceIBMISLBListener() *schema.Resource { return &schema.Resource{ - Create: resourceIBMISLBListenerCreate, - Read: resourceIBMISLBListenerRead, - Update: resourceIBMISLBListenerUpdate, - Delete: resourceIBMISLBListenerDelete, - Exists: resourceIBMISLBListenerExists, - Importer: &schema.ResourceImporter{}, + CreateContext: resourceIBMISLBListenerCreate, + ReadContext: resourceIBMISLBListenerRead, + UpdateContext: resourceIBMISLBListenerUpdate, + DeleteContext: resourceIBMISLBListenerDelete, + Exists: resourceIBMISLBListenerExists, + Importer: &schema.ResourceImporter{}, Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(10 * time.Minute), @@ -115,26 +118,86 @@ func ResourceIBMISLBListener() *schema.Resource { }, isLBListenerHTTPSRedirectStatusCode: { - Type: schema.TypeInt, - Optional: true, - RequiredWith: []string{isLBListenerHTTPSRedirectListener}, - Description: "The HTTP status code to be returned in the redirect response", + Type: schema.TypeInt, + Optional: true, + RequiredWith: []string{isLBListenerHTTPSRedirectListener}, + ConflictsWith: []string{"https_redirect"}, + Deprecated: "Please use the argument 'https_redirect'", + Description: "The HTTP status code to be returned in the redirect response", }, isLBListenerHTTPSRedirectURI: { - Type: schema.TypeString, - Optional: true, - RequiredWith: []string{isLBListenerHTTPSRedirectStatusCode, isLBListenerHTTPSRedirectListener}, - Description: "Target URI where traffic will be redirected", + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"https_redirect"}, + Deprecated: "Please use the argument 'https_redirect'", + RequiredWith: []string{isLBListenerHTTPSRedirectStatusCode, isLBListenerHTTPSRedirectListener}, + Description: "Target URI where traffic will be redirected", }, isLBListenerHTTPSRedirectListener: { - Type: schema.TypeString, - Optional: true, - RequiredWith: []string{isLBListenerHTTPSRedirectStatusCode}, - Description: "ID of the listener that will be set as http redirect target", + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"https_redirect"}, + Deprecated: "Please use the argument 'https_redirect'", + RequiredWith: []string{isLBListenerHTTPSRedirectStatusCode}, + Description: "ID of the listener that will be set as http redirect target", + }, + "https_redirect": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + ConflictsWith: []string{"https_redirect_status_code", "https_redirect_uri", "https_redirect_listener"}, + Description: "If present, the target listener that requests are redirected to.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "http_status_code": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + Description: "The HTTP status code for this redirect.", + }, + "listener": &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 listener's canonical URL.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The unique identifier for this load balancer listener.", + }, + }, + }, + }, + "uri": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The redirect relative target URI.", + }, + }, + }, }, - isLBListenerConnectionLimit: { Type: schema.TypeInt, Optional: true, @@ -209,7 +272,7 @@ func ResourceIBMISLBListenerValidator() *validate.ResourceValidator { return &ibmISLBListenerResourceValidator } -func resourceIBMISLBListenerCreate(d *schema.ResourceData, meta interface{}) error { +func resourceIBMISLBListenerCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { log.Printf("[DEBUG] LB Listener create") lbID := d.Get(isLBListenerLBID).(string) @@ -221,7 +284,7 @@ func resourceIBMISLBListenerCreate(d *schema.ResourceData, meta interface{}) err if pool, ok := d.GetOk(isLBListenerDefaultPool); ok { lbPool, err := getPoolId(pool.(string)) if err != nil { - return err + diag.FromErr(err) } defPool = lbPool } @@ -263,13 +326,13 @@ func resourceIBMISLBListenerCreate(d *schema.ResourceData, meta interface{}) err return err } - return resourceIBMISLBListenerRead(d, meta) + return resourceIBMISLBListenerRead(context, d, meta) } -func lbListenerCreate(d *schema.ResourceData, meta interface{}, lbID, protocol, defPool, certificateCRN, listener, uri string, port, portMin, portMax, connLimit, httpStatusCode int64) error { +func lbListenerCreate(d *schema.ResourceData, meta interface{}, lbID, protocol, defPool, certificateCRN, listener, uri string, port, portMin, portMax, connLimit, httpStatusCode int64) diag.Diagnostics { sess, err := vpcClient(meta) if err != nil { - return err + return diag.FromErr(err) } options := &vpcv1.CreateLoadBalancerListenerOptions{ @@ -283,11 +346,11 @@ func lbListenerCreate(d *schema.ResourceData, meta interface{}, lbID, protocol, lb, response, err := sess.GetLoadBalancer(getlboptions) if err != nil || lb == nil { - return fmt.Errorf("[ERROR] Error getting Load Balancer : %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] Error getting Load Balancer : %s\n%s", err, response)) } if lb != nil && *lb.RouteMode && lb.Profile != nil && *lb.Profile.Name == "network-fixed" { if portMin > 0 && portMax > 0 && portMin != 1 && portMax != 65535 { - return fmt.Errorf("[ERROR] Only acceptable value for port_min is 1 and port_max is 65535 for route_mode enabled private network load balancer") + return diag.FromErr(fmt.Errorf("[ERROR] Only acceptable value for port_min is 1 and port_max is 65535 for route_mode enabled private network load balancer")) } pmin := int64(1) pmax := int64(65535) @@ -297,8 +360,8 @@ func lbListenerCreate(d *schema.ResourceData, meta interface{}, lbID, protocol, } else if lb != nil && lb.Profile != nil { if strings.EqualFold(*lb.Profile.Family, "network") && *lb.IsPublic { if port == 0 && (portMin == 0 || portMax == 0) { - return fmt.Errorf( - "[ERROR] Error port_min(%d)/port_max(%d) for public network load balancer(%s) needs to be in between 1-65335", portMin, portMax, lbID) + return diag.FromErr(fmt.Errorf( + "[ERROR] Error port_min(%d)/port_max(%d) for public network load balancer(%s) needs to be in between 1-65335", portMin, portMax, lbID)) } else { if port != 0 { options.Port = &port @@ -308,7 +371,7 @@ func lbListenerCreate(d *schema.ResourceData, meta interface{}, lbID, protocol, } } } else if portMin != portMax { - return fmt.Errorf("[ERROR] Listener port_min and port_max values have to be equal for ALB and private NLB (excluding route mode)") + return diag.FromErr(fmt.Errorf("[ERROR] Listener port_min and port_max values have to be equal for ALB and private NLB (excluding route mode)")) } else { if port != 0 && (portMin == 0 || port == portMin) { options.Port = &port @@ -345,6 +408,13 @@ func lbListenerCreate(d *schema.ResourceData, meta interface{}, lbID, protocol, } options.HTTPSRedirect = httpsRedirect } + if _, ok := d.GetOk("https_redirect"); ok { + httpsRedirectModel, err := resourceIBMIsLbListenerMapToLoadBalancerListenerHTTPSRedirectPrototype(d.Get("https_redirect.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } + options.SetHTTPSRedirect(httpsRedirectModel) + } if certificateCRN != "" { options.CertificateInstance = &vpcv1.CertificateInstanceIdentity{ CRN: &certificateCRN, @@ -355,21 +425,21 @@ func lbListenerCreate(d *schema.ResourceData, meta interface{}, lbID, protocol, } _, err = isWaitForLBAvailable(sess, lbID, d.Timeout(schema.TimeoutCreate)) if err != nil { - return fmt.Errorf("[ERROR] Error checking for load balancer (%s) is active: %s", lbID, err) + return diag.FromErr(fmt.Errorf("[ERROR] Error checking for load balancer (%s) is active: %s", lbID, err)) } lbListener, response, err := sess.CreateLoadBalancerListener(options) if err != nil { - return fmt.Errorf("[ERROR] Error while creating Load Balanacer Listener err %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] Error while creating Load Balanacer Listener err %s\n%s", err, response)) } d.SetId(fmt.Sprintf("%s/%s", lbID, *lbListener.ID)) _, err = isWaitForLBListenerAvailable(sess, lbID, *lbListener.ID, d.Timeout(schema.TimeoutCreate)) if err != nil { - return fmt.Errorf("[ERROR] Error waiting for load balancer listener(%s) to become ready: %s", d.Id(), err) + return diag.FromErr(fmt.Errorf("[ERROR] Error waiting for load balancer listener(%s) to become ready: %s", d.Id(), err)) } _, err = isWaitForLBAvailable(sess, lbID, d.Timeout(schema.TimeoutCreate)) if err != nil { - return fmt.Errorf("[ERROR] Error waiting for load balancer (%s) to become ready: %s", lbID, err) + return diag.FromErr(fmt.Errorf("[ERROR] Error waiting for load balancer (%s) to become ready: %s", lbID, err)) } log.Printf("[INFO] Load balancer Listener : %s", *lbListener.ID) @@ -411,28 +481,28 @@ func isLBListenerRefreshFunc(sess *vpcv1.VpcV1, lbID, lbListenerID string) resou } } -func resourceIBMISLBListenerRead(d *schema.ResourceData, meta interface{}) error { +func resourceIBMISLBListenerRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { parts, err := flex.IdParts(d.Id()) if err != nil { - return err + diag.FromErr(err) } lbID := parts[0] lbListenerID := parts[1] - err = lbListenerGet(d, meta, lbID, lbListenerID) - if err != nil { - return err + diagEerr := lbListenerGet(d, meta, lbID, lbListenerID) + if diagEerr != nil { + return diagEerr } return nil } -func lbListenerGet(d *schema.ResourceData, meta interface{}, lbID, lbListenerID string) error { +func lbListenerGet(d *schema.ResourceData, meta interface{}, lbID, lbListenerID string) diag.Diagnostics { sess, err := vpcClient(meta) if err != nil { - return err + diag.FromErr(err) } getLoadBalancerListenerOptions := &vpcv1.GetLoadBalancerListenerOptions{ LoadBalancerID: &lbID, @@ -444,7 +514,7 @@ func lbListenerGet(d *schema.ResourceData, meta interface{}, lbID, lbListenerID d.SetId("") return nil } - return fmt.Errorf("[ERROR] Error Getting Load Balancer Listener : %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] Error Getting Load Balancer Listener : %s\n%s", err, response)) } d.Set(isLBListenerLBID, lbID) if lbListener.Port != nil { @@ -463,10 +533,21 @@ func lbListenerGet(d *schema.ResourceData, meta interface{}, lbID, lbListenerID d.Set(isLBListenerDefaultPool, *lbListener.DefaultPool.ID) } if lbListener.HTTPSRedirect != nil { - d.Set(isLBListenerHTTPSRedirectStatusCode, *lbListener.HTTPSRedirect.HTTPStatusCode) - d.Set(isLBListenerHTTPSRedirectListener, *lbListener.HTTPSRedirect.Listener.ID) - if lbListener.HTTPSRedirect.URI != nil { - d.Set(isLBListenerHTTPSRedirectURI, *lbListener.HTTPSRedirect.URI) + if _, ok := d.GetOk("https_redirect"); ok { + httpsRedirectMap, err := resourceIBMIsLbListenerLoadBalancerListenerHTTPSRedirectToMap(lbListener.HTTPSRedirect) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("https_redirect", []map[string]interface{}{httpsRedirectMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting https_redirect: %s", err)) + } + + } else { + d.Set(isLBListenerHTTPSRedirectStatusCode, *lbListener.HTTPSRedirect.HTTPStatusCode) + d.Set(isLBListenerHTTPSRedirectListener, *lbListener.HTTPSRedirect.Listener.ID) + if lbListener.HTTPSRedirect.URI != nil { + d.Set(isLBListenerHTTPSRedirectURI, *lbListener.HTTPSRedirect.URI) + } } } if lbListener.CertificateInstance != nil { @@ -485,34 +566,34 @@ func lbListenerGet(d *schema.ResourceData, meta interface{}, lbID, lbListenerID } lb, response, err := sess.GetLoadBalancer(getLoadBalancerOptions) if err != nil { - return fmt.Errorf("[ERROR] Error Getting Load Balancer : %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] Error Getting Load Balancer : %s\n%s", err, response)) } d.Set(flex.RelatedCRN, *lb.CRN) return nil } -func resourceIBMISLBListenerUpdate(d *schema.ResourceData, meta interface{}) error { +func resourceIBMISLBListenerUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { parts, err := flex.IdParts(d.Id()) if err != nil { - return err + diag.FromErr(err) } lbID := parts[0] lbListenerID := parts[1] - err = lbListenerUpdate(d, meta, lbID, lbListenerID) - if err != nil { - return err + diagEerr := lbListenerUpdate(d, meta, lbID, lbListenerID) + if diagEerr != nil { + return diagEerr } - return resourceIBMISLBListenerRead(d, meta) + return resourceIBMISLBListenerRead(context, d, meta) } -func lbListenerUpdate(d *schema.ResourceData, meta interface{}, lbID, lbListenerID string) error { +func lbListenerUpdate(d *schema.ResourceData, meta interface{}, lbID, lbListenerID string) diag.Diagnostics { sess, err := vpcClient(meta) if err != nil { - return err + diag.FromErr(err) } hasChanged := false var certificateInstance, defPool, protocol, listener, uri string @@ -535,7 +616,7 @@ func lbListenerUpdate(d *schema.ResourceData, meta interface{}, lbID, lbListener if d.HasChange(isLBListenerDefaultPool) { lbpool, err := getPoolId(d.Get(isLBListenerDefaultPool).(string)) if err != nil { - return err + diag.FromErr(err) } defPool = lbpool loadBalancerListenerPatchModel.DefaultPool = &vpcv1.LoadBalancerPoolIdentity{ @@ -545,28 +626,54 @@ func lbListenerUpdate(d *schema.ResourceData, meta interface{}, lbID, lbListener } httpsRedirectRemoved := false httpsURIRemoved := false - if d.HasChange(isLBListenerHTTPSRedirectListener) || d.HasChange(isLBListenerHTTPSRedirectURI) || d.HasChange(isLBListenerHTTPSRedirectStatusCode) { - hasChanged = true - listener = d.Get(isLBListenerHTTPSRedirectListener).(string) - httpStatusCode = int64(d.Get(isLBListenerHTTPSRedirectStatusCode).(int)) - uri = d.Get(isLBListenerHTTPSRedirectURI).(string) - if listener == "" { + if d.HasChange("https_redirect") { + httpsRedirect := &vpcv1.LoadBalancerListenerHTTPSRedirectPatch{} + if _, ok := d.GetOk("https_redirect"); !ok { httpsRedirectRemoved = true } else { - HTTPSRedirect := &vpcv1.LoadBalancerListenerHTTPSRedirectPatch{ - HTTPStatusCode: &httpStatusCode, - Listener: &vpcv1.LoadBalancerListenerIdentityByID{ID: &listener}, + if d.HasChange("https_redirect.0.http_status_code") { + httpStatusCode := int64(d.Get("https_redirect.0.http_status_code").(int)) + httpsRedirect.HTTPStatusCode = &httpStatusCode } - if d.HasChange(isLBListenerHTTPSRedirectURI) { + if d.HasChange("https_redirect.0.listener.0.id") { + listenerId := d.Get("https_redirect.0.listener.0.id").(string) + httpsRedirect.Listener = &vpcv1.LoadBalancerListenerIdentityByID{ID: &listenerId} + } + if d.HasChange("https_redirect.0.uri") { + uri := d.Get("https_redirect.0.uri").(string) if uri == "" { - HTTPSRedirect.URI = nil httpsURIRemoved = true } else { - HTTPSRedirect.URI = &uri + httpsRedirect.URI = &uri } } + } + loadBalancerListenerPatchModel.HTTPSRedirect = httpsRedirect + hasChanged = true + } else { + if d.HasChange(isLBListenerHTTPSRedirectListener) || d.HasChange(isLBListenerHTTPSRedirectURI) || d.HasChange(isLBListenerHTTPSRedirectStatusCode) { + hasChanged = true + listener = d.Get(isLBListenerHTTPSRedirectListener).(string) + httpStatusCode = int64(d.Get(isLBListenerHTTPSRedirectStatusCode).(int)) + uri = d.Get(isLBListenerHTTPSRedirectURI).(string) + if listener == "" { + httpsRedirectRemoved = true + } else { + HTTPSRedirect := &vpcv1.LoadBalancerListenerHTTPSRedirectPatch{ + HTTPStatusCode: &httpStatusCode, + Listener: &vpcv1.LoadBalancerListenerIdentityByID{ID: &listener}, + } + if d.HasChange(isLBListenerHTTPSRedirectURI) { + if uri == "" { + HTTPSRedirect.URI = nil + httpsURIRemoved = true + } else { + HTTPSRedirect.URI = &uri + } + } - loadBalancerListenerPatchModel.HTTPSRedirect = HTTPSRedirect + loadBalancerListenerPatchModel.HTTPSRedirect = HTTPSRedirect + } } } if _, ok := d.GetOk(isLBListenerPort); ok && d.HasChange(isLBListenerPort) { @@ -610,7 +717,7 @@ func lbListenerUpdate(d *schema.ResourceData, meta interface{}, lbID, lbListener if hasChanged { loadBalancerListenerPatch, err := loadBalancerListenerPatchModel.AsPatch() if err != nil { - return fmt.Errorf("[ERROR] Error calling asPatch for LoadBalancerListenerPatch: %s", err) + return diag.FromErr(fmt.Errorf("[ERROR] Error calling asPatch for LoadBalancerListenerPatch: %s", err)) } if httpsRedirectRemoved { loadBalancerListenerPatch["https_redirect"] = nil @@ -626,34 +733,34 @@ func lbListenerUpdate(d *schema.ResourceData, meta interface{}, lbID, lbListener _, err = isWaitForLBAvailable(sess, lbID, d.Timeout(schema.TimeoutUpdate)) if err != nil { - return fmt.Errorf( - "Error checking for load balancer (%s) is active: %s", lbID, err) + return diag.FromErr(fmt.Errorf( + "Error checking for load balancer (%s) is active: %s", lbID, err)) } _, response, err := sess.UpdateLoadBalancerListener(updateLoadBalancerListenerOptions) if err != nil { - return fmt.Errorf("[ERROR] Error Updating Load Balancer Listener : %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] Error Updating Load Balancer Listener : %s\n%s", err, response)) } _, err = isWaitForLBListenerAvailable(sess, lbID, lbListenerID, d.Timeout(schema.TimeoutUpdate)) if err != nil { - return fmt.Errorf( - "Error waiting for load balancer listener(%s) to become ready: %s", d.Id(), err) + return diag.FromErr(fmt.Errorf( + "Error waiting for load balancer listener(%s) to become ready: %s", d.Id(), err)) } _, err = isWaitForLBAvailable(sess, lbID, d.Timeout(schema.TimeoutUpdate)) if err != nil { - return fmt.Errorf( - "Error waiting for load balancer (%s) to become ready: %s", lbID, err) + return diag.FromErr(fmt.Errorf( + "Error waiting for load balancer (%s) to become ready: %s", lbID, err)) } } return nil } -func resourceIBMISLBListenerDelete(d *schema.ResourceData, meta interface{}) error { +func resourceIBMISLBListenerDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { parts, err := flex.IdParts(d.Id()) if err != nil { - return err + diag.FromErr(err) } lbID := parts[0] @@ -663,18 +770,18 @@ func resourceIBMISLBListenerDelete(d *schema.ResourceData, meta interface{}) err conns.IbmMutexKV.Lock(isLBKey) defer conns.IbmMutexKV.Unlock(isLBKey) - err = lbListenerDelete(d, meta, lbID, lbListenerID) - if err != nil { - return err + diagEerr := lbListenerDelete(d, meta, lbID, lbListenerID) + if diagEerr != nil { + return diagEerr } return nil } -func lbListenerDelete(d *schema.ResourceData, meta interface{}, lbID, lbListenerID string) error { +func lbListenerDelete(d *schema.ResourceData, meta interface{}, lbID, lbListenerID string) diag.Diagnostics { sess, err := vpcClient(meta) if err != nil { - return err + diag.FromErr(err) } getLoadBalancerListenerOptions := &vpcv1.GetLoadBalancerListenerOptions{ LoadBalancerID: &lbID, @@ -687,11 +794,11 @@ func lbListenerDelete(d *schema.ResourceData, meta interface{}, lbID, lbListener d.SetId("") return nil } - return fmt.Errorf("[ERROR] Error Getting vpc load balancer listener(%s): %s\n%s", lbListenerID, err, response) + return diag.FromErr(fmt.Errorf("[ERROR] Error Getting vpc load balancer listener(%s): %s\n%s", lbListenerID, err, response)) } _, err = isWaitForLBAvailable(sess, lbID, d.Timeout(schema.TimeoutDelete)) if err != nil { - return fmt.Errorf("[ERROR] Error checking for load balancer (%s) is active: %s", lbID, err) + return diag.FromErr(fmt.Errorf("[ERROR] Error checking for load balancer (%s) is active: %s", lbID, err)) } deleteLoadBalancerListenerOptions := &vpcv1.DeleteLoadBalancerListenerOptions{ LoadBalancerID: &lbID, @@ -699,15 +806,15 @@ func lbListenerDelete(d *schema.ResourceData, meta interface{}, lbID, lbListener } response, err = sess.DeleteLoadBalancerListener(deleteLoadBalancerListenerOptions) if err != nil { - return fmt.Errorf("[ERROR] Error Deleting Load Balancer Pool : %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] Error Deleting Load Balancer Pool : %s\n%s", err, response)) } _, err = isWaitForLBListenerDeleted(sess, lbID, lbListenerID, d.Timeout(schema.TimeoutDelete)) if err != nil { - return err + diag.FromErr(err) } _, err = isWaitForLBAvailable(sess, lbID, d.Timeout(schema.TimeoutDelete)) if err != nil { - return fmt.Errorf("[ERROR] Error waiting for load balancer (%s) to be active: %s", lbID, err) + return diag.FromErr(fmt.Errorf("[ERROR] Error waiting for load balancer (%s) to be active: %s", lbID, err)) } d.SetId("") @@ -782,3 +889,58 @@ func lbListenerExists(d *schema.ResourceData, meta interface{}, lbID, lbListener } return true, nil } + +func resourceIBMIsLbListenerMapToLoadBalancerListenerHTTPSRedirectPrototype(modelMap map[string]interface{}) (*vpcv1.LoadBalancerListenerHTTPSRedirectPrototype, error) { + model := &vpcv1.LoadBalancerListenerHTTPSRedirectPrototype{} + model.HTTPStatusCode = core.Int64Ptr(int64(modelMap["http_status_code"].(int))) + ListenerModel, err := resourceIBMIsLbListenerMapToLoadBalancerListenerIdentity(modelMap["listener"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.Listener = ListenerModel + if modelMap["uri"] != nil && modelMap["uri"].(string) != "" { + model.URI = core.StringPtr(modelMap["uri"].(string)) + } + return model, nil +} + +func resourceIBMIsLbListenerMapToLoadBalancerListenerIdentity(modelMap map[string]interface{}) (vpcv1.LoadBalancerListenerIdentityIntf, error) { + model := &vpcv1.LoadBalancerListenerIdentity{} + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + return model, nil +} + +func resourceIBMIsLbListenerLoadBalancerListenerHTTPSRedirectToMap(model *vpcv1.LoadBalancerListenerHTTPSRedirect) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["http_status_code"] = flex.IntValue(model.HTTPStatusCode) + listenerMap, err := resourceIBMIsLbListenerLoadBalancerListenerReferenceToMap(model.Listener) + if err != nil { + return modelMap, err + } + modelMap["listener"] = []map[string]interface{}{listenerMap} + if model.URI != nil { + modelMap["uri"] = model.URI + } + return modelMap, nil +} + +func resourceIBMIsLbListenerLoadBalancerListenerReferenceToMap(model *vpcv1.LoadBalancerListenerReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Deleted != nil { + deletedMap, err := resourceIBMIsLbListenerLoadBalancerListenerReferenceDeletedToMap(model.Deleted) + if err != nil { + return modelMap, err + } + modelMap["deleted"] = []map[string]interface{}{deletedMap} + } + modelMap["href"] = model.Href + modelMap["id"] = model.ID + return modelMap, nil +} +func resourceIBMIsLbListenerLoadBalancerListenerReferenceDeletedToMap(model *vpcv1.LoadBalancerListenerReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = model.MoreInfo + return modelMap, nil +} diff --git a/ibm/service/vpc/resource_ibm_is_lb_listener_policy.go b/ibm/service/vpc/resource_ibm_is_lb_listener_policy.go index e8bf3a8d69..03ee1638ad 100644 --- a/ibm/service/vpc/resource_ibm_is_lb_listener_policy.go +++ b/ibm/service/vpc/resource_ibm_is_lb_listener_policy.go @@ -13,8 +13,9 @@ import ( "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" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -52,20 +53,12 @@ const ( func ResourceIBMISLBListenerPolicy() *schema.Resource { return &schema.Resource{ - Create: resourceIBMISLBListenerPolicyCreate, - Read: resourceIBMISLBListenerPolicyRead, - Update: resourceIBMISLBListenerPolicyUpdate, - Delete: resourceIBMISLBListenerPolicyDelete, - Exists: resourceIBMISLBListenerPolicyExists, - Importer: &schema.ResourceImporter{}, - - CustomizeDiff: customdiff.All( - customdiff.Sequence( - func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return flex.ResourceLBListenerPolicyCustomizeDiff(diff) - }, - ), - ), + CreateContext: resourceIBMISLBListenerPolicyCreate, + ReadContext: resourceIBMISLBListenerPolicyRead, + UpdateContext: resourceIBMISLBListenerPolicyUpdate, + DeleteContext: resourceIBMISLBListenerPolicyDelete, + Exists: resourceIBMISLBListenerPolicyExists, + Importer: &schema.ResourceImporter{}, Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(10 * time.Minute), @@ -114,12 +107,14 @@ func ResourceIBMISLBListenerPolicy() *schema.Resource { Type: schema.TypeInt, Optional: true, RequiredWith: []string{isLBListenerPolicyHTTPSRedirectListener}, + Deprecated: "Please use the argument 'target'", Description: "The HTTP status code to be returned in the redirect response", }, isLBListenerPolicyHTTPSRedirectURI: { Type: schema.TypeString, Optional: true, + Deprecated: "Please use the argument 'target'", RequiredWith: []string{isLBListenerPolicyHTTPSRedirectListener, isLBListenerPolicyHTTPSRedirectStatusCode}, Description: "Target URI where traffic will be redirected", }, @@ -127,6 +122,7 @@ func ResourceIBMISLBListenerPolicy() *schema.Resource { isLBListenerPolicyHTTPSRedirectListener: { Type: schema.TypeString, Optional: true, + Deprecated: "Please use the argument 'target'", RequiredWith: []string{isLBListenerPolicyHTTPSRedirectStatusCode}, Description: "ID of the listener that will be set as http redirect target", }, @@ -207,9 +203,10 @@ func ResourceIBMISLBListenerPolicy() *schema.Resource { }, isLBListenerPolicyTargetID: { - Type: schema.TypeString, - ForceNew: false, - Optional: true, + Type: schema.TypeString, + ForceNew: false, + Optional: true, + Deprecated: "Please use the argument 'target'", DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { if o == "" { return false @@ -237,6 +234,7 @@ func ResourceIBMISLBListenerPolicy() *schema.Resource { Type: schema.TypeInt, ForceNew: false, Optional: true, + Deprecated: "Please use the argument 'target'", Description: "Listener Policy target HTTPS Status code.", }, @@ -244,9 +242,106 @@ func ResourceIBMISLBListenerPolicy() *schema.Resource { Type: schema.TypeString, ForceNew: false, Optional: true, + Deprecated: "Please use the argument 'target'", Description: "Policy Target URL", }, - + "target": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + ConflictsWith: []string{"target_url", "target_http_status_code", "target_id", "target_https_redirect_listener", "target_https_redirect_uri", "target_https_redirect_status_code"}, + Description: "- If `action` is `forward`, the response is a `LoadBalancerPoolReference`- If `action` is `redirect`, the response is a `LoadBalancerListenerPolicyRedirectURL`- If `action` is `https_redirect`, the response is a `LoadBalancerListenerHTTPSRedirect`.", + 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 pool's canonical URL.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + AtLeastOneOf: []string{"target.0.id", "target.0.http_status_code", "target.0.url", "target.0.listener"}, + ConflictsWith: []string{"target.0.http_status_code", "target.0.url", "target.0.listener", "target.0.uri"}, + Description: "The unique identifier for this load balancer pool.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this load balancer pool. The name is unique across all pools for the load balancer.", + }, + "http_status_code": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + AtLeastOneOf: []string{"target.0.id", "target.0.http_status_code", "target.0.url", "target.0.listener"}, + ConflictsWith: []string{"target.0.id"}, + Description: "The HTTP status code for this redirect.", + }, + "url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + AtLeastOneOf: []string{"target.0.id", "target.0.http_status_code", "target.0.url", "target.0.listener"}, + ConflictsWith: []string{"target.0.id", "target.0.listener", "target.0.uri"}, + Description: "The redirect target URL.", + }, + "listener": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + AtLeastOneOf: []string{"target.0.id", "target.0.http_status_code", "target.0.url", "target.0.listener"}, + ConflictsWith: []string{"target.0.id", "target.0.url"}, + 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 listener's canonical URL.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The unique identifier for this load balancer listener.", + }, + }, + }, + }, + "uri": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"target.0.id", "target.0.url"}, + Description: "The redirect relative target URI.", + }, + }, + }, + }, isLBListenerPolicyStatus: { Type: schema.TypeString, Computed: true, @@ -287,7 +382,7 @@ func ResourceIBMISLBListenerPolicyValidator() *validate.ResourceValidator { return &ibmISLBListenerPolicyResourceValidator } -func resourceIBMISLBListenerPolicyCreate(d *schema.ResourceData, meta interface{}) error { +func resourceIBMISLBListenerPolicyCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { //Get the Load balancer ID lbID := d.Get(isLBListenerPolicyLBID).(string) @@ -295,7 +390,7 @@ func resourceIBMISLBListenerPolicyCreate(d *schema.ResourceData, meta interface{ //User can set listener id as combination of lbID/listenerID, parse and get the listenerID listenerID, err := getListenerID(d.Get(isLBListenerPolicyListenerID).(string)) if err != nil { - return err + return diag.FromErr(err) } action := d.Get(isLBListenerPolicyAction).(string) @@ -307,12 +402,12 @@ func resourceIBMISLBListenerPolicyCreate(d *schema.ResourceData, meta interface{ name = n.(string) } - err = lbListenerPolicyCreate(d, meta, lbID, listenerID, action, name, priority) - if err != nil { - return err + errDiag := lbListenerPolicyCreate(d, meta, lbID, listenerID, action, name, priority) + if errDiag != nil { + return errDiag } - return resourceIBMISLBListenerPolicyRead(d, meta) + return resourceIBMISLBListenerPolicyRead(context, d, meta) } func getListenerID(id string) (string, error) { @@ -341,11 +436,11 @@ func getPoolID(id string) (string, error) { } -func lbListenerPolicyCreate(d *schema.ResourceData, meta interface{}, lbID, listenerID, action, name string, priority int64) error { +func lbListenerPolicyCreate(d *schema.ResourceData, meta interface{}, lbID, listenerID, action, name string, priority int64) diag.Diagnostics { sess, err := vpcClient(meta) if err != nil { - return err + return diag.FromErr(err) } // When `action` is `forward`, `LoadBalancerPoolIdentity` is required to specify which @@ -362,69 +457,75 @@ func lbListenerPolicyCreate(d *schema.ResourceData, meta interface{}, lbID, list listener, listenerSet := d.GetOk(isLBListenerPolicyHTTPSRedirectListener) httpsStatusCode, httpsStatusSet := d.GetOk(isLBListenerPolicyHTTPSRedirectStatusCode) uri, uriSet := d.GetOk(isLBListenerPolicyHTTPSRedirectURI) + if _, ok := d.GetOk("target"); ok { + target, err = resourceIBMIsLbListenerPolicyMapToLoadBalancerListenerPolicyTargetPrototype(d.Get("target.0").(map[string]interface{})) + if err != nil { + return diag.FromErr(err) + } - if actionChk.(string) == "forward" { - if targetIDSet { + } else { + if actionChk.(string) == "forward" { + if targetIDSet { - //User can set the poolId as combination of lbID/poolID, if so parse the string & get the poolID - id, err := getPoolID(tID.(string)) - if err != nil { - return err - } + //User can set the poolId as combination of lbID/poolID, if so parse the string & get the poolID + id, err := getPoolID(tID.(string)) + if err != nil { + return diag.FromErr(err) + } - target = &vpcv1.LoadBalancerListenerPolicyTargetPrototypeLoadBalancerPoolIdentity{ - ID: &id, + target = &vpcv1.LoadBalancerListenerPolicyTargetPrototypeLoadBalancerPoolIdentity{ + ID: &id, + } + } else { + return diag.FromErr(fmt.Errorf("When action is forward please specify target_id")) } - } else { - return fmt.Errorf("When action is forward please specify target_id") - } - } else if actionChk.(string) == "redirect" { + } else if actionChk.(string) == "redirect" { - urlPrototype := vpcv1.LoadBalancerListenerPolicyTargetPrototypeLoadBalancerListenerPolicyRedirectURLPrototype{} + urlPrototype := vpcv1.LoadBalancerListenerPolicyTargetPrototypeLoadBalancerListenerPolicyRedirectURLPrototype{} - if statusSet { - sc := int64(statusCode.(int)) - urlPrototype.HTTPStatusCode = &sc - } else { - return fmt.Errorf("When action is redirect please specify target_http_status_code") - } + if statusSet { + sc := int64(statusCode.(int)) + urlPrototype.HTTPStatusCode = &sc + } else { + return diag.FromErr(fmt.Errorf("When action is redirect please specify target_http_status_code")) + } - if urlSet { - link := url.(string) - urlPrototype.URL = &link - } else { - return fmt.Errorf("When action is redirect please specify target_url") - } + if urlSet { + link := url.(string) + urlPrototype.URL = &link + } else { + return diag.FromErr(fmt.Errorf("When action is redirect please specify target_url")) + } - target = &urlPrototype - } else if actionChk.(string) == "https_redirect" { + target = &urlPrototype + } else if actionChk.(string) == "https_redirect" { - urlPrototype := vpcv1.LoadBalancerListenerPolicyTargetPrototypeLoadBalancerListenerHTTPSRedirectPrototype{} + urlPrototype := vpcv1.LoadBalancerListenerPolicyTargetPrototypeLoadBalancerListenerHTTPSRedirectPrototype{} - if listenerSet { - listener := listener.(string) - urlPrototype.Listener = &vpcv1.LoadBalancerListenerIdentity{ - ID: &listener, + if listenerSet { + listener := listener.(string) + urlPrototype.Listener = &vpcv1.LoadBalancerListenerIdentity{ + ID: &listener, + } + } else { + return diag.FromErr(fmt.Errorf("When action is https_redirect please specify target_https_redirect_listener")) } - } else { - return fmt.Errorf("When action is https_redirect please specify target_https_redirect_listener") - } - if httpsStatusSet { - sc := int64(httpsStatusCode.(int)) - urlPrototype.HTTPStatusCode = &sc - } else { - return fmt.Errorf("When action is https_redirect please specify target_https_redirect_status_code") - } + if httpsStatusSet { + sc := int64(httpsStatusCode.(int)) + urlPrototype.HTTPStatusCode = &sc + } else { + return diag.FromErr(fmt.Errorf("When action is https_redirect please specify target_https_redirect_status_code")) + } - if uriSet { - link := uri.(string) - urlPrototype.URI = &link - } + if uriSet { + link := uri.(string) + urlPrototype.URI = &link + } - target = &urlPrototype + target = &urlPrototype + } } - //Read Rules rulesInfo := make([]vpcv1.LoadBalancerListenerPolicyRulePrototype, 0) if rules, rulesSet := d.GetOk(isLBListenerPolicyRules); rulesSet { @@ -477,20 +578,20 @@ func lbListenerPolicyCreate(d *schema.ResourceData, meta interface{}, lbID, list _, err = isWaitForLbAvailable(sess, lbID, d.Timeout(schema.TimeoutCreate)) if err != nil { - return fmt.Errorf( - "LB-LP Error checking for load balancer (%s) is active: %s", lbID, err) + return diag.FromErr(fmt.Errorf( + "LB-LP Error checking for load balancer (%s) is active: %s", lbID, err)) } policy, response, err := sess.CreateLoadBalancerListenerPolicy(options) if err != nil { - return fmt.Errorf("[ERROR] Error while creating lb listener policy for LB %s: Error %v Response %v", lbID, err, *response) + return diag.FromErr(fmt.Errorf("[ERROR] Error while creating lb listener policy for LB %s: Error %v Response %v", lbID, err, *response)) } d.SetId(fmt.Sprintf("%s/%s/%s", lbID, listenerID, *(policy.ID))) _, err = isWaitForLbListenerPolicyAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) if err != nil { - return err + return diag.FromErr(err) } return nil } @@ -575,21 +676,21 @@ func isLbListenerPolicyRefreshFunc(vpc *vpcv1.VpcV1, id string) resource.StateRe } } -func resourceIBMISLBListenerPolicyRead(d *schema.ResourceData, meta interface{}) error { +func resourceIBMISLBListenerPolicyRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { ID := d.Id() parts, err := flex.IdParts(ID) if err != nil { - return err + return diag.FromErr(err) } lbID := parts[0] listenerID := parts[1] policyID := parts[2] - err = lbListenerPolicyGet(d, meta, lbID, listenerID, policyID) - if err != nil { - return err + diag := lbListenerPolicyGet(d, meta, lbID, listenerID, policyID) + if diag != nil { + return diag } return nil @@ -638,29 +739,29 @@ func lbListenerPolicyExists(d *schema.ResourceData, meta interface{}, ID string) } return true, nil } -func resourceIBMISLBListenerPolicyUpdate(d *schema.ResourceData, meta interface{}) error { +func resourceIBMISLBListenerPolicyUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { parts, err := flex.IdParts(d.Id()) if err != nil { - return err + return diag.FromErr(err) } lbID := parts[0] listenerID := parts[1] policyID := parts[2] - err = lbListenerPolicyUpdate(d, meta, lbID, listenerID, policyID) - if err != nil { - return err + diagErr := lbListenerPolicyUpdate(d, meta, lbID, listenerID, policyID) + if diagErr != nil { + return diagErr } - return resourceIBMISLBListenerPolicyRead(d, meta) + return resourceIBMISLBListenerPolicyRead(context, d, meta) } -func lbListenerPolicyUpdate(d *schema.ResourceData, meta interface{}, lbID, listenerID, ID string) error { +func lbListenerPolicyUpdate(d *schema.ResourceData, meta interface{}, lbID, listenerID, ID string) diag.Diagnostics { sess, err := vpcClient(meta) if err != nil { - return err + return diag.FromErr(err) } hasChanged := false updatePolicyOptions := vpcv1.UpdateLoadBalancerListenerPolicyOptions{} @@ -683,92 +784,101 @@ func lbListenerPolicyUpdate(d *schema.ResourceData, meta interface{}, lbID, list hasChanged = true } httpsURIRemoved := false - var target vpcv1.LoadBalancerListenerPolicyTargetPatchIntf - //If Action is forward and TargetID is changed, set the target to pool ID - if d.Get(isLBListenerPolicyAction).(string) == "forward" && d.HasChange(isLBListenerPolicyTargetID) { - - //User can set the poolId as combination of lbID/poolID, if so parse the string & get the poolID - id, err := getPoolID(d.Get(isLBListenerPolicyTargetID).(string)) + if d.HasChange("target") { + target, err := resourceIBMIsLbListenerPolicyMapToLoadBalancerListenerPolicyTargetPatch(d, d.Get("target.0").(map[string]interface{}), &httpsURIRemoved) if err != nil { - return err - } - target = &vpcv1.LoadBalancerListenerPolicyTargetPatchLoadBalancerPoolIdentity{ - ID: &id, + return diag.FromErr(err) } - loadBalancerListenerPolicyPatchModel.Target = target hasChanged = true - } else if d.Get(isLBListenerPolicyAction).(string) == "redirect" { - //if Action is redirect and either status code or URL chnaged, set accordingly - //LoadBalancerListenerPolicyPatchTargetLoadBalancerListenerPolicyRedirectURLPatch - redirectPatch := vpcv1.LoadBalancerListenerPolicyTargetPatchLoadBalancerListenerPolicyRedirectURLPatch{} + } else { - targetChange := false - if d.HasChange(isLBListenerPolicyTargetHTTPStatusCode) { - status := d.Get(isLBListenerPolicyTargetHTTPStatusCode).(int) - sc := int64(status) - redirectPatch.HTTPStatusCode = &sc - hasChanged = true - targetChange = true - } + //If Action is forward and TargetID is changed, set the target to pool ID + if d.Get(isLBListenerPolicyAction).(string) == "forward" && d.HasChange(isLBListenerPolicyTargetID) { - if d.HasChange(isLBListenerPolicyTargetURL) { - url := d.Get(isLBListenerPolicyTargetURL).(string) - redirectPatch.URL = &url - hasChanged = true - targetChange = true - } + //User can set the poolId as combination of lbID/poolID, if so parse the string & get the poolID + id, err := getPoolID(d.Get(isLBListenerPolicyTargetID).(string)) + if err != nil { + return diag.FromErr(err) + } + target = &vpcv1.LoadBalancerListenerPolicyTargetPatchLoadBalancerPoolIdentity{ + ID: &id, + } - //Update the target only if there is a change in either statusCode or URL - if targetChange { - target = &redirectPatch loadBalancerListenerPolicyPatchModel.Target = target - } - } else if d.Get(isLBListenerPolicyAction).(string) == "https_redirect" { + hasChanged = true + } else if d.Get(isLBListenerPolicyAction).(string) == "redirect" { + //if Action is redirect and either status code or URL chnaged, set accordingly + //LoadBalancerListenerPolicyPatchTargetLoadBalancerListenerPolicyRedirectURLPatch + + redirectPatch := vpcv1.LoadBalancerListenerPolicyTargetPatchLoadBalancerListenerPolicyRedirectURLPatch{} + + targetChange := false + if d.HasChange(isLBListenerPolicyTargetHTTPStatusCode) { + status := d.Get(isLBListenerPolicyTargetHTTPStatusCode).(int) + sc := int64(status) + redirectPatch.HTTPStatusCode = &sc + hasChanged = true + targetChange = true + } - httpsRedirectPatch := vpcv1.LoadBalancerListenerPolicyTargetPatchLoadBalancerListenerHTTPSRedirectPatch{} + if d.HasChange(isLBListenerPolicyTargetURL) { + url := d.Get(isLBListenerPolicyTargetURL).(string) + redirectPatch.URL = &url + hasChanged = true + targetChange = true + } - targetChange := false - if d.HasChange(isLBListenerPolicyHTTPSRedirectListener) { - listener := d.Get(isLBListenerPolicyHTTPSRedirectListener).(string) - httpsRedirectPatch.Listener = &vpcv1.LoadBalancerListenerIdentity{ - ID: &listener, + //Update the target only if there is a change in either statusCode or URL + if targetChange { + target = &redirectPatch + loadBalancerListenerPolicyPatchModel.Target = target } - hasChanged = true - targetChange = true - } + } else if d.Get(isLBListenerPolicyAction).(string) == "https_redirect" { - if d.HasChange(isLBListenerPolicyHTTPSRedirectStatusCode) { - status := d.Get(isLBListenerPolicyHTTPSRedirectStatusCode).(int) - sc := int64(status) - httpsRedirectPatch.HTTPStatusCode = &sc - hasChanged = true - targetChange = true - } + httpsRedirectPatch := vpcv1.LoadBalancerListenerPolicyTargetPatchLoadBalancerListenerHTTPSRedirectPatch{} - if d.HasChange(isLBListenerPolicyHTTPSRedirectURI) { - uri := d.Get(isLBListenerPolicyHTTPSRedirectURI).(string) - httpsRedirectPatch.URI = &uri - hasChanged = true - targetChange = true - if uri == "" { - httpsURIRemoved = true + targetChange := false + if d.HasChange(isLBListenerPolicyHTTPSRedirectListener) { + listener := d.Get(isLBListenerPolicyHTTPSRedirectListener).(string) + httpsRedirectPatch.Listener = &vpcv1.LoadBalancerListenerIdentity{ + ID: &listener, + } + hasChanged = true + targetChange = true } - } - //Update the target only if there is a change in either listener, statusCode or URI - if targetChange { - target = &httpsRedirectPatch - loadBalancerListenerPolicyPatchModel.Target = target + if d.HasChange(isLBListenerPolicyHTTPSRedirectStatusCode) { + status := d.Get(isLBListenerPolicyHTTPSRedirectStatusCode).(int) + sc := int64(status) + httpsRedirectPatch.HTTPStatusCode = &sc + hasChanged = true + targetChange = true + } + + if d.HasChange(isLBListenerPolicyHTTPSRedirectURI) { + uri := d.Get(isLBListenerPolicyHTTPSRedirectURI).(string) + httpsRedirectPatch.URI = &uri + hasChanged = true + targetChange = true + if uri == "" { + httpsURIRemoved = true + } + } + + //Update the target only if there is a change in either listener, statusCode or URI + if targetChange { + target = &httpsRedirectPatch + loadBalancerListenerPolicyPatchModel.Target = target + } } } - if hasChanged { loadBalancerListenerPolicyPatch, err := loadBalancerListenerPolicyPatchModel.AsPatch() if err != nil { - return fmt.Errorf("[ERROR] Error calling asPatch for LoadBalancerListenerPolicyPatch: %s", err) + return diag.FromErr(fmt.Errorf("[ERROR] Error calling asPatch for LoadBalancerListenerPolicyPatch: %s", err)) } if httpsURIRemoved { loadBalancerListenerPolicyPatch["target"].(map[string]interface{})["uri"] = nil @@ -780,28 +890,28 @@ func lbListenerPolicyUpdate(d *schema.ResourceData, meta interface{}, lbID, list _, err = isWaitForLbAvailable(sess, lbID, d.Timeout(schema.TimeoutCreate)) if err != nil { - return fmt.Errorf( - "LB-LP Error checking for load balancer (%s) is active: %s", lbID, err) + return diag.FromErr(fmt.Errorf( + "LB-LP Error checking for load balancer (%s) is active: %s", lbID, err)) } _, response, err := sess.UpdateLoadBalancerListenerPolicy(&updatePolicyOptions) if err != nil { - return fmt.Errorf("[ERROR] Error Updating in policy : %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] Error Updating in policy : %s\n%s", err, response)) } _, err = isWaitForLbListenerPolicyAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) if err != nil { - return err + return diag.FromErr(err) } } return nil } -func resourceIBMISLBListenerPolicyDelete(d *schema.ResourceData, meta interface{}) error { +func resourceIBMISLBListenerPolicyDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { //Retrieve lbId, listenerId and policyID parts, err := flex.IdParts(d.Id()) if err != nil { - return err + return diag.FromErr(err) } lbID := parts[0] @@ -814,7 +924,7 @@ func resourceIBMISLBListenerPolicyDelete(d *schema.ResourceData, meta interface{ err = lbListenerPolicyDelete(d, meta, lbID, listenerID, policyID) if err != nil { - return err + return diag.FromErr(err) } d.SetId("") @@ -912,11 +1022,11 @@ func isLbListenerPolicyDeleteRefreshFunc(vpc *vpcv1.VpcV1, id string) resource.S } } -func lbListenerPolicyGet(d *schema.ResourceData, meta interface{}, lbID, listenerID, id string) error { +func lbListenerPolicyGet(d *schema.ResourceData, meta interface{}, lbID, listenerID, id string) diag.Diagnostics { sess, err := vpcClient(meta) if err != nil { - return err + return diag.FromErr(err) } //Getting policy optins @@ -933,7 +1043,7 @@ func lbListenerPolicyGet(d *schema.ResourceData, meta interface{}, lbID, listene d.SetId("") return nil } - return err + return diag.FromErr(err) } //set the argument values @@ -965,7 +1075,7 @@ func lbListenerPolicyGet(d *schema.ResourceData, meta interface{}, lbID, listene d.SetId("") return nil } - return err + return diag.FromErr(err) } l := map[string]interface{}{ @@ -983,41 +1093,222 @@ func lbListenerPolicyGet(d *schema.ResourceData, meta interface{}, lbID, listene // `LoadBalancerPoolReference` is in the response if `action` is `forward`. // `LoadBalancerListenerPolicyRedirectURL` is in the response if `action` is `redirect`. - if *(policy.Action) == "forward" { - if reflect.TypeOf(policy.Target).String() == "*vpcv1.LoadBalancerListenerPolicyTargetLoadBalancerPoolReference" { - target, ok := policy.Target.(*vpcv1.LoadBalancerListenerPolicyTargetLoadBalancerPoolReference) - if ok { - d.Set(isLBListenerPolicyTargetID, target.ID) - } - } + if !core.IsNil(policy.Target) { + if _, ok := d.GetOk("target"); ok { - } else if *(policy.Action) == "redirect" { - if reflect.TypeOf(policy.Target).String() == "*vpcv1.LoadBalancerListenerPolicyTargetLoadBalancerListenerPolicyRedirectURL" { - target, ok := policy.Target.(*vpcv1.LoadBalancerListenerPolicyTargetLoadBalancerListenerPolicyRedirectURL) - if ok { - d.Set(isLBListenerPolicyTargetURL, target.URL) - d.Set(isLBListenerPolicyTargetHTTPStatusCode, target.HTTPStatusCode) + targetMap, err := resourceIBMIsLbListenerPolicyLoadBalancerListenerPolicyTargetToMap(policy.Target) + if err != nil { + return diag.FromErr(err) } - } - } else if *(policy.Action) == "https_redirect" { - if reflect.TypeOf(policy.Target).String() == "*vpcv1.LoadBalancerListenerPolicyTargetLoadBalancerListenerHTTPSRedirect" { - target, ok := policy.Target.(*vpcv1.LoadBalancerListenerPolicyTargetLoadBalancerListenerHTTPSRedirect) - if ok { - d.Set(isLBListenerPolicyHTTPSRedirectListener, target.Listener.ID) - d.Set(isLBListenerPolicyHTTPSRedirectStatusCode, target.HTTPStatusCode) - d.Set(isLBListenerPolicyHTTPSRedirectURI, target.URI) + if err = d.Set("target", []map[string]interface{}{targetMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting target: %s", err)) + } + } else { + if *(policy.Action) == "forward" { + if reflect.TypeOf(policy.Target).String() == "*vpcv1.LoadBalancerListenerPolicyTargetLoadBalancerPoolReference" { + target, ok := policy.Target.(*vpcv1.LoadBalancerListenerPolicyTargetLoadBalancerPoolReference) + if ok { + d.Set(isLBListenerPolicyTargetID, target.ID) + } + } + + } else if *(policy.Action) == "redirect" { + if reflect.TypeOf(policy.Target).String() == "*vpcv1.LoadBalancerListenerPolicyTargetLoadBalancerListenerPolicyRedirectURL" { + target, ok := policy.Target.(*vpcv1.LoadBalancerListenerPolicyTargetLoadBalancerListenerPolicyRedirectURL) + if ok { + d.Set(isLBListenerPolicyTargetURL, target.URL) + d.Set(isLBListenerPolicyTargetHTTPStatusCode, target.HTTPStatusCode) + } + } + } else if *(policy.Action) == "https_redirect" { + if reflect.TypeOf(policy.Target).String() == "*vpcv1.LoadBalancerListenerPolicyTargetLoadBalancerListenerHTTPSRedirect" { + target, ok := policy.Target.(*vpcv1.LoadBalancerListenerPolicyTargetLoadBalancerListenerHTTPSRedirect) + if ok { + d.Set(isLBListenerPolicyHTTPSRedirectListener, target.Listener.ID) + d.Set(isLBListenerPolicyHTTPSRedirectStatusCode, target.HTTPStatusCode) + d.Set(isLBListenerPolicyHTTPSRedirectURI, target.URI) + } + } } } } - getLoadBalancerOptions := &vpcv1.GetLoadBalancerOptions{ ID: &lbID, } lb, response, err := sess.GetLoadBalancer(getLoadBalancerOptions) if err != nil { - return fmt.Errorf("[ERROR] Error Getting Load Balancer : %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] Error Getting Load Balancer : %s\n%s", err, response)) } d.Set(flex.RelatedCRN, *lb.CRN) return nil } + +func resourceIBMIsLbListenerPolicyMapToLoadBalancerListenerPolicyTargetPrototype(modelMap map[string]interface{}) (vpcv1.LoadBalancerListenerPolicyTargetPrototypeIntf, error) { + model := &vpcv1.LoadBalancerListenerPolicyTargetPrototype{} + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + if modelMap["http_status_code"] != nil && modelMap["http_status_code"].(int) != 0 { + model.HTTPStatusCode = core.Int64Ptr(int64(modelMap["http_status_code"].(int))) + } + if modelMap["url"] != nil && modelMap["url"].(string) != "" { + model.URL = core.StringPtr(modelMap["url"].(string)) + } + if modelMap["listener"] != nil && len(modelMap["listener"].([]interface{})) > 0 { + ListenerModel, err := resourceIBMIsLbListenerPolicyMapToLoadBalancerListenerIdentity(modelMap["listener"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.Listener = ListenerModel + } + if modelMap["uri"] != nil && modelMap["uri"].(string) != "" { + model.URI = core.StringPtr(modelMap["uri"].(string)) + } + return model, nil +} +func resourceIBMIsLbListenerPolicyMapToLoadBalancerListenerIdentity(modelMap map[string]interface{}) (vpcv1.LoadBalancerListenerIdentityIntf, error) { + model := &vpcv1.LoadBalancerListenerIdentity{} + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + return model, nil +} + +func resourceIBMIsLbListenerPolicyLoadBalancerListenerPolicyTargetToMap(model vpcv1.LoadBalancerListenerPolicyTargetIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.LoadBalancerListenerPolicyTargetLoadBalancerPoolReference); ok { + return resourceIBMIsLbListenerPolicyLoadBalancerListenerPolicyTargetLoadBalancerPoolReferenceToMap(model.(*vpcv1.LoadBalancerListenerPolicyTargetLoadBalancerPoolReference)) + } else if _, ok := model.(*vpcv1.LoadBalancerListenerPolicyTargetLoadBalancerListenerPolicyRedirectURL); ok { + return resourceIBMIsLbListenerPolicyLoadBalancerListenerPolicyTargetLoadBalancerListenerPolicyRedirectURLToMap(model.(*vpcv1.LoadBalancerListenerPolicyTargetLoadBalancerListenerPolicyRedirectURL)) + } else if _, ok := model.(*vpcv1.LoadBalancerListenerPolicyTargetLoadBalancerListenerHTTPSRedirect); ok { + return resourceIBMIsLbListenerPolicyLoadBalancerListenerPolicyTargetLoadBalancerListenerHTTPSRedirectToMap(model.(*vpcv1.LoadBalancerListenerPolicyTargetLoadBalancerListenerHTTPSRedirect)) + } else if _, ok := model.(*vpcv1.LoadBalancerListenerPolicyTarget); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.LoadBalancerListenerPolicyTarget) + if model.Deleted != nil { + deletedMap, err := resourceIBMIsLbListenerPolicyLoadBalancerPoolReferenceDeletedToMap(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.HTTPStatusCode != nil { + modelMap["http_status_code"] = flex.IntValue(model.HTTPStatusCode) + } + if model.URL != nil { + modelMap["url"] = model.URL + } + if model.Listener != nil { + listenerMap, err := resourceIBMIsLbListenerPolicyLoadBalancerListenerReferenceToMap(model.Listener) + if err != nil { + return modelMap, err + } + modelMap["listener"] = []map[string]interface{}{listenerMap} + } + if model.URI != nil { + modelMap["uri"] = model.URI + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.LoadBalancerListenerPolicyTargetIntf subtype encountered") + } +} + +func resourceIBMIsLbListenerPolicyLoadBalancerPoolReferenceDeletedToMap(model *vpcv1.LoadBalancerPoolReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = model.MoreInfo + return modelMap, nil +} + +func resourceIBMIsLbListenerPolicyLoadBalancerListenerReferenceToMap(model *vpcv1.LoadBalancerListenerReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Deleted != nil { + deletedMap, err := resourceIBMIsLbListenerPolicyLoadBalancerListenerReferenceDeletedToMap(model.Deleted) + if err != nil { + return modelMap, err + } + modelMap["deleted"] = []map[string]interface{}{deletedMap} + } + modelMap["href"] = model.Href + modelMap["id"] = model.ID + return modelMap, nil +} + +func resourceIBMIsLbListenerPolicyLoadBalancerListenerReferenceDeletedToMap(model *vpcv1.LoadBalancerListenerReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = model.MoreInfo + return modelMap, nil +} + +func resourceIBMIsLbListenerPolicyLoadBalancerListenerPolicyTargetLoadBalancerPoolReferenceToMap(model *vpcv1.LoadBalancerListenerPolicyTargetLoadBalancerPoolReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Deleted != nil { + deletedMap, err := resourceIBMIsLbListenerPolicyLoadBalancerPoolReferenceDeletedToMap(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 + return modelMap, nil +} + +func resourceIBMIsLbListenerPolicyLoadBalancerListenerPolicyTargetLoadBalancerListenerPolicyRedirectURLToMap(model *vpcv1.LoadBalancerListenerPolicyTargetLoadBalancerListenerPolicyRedirectURL) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["http_status_code"] = flex.IntValue(model.HTTPStatusCode) + modelMap["url"] = model.URL + return modelMap, nil +} + +func resourceIBMIsLbListenerPolicyLoadBalancerListenerPolicyTargetLoadBalancerListenerHTTPSRedirectToMap(model *vpcv1.LoadBalancerListenerPolicyTargetLoadBalancerListenerHTTPSRedirect) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["http_status_code"] = flex.IntValue(model.HTTPStatusCode) + listenerMap, err := resourceIBMIsLbListenerPolicyLoadBalancerListenerReferenceToMap(model.Listener) + if err != nil { + return modelMap, err + } + modelMap["listener"] = []map[string]interface{}{listenerMap} + if model.URI != nil { + modelMap["uri"] = model.URI + } + return modelMap, nil +} + +func resourceIBMIsLbListenerPolicyMapToLoadBalancerListenerPolicyTargetPatch(d *schema.ResourceData, modelMap map[string]interface{}, httpsURIRemoved *bool) (vpcv1.LoadBalancerListenerPolicyTargetPatchIntf, error) { + model := &vpcv1.LoadBalancerListenerPolicyTargetPatch{} + if d.HasChange("target.0.id") && modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + if d.HasChange("target.0.http_status_code") && modelMap["http_status_code"] != nil { + model.HTTPStatusCode = core.Int64Ptr(int64(modelMap["http_status_code"].(int))) + } + if d.HasChange("target.0.url") && modelMap["url"] != nil && modelMap["url"].(string) != "" { + model.URL = core.StringPtr(modelMap["url"].(string)) + } + if d.HasChange("target.0.listener") && modelMap["listener"] != nil && len(modelMap["listener"].([]interface{})) > 0 { + ListenerModel, err := resourceIBMIsLbListenerPolicyMapToLoadBalancerListenerIdentity(modelMap["listener"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.Listener = ListenerModel + } + if d.HasChange("target.0.uri") { + if modelMap["uri"] != nil && modelMap["uri"].(string) != "" { + model.URI = core.StringPtr(modelMap["uri"].(string)) + } else { + *httpsURIRemoved = true + } + } + return model, nil +} diff --git a/ibm/service/vpc/resource_ibm_is_lb_listener_policy_test.go b/ibm/service/vpc/resource_ibm_is_lb_listener_policy_test.go index 340fbac619..75af6db710 100644 --- a/ibm/service/vpc/resource_ibm_is_lb_listener_policy_test.go +++ b/ibm/service/vpc/resource_ibm_is_lb_listener_policy_test.go @@ -211,6 +211,58 @@ func TestAccIBMISLBListenerPolicyHttpRedirect_basic(t *testing.T) { }) } +func TestAccIBMISLBListenerPolicyHttpRedirectNew_basic(t *testing.T) { + var lb string + vpcname := fmt.Sprintf("tflblis-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tflblis-subnet-%d", acctest.RandIntRange(10, 100)) + lbname := fmt.Sprintf("tflblis%d", acctest.RandIntRange(10, 100)) + lbpolicyname := fmt.Sprintf("tflblispol%d", acctest.RandIntRange(10, 100)) + protocol1 := "https" + port1 := "9086" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISLBListenerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISLBListenerPolicyHttpsRedirectNewConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port1, protocol1, lbpolicyname), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBListenerExists("ibm_is_lb_listener_policy.lb_listener_policy", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "name", lbname), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener_policy.lb_listener_policy", "target.0.http_status_code", "302"), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener_policy.lb_listener_policy", "target.0.uri", "/example?doc=get"), + ), + }, + { + Config: testAccCheckIBMISLBListenerPolicyHttpsRedirectNewConfigUpdate(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port1, protocol1, lbpolicyname), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBListenerExists("ibm_is_lb_listener_policy.lb_listener_policy", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "name", lbname), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener_policy.lb_listener_policy", "target.0.http_status_code", "301"), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener_policy.lb_listener_policy", "target.0.uri", "/example?doc=getupdated"), + ), + }, + { + Config: testAccCheckIBMISLBListenerPolicyHttpsRedirectNewConfigRemoveUri(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port1, protocol1, lbpolicyname), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBListenerExists("ibm_is_lb_listener_policy.lb_listener_policy", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "name", lbname), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener_policy.lb_listener_policy", "target.0.http_status_code", "301"), + resource.TestCheckResourceAttr("ibm_is_lb_listener_policy.lb_listener_policy", "target.0.uri", ""), + ), + }, + }, + }) +} func testAccCheckIBMISLBListenerPolicyDestroy(s *terraform.State) error { sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() @@ -571,7 +623,174 @@ func testAccCheckIBMISLBListenerPolicyHttpsRedirectConfig(vpcname, subnetname, z }`, vpcname, subnetname, zone, cidr, lbname, acc.LbListerenerCertificateInstance, lbpolicyname) } +func testAccCheckIBMISLBListenerPolicyHttpsRedirectNewConfig(vpcname, subnetname, zone, cidr, lbname, port, protocol, lbpolicyname 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_lb" "testacc_LB" { + name = "%s" + subnets = ["${ibm_is_subnet.testacc_subnet.id}"] + } + resource "ibm_is_lb_listener" "lb_listener1"{ + lb = ibm_is_lb.testacc_LB.id + port = "9086" + protocol = "https" + certificate_instance="%s" + } + resource "ibm_is_lb_listener" "lb_listener2"{ + lb = ibm_is_lb.testacc_LB.id + port = "9087" + protocol = "http" + https_redirect { + http_status_code = 301 + listener { + id = ibm_is_lb_listener.lb_listener1.listener_id + } + uri = "/example?doc=get" + } + } + resource "ibm_is_lb_listener" "lb_listener3"{ + lb = ibm_is_lb.testacc_LB.id + port = "9088" + protocol = "https" + certificate_instance="%s" + } + + resource "ibm_is_lb_listener_policy" "lb_listener_policy" { + name = "%s" + lb = ibm_is_lb.testacc_LB.id + listener = ibm_is_lb_listener.lb_listener2.listener_id + action = "https_redirect" + target { + http_status_code = 302 + listener { + id = ibm_is_lb_listener.lb_listener1.listener_id + } + uri = "/example?doc=get" + } + priority = 2 + }`, vpcname, subnetname, zone, cidr, lbname, acc.LbListerenerCertificateInstance, acc.LbListerenerCertificateInstance, lbpolicyname) + +} +func testAccCheckIBMISLBListenerPolicyHttpsRedirectNewConfigUpdate(vpcname, subnetname, zone, cidr, lbname, port, protocol, lbpolicyname 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_lb" "testacc_LB" { + name = "%s" + subnets = ["${ibm_is_subnet.testacc_subnet.id}"] + } + resource "ibm_is_lb_listener" "lb_listener1"{ + lb = ibm_is_lb.testacc_LB.id + port = "9086" + protocol = "https" + certificate_instance="%s" + } + resource "ibm_is_lb_listener" "lb_listener2"{ + lb = ibm_is_lb.testacc_LB.id + port = "9087" + protocol = "http" + https_redirect { + http_status_code = 301 + listener { + id = ibm_is_lb_listener.lb_listener1.listener_id + } + uri = "/example?doc=get" + } + } + resource "ibm_is_lb_listener" "lb_listener3"{ + lb = ibm_is_lb.testacc_LB.id + port = "9088" + protocol = "https" + certificate_instance="%s" + } + + resource "ibm_is_lb_listener_policy" "lb_listener_policy" { + name = "%s" + lb = ibm_is_lb.testacc_LB.id + listener = ibm_is_lb_listener.lb_listener2.listener_id + action = "https_redirect" + target { + http_status_code = 301 + listener { + id = ibm_is_lb_listener.lb_listener3.listener_id + } + uri = "/example?doc=getupdated" + } + priority = 2 + }`, vpcname, subnetname, zone, cidr, lbname, acc.LbListerenerCertificateInstance, acc.LbListerenerCertificateInstance, lbpolicyname) +} +func testAccCheckIBMISLBListenerPolicyHttpsRedirectNewConfigRemoveUri(vpcname, subnetname, zone, cidr, lbname, port, protocol, lbpolicyname 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_lb" "testacc_LB" { + name = "%s" + subnets = ["${ibm_is_subnet.testacc_subnet.id}"] + } + resource "ibm_is_lb_listener" "lb_listener1"{ + lb = ibm_is_lb.testacc_LB.id + port = "9086" + protocol = "https" + certificate_instance="%s" + } + resource "ibm_is_lb_listener" "lb_listener2"{ + lb = ibm_is_lb.testacc_LB.id + port = "9087" + protocol = "http" + + https_redirect { + http_status_code = 301 + listener { + id = ibm_is_lb_listener.lb_listener1.listener_id + } + uri = "/example?doc=get" + } + } + resource "ibm_is_lb_listener" "lb_listener3"{ + lb = ibm_is_lb.testacc_LB.id + port = "9088" + protocol = "https" + certificate_instance="%s" + } + + resource "ibm_is_lb_listener_policy" "lb_listener_policy" { + name = "%s" + lb = ibm_is_lb.testacc_LB.id + listener = ibm_is_lb_listener.lb_listener2.listener_id + action = "https_redirect" + target { + http_status_code = 301 + listener { + id = ibm_is_lb_listener.lb_listener3.listener_id + } + } + priority = 2 + }`, vpcname, subnetname, zone, cidr, lbname, acc.LbListerenerCertificateInstance, acc.LbListerenerCertificateInstance, lbpolicyname) + +} func testAccCheckIBMISLBListenerPolicyHttpsRedirectConfigUpdate(vpcname, subnetname, zone, cidr, lbname, port, protocol, lbpolicyname string) string { return fmt.Sprintf(` resource "ibm_is_vpc" "testacc_vpc" { diff --git a/ibm/service/vpc/resource_ibm_is_lb_listener_test.go b/ibm/service/vpc/resource_ibm_is_lb_listener_test.go index 68ac22f588..ed74208173 100644 --- a/ibm/service/vpc/resource_ibm_is_lb_listener_test.go +++ b/ibm/service/vpc/resource_ibm_is_lb_listener_test.go @@ -299,6 +299,69 @@ func TestAccIBMISLBListenerHttpRedirect_basic(t *testing.T) { }, }) } +func TestAccIBMISLBListenerHttpRedirectNew_basic(t *testing.T) { + var lb string + vpcname := fmt.Sprintf("tflblis-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tflblis-subnet-%d", acctest.RandIntRange(10, 100)) + lbname := fmt.Sprintf("tflblis%d", acctest.RandIntRange(10, 100)) + + protocol1 := "https" + port1 := "9086" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISLBListenerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISLBListenerHttpsRedirectNewConfig(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port1, protocol1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBListenerExists("ibm_is_lb_listener.lb_listener2", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "name", lbname), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener.lb_listener2", "https_redirect.0.http_status_code", "302"), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener.lb_listener2", "https_redirect.0.uri", "/example?doc=get"), + ), + }, + { + Config: testAccCheckIBMISLBListenerHttpsRedirectNewConfigUpdate(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port1, protocol1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBListenerExists("ibm_is_lb_listener.lb_listener2", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "name", lbname), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener.lb_listener2", "https_redirect.0.http_status_code", "303"), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener.lb_listener2", "https_redirect.0.uri", "/example?doc=getupdated"), + ), + }, + { + Config: testAccCheckIBMISLBListenerHttpsRedirectNewConfigURIRemove(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port1, protocol1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBListenerExists("ibm_is_lb_listener.lb_listener2", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "name", lbname), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener.lb_listener2", "https_redirect.0.http_status_code", "303"), + resource.TestCheckResourceAttr( + "ibm_is_lb_listener.lb_listener2", "https_redirect.0.uri", ""), + ), + }, + { + Config: testAccCheckIBMISLBListenerHttpsRedirectNewConfigRemove(vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, lbname, port1, protocol1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISLBListenerExists("ibm_is_lb_listener.lb_listener2", lb), + resource.TestCheckResourceAttr( + "ibm_is_lb.testacc_LB", "name", lbname), + resource.TestCheckNoResourceAttr( + "ibm_is_lb_listener.lb_listener2", "https_redirect.#"), + ), + }, + }, + }) +} func testAccCheckIBMISLBListenerDestroy(s *terraform.State) error { @@ -536,6 +599,151 @@ func testAccCheckIBMISLBListenerHttpsRedirectConfigRemove(vpcname, subnetname, z }`, vpcname, subnetname, zone, cidr, lbname, acc.LbListerenerCertificateInstance) } + +func testAccCheckIBMISLBListenerHttpsRedirectNewConfig(vpcname, subnetname, zone, cidr, lbname, port, protocol 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_lb" "testacc_LB" { + name = "%s" + subnets = ["${ibm_is_subnet.testacc_subnet.id}"] + } + resource "ibm_is_lb_listener" "lb_listener1"{ + lb = ibm_is_lb.testacc_LB.id + port = "9088" + protocol = "https" + certificate_instance="%s" + } + + resource "ibm_is_lb_listener" "lb_listener2"{ + lb = ibm_is_lb.testacc_LB.id + port = "9087" + protocol = "http" + https_redirect { + http_status_code = 302 + listener { + id = ibm_is_lb_listener.lb_listener1.listener_id + } + uri = "/example?doc=get" + } + }`, vpcname, subnetname, zone, cidr, lbname, acc.LbListerenerCertificateInstance) + +} + +func testAccCheckIBMISLBListenerHttpsRedirectNewConfigUpdate(vpcname, subnetname, zone, cidr, lbname, port, protocol 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_lb" "testacc_LB" { + name = "%s" + subnets = ["${ibm_is_subnet.testacc_subnet.id}"] + } + resource "ibm_is_lb_listener" "lb_listener1"{ + lb = ibm_is_lb.testacc_LB.id + port = "9086" + protocol = "https" + certificate_instance="%s" + } + + resource "ibm_is_lb_listener" "lb_listener2"{ + lb = ibm_is_lb.testacc_LB.id + port = "9087" + protocol = "http" + https_redirect { + http_status_code = 303 + listener { + id = ibm_is_lb_listener.lb_listener1.listener_id + } + uri = "/example?doc=getupdated" + } + }`, vpcname, subnetname, zone, cidr, lbname, acc.LbListerenerCertificateInstance) + +} + +func testAccCheckIBMISLBListenerHttpsRedirectNewConfigURIRemove(vpcname, subnetname, zone, cidr, lbname, port, protocol 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_lb" "testacc_LB" { + name = "%s" + subnets = ["${ibm_is_subnet.testacc_subnet.id}"] + } + resource "ibm_is_lb_listener" "lb_listener1"{ + lb = ibm_is_lb.testacc_LB.id + port = "9086" + protocol = "https" + certificate_instance="%s" + } + + resource "ibm_is_lb_listener" "lb_listener2"{ + lb = ibm_is_lb.testacc_LB.id + port = "9087" + protocol = "http" + https_redirect { + http_status_code = 303 + listener { + id = ibm_is_lb_listener.lb_listener1.listener_id + } + } + }`, vpcname, subnetname, zone, cidr, lbname, acc.LbListerenerCertificateInstance) + +} + +func testAccCheckIBMISLBListenerHttpsRedirectNewConfigRemove(vpcname, subnetname, zone, cidr, lbname, port, protocol 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_lb" "testacc_LB" { + name = "%s" + subnets = ["${ibm_is_subnet.testacc_subnet.id}"] + } + resource "ibm_is_lb_listener" "lb_listener1"{ + lb = ibm_is_lb.testacc_LB.id + port = "9086" + protocol = "https" + certificate_instance="%s" + } + + resource "ibm_is_lb_listener" "lb_listener2"{ + lb = ibm_is_lb.testacc_LB.id + port = "9087" + protocol = "http" + }`, vpcname, subnetname, zone, cidr, lbname, acc.LbListerenerCertificateInstance) + +} + func testAccCheckIBMISNLBRouteModeListenerConfig(vpcname, subnetname, zone, cidr, lbname, port, protocol string) string { return fmt.Sprintf(` resource "ibm_is_vpc" "testacc_vpc" { diff --git a/ibm/service/vpc/resource_ibm_is_reservation.go b/ibm/service/vpc/resource_ibm_is_reservation.go new file mode 100644 index 0000000000..0d98ac3520 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_reservation.go @@ -0,0 +1,669 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "fmt" + "log" + + "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" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + isReservation = "reservation" + isReservationName = "name" + isReservationAffinityPolicy = "affinity_policy" + isReservationCapacity = "capacity" + isReservationCapacityTotal = "total" + isReservationCommittedUse = "committed_use" + isReservationComittedUseExpirationPolicy = "expiration_policy" + isReservationComittedUseTerm = "term" + isReservationProfile = "profile" + isReservationProfileName = "name" + isReservationProfileResourceType = "resource_type" + isReservationResourceGroup = "resource_group" + isReservationZone = "zone" + + isReservationCapacityAllocated = "allocated" + isReservationCapacityAvailable = "available" + isReservationCapacityStatus = "status" + isReservationCapacityUsed = "used" + isReservationCommittedUseExpirationAt = "expiration_at" + isReservationCreatedAt = "created_at" + isReservationCrn = "crn" + isReservationHref = "href" + isReservationId = "id" + isReservationLifecycleState = "lifecycle_state" + isReservationProfileHref = "href" + isReservationResourceGroupHref = "href" + isReservationResourceGroupId = "id" + isReservationResourceGroupName = "name" + isReservationResourceType = "resource_type" + isReservationStatusReasons = "status_reasons" + isReservationStatusReasonCode = "code" + isReservationStatusReasonMessage = "message" + isReservationStatusReasonMoreInfo = "more_info" + isReservationZoneHref = "href" + isReservationZoneName = "name" + isReservationStatus = "status" +) + +func ResourceIBMISReservation() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMISReservationCreate, + Read: resourceIBMISReservationRead, + Update: resourceIBMISReservationUpdate, + Delete: resourceIBMISReservationDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + isReservationAffinityPolicy: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_is_reservation", isReservationAffinityPolicy), + Description: "The affinity policy to use for this reservation", + }, + isReservationCapacity: &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Required: true, + Description: "The capacity reservation configuration to use", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isReservationCapacityTotal: &schema.Schema{ + Type: schema.TypeInt, + Required: true, + Description: "The total amount to use for this capacity reservation.", + }, + isReservationCapacityAllocated: &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The amount allocated to this capacity reservation.", + }, + isReservationCapacityAvailable: &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The amount of this capacity reservation available for new attachments.", + }, + isReservationCapacityUsed: &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The amount of this capacity reservation used by existing attachments.", + }, + isReservationCapacityStatus: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The status of the capacity reservation.", + }, + }, + }, + }, + isReservationCommittedUse: &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Required: true, + Description: "The committed use configuration to use for this reservation", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isReservationComittedUseExpirationPolicy: &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The maximum number of days to keep each backup after creation.", + }, + isReservationComittedUseTerm: &schema.Schema{ + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_is_reservation", isReservationComittedUseTerm), + Description: "The maximum number of recent backups to keep. If unspecified, there will be no maximum.", + }, + isReservationCommittedUseExpirationAt: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The expiration date and time for this committed use reservation.", + }, + }, + }, + }, + isReservationCreatedAt: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the reservation was created.", + }, + isReservationCrn: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this reservation.", + }, + isReservationHref: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reservation.", + }, + isReservationId: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this reservation.", + }, + isReservationLifecycleState: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of this reservation.", + }, + isReservationName: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_reservation", isReservationName), + Description: "Reservation name", + }, + isReservationProfile: &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Required: true, + Description: "The profile to use for this reservation.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isReservationProfileName: &schema.Schema{ + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_is_reservation", isReservationProfileName), + Description: "The globally unique name for this virtual server instance profile.", + }, + isReservationProfileResourceType: &schema.Schema{ + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_is_reservation", isReservationProfileResourceType), + Description: "The resource type of the profile.", + }, + isReservationProfileHref: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this virtual server instance profile.", + }, + }, + }, + }, + isReservationResourceGroup: &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "The committed use configuration to use for this reservation", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isReservationResourceGroupHref: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this resource group.", + }, + isReservationResourceGroupId: &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The unique identifier for this resource group", + }, + isReservationResourceGroupName: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this resource group.", + }, + }, + }, + }, + isReservationResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + isReservationStatus: { + Type: schema.TypeString, + Computed: true, + Description: "The status of the reservation.", + }, + isReservationStatusReasons: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The committed use configuration to use for this reservation", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isReservationStatusReasonCode: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: " snake case string succinctly identifying the status reason.", + }, + isReservationStatusReasonMessage: &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "An explanation of the status reason", + }, + isReservationStatusReasonMoreInfo: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Optional: true, + Description: "Link to documentation about this status reason.", + }, + }, + }, + }, + isReservationZone: { + Type: schema.TypeString, + Required: true, + Description: "The globally unique name for this zone.", + }, + }, + } +} + +func ResourceIBMISReservationValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + affinityPolicy := "restricted" + term := "one_year,three_year" + resourceType := "instance_profile" + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isReservationName, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$`, + MinValueLength: 1, + MaxValueLength: 63}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isReservationAffinityPolicy, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Optional: true, + AllowedValues: affinityPolicy}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isReservationComittedUseTerm, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: term}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isReservationProfileResourceType, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: resourceType}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isReservationProfileName, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$`, + MinValueLength: 1, + MaxValueLength: 63}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isReservationZone, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: 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}) + ibmISVPCResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_reservation", Schema: validateSchema} + return &ibmISVPCResourceValidator +} + +func resourceIBMISReservationCreate(d *schema.ResourceData, meta interface{}) error { + + createReservationOptions := &vpcv1.CreateReservationOptions{} + if _, ok := d.GetOk(isReservationCapacity); ok { + resCapacity := d.Get(isReservationCapacity + ".0").(map[string]interface{}) + reservationCapacityPrototype := &vpcv1.ReservationCapacityPrototype{} + + if resCapacity[isReservationCapacityTotal] != nil { + reservationCapacityPrototype.Total = core.Int64Ptr(int64(resCapacity[isReservationCapacityTotal].(int))) + } + createReservationOptions.Capacity = reservationCapacityPrototype + } + + if _, ok := d.GetOk(isReservationCommittedUse); ok { + resCommittedUse := d.Get(isReservationCommittedUse + ".0").(map[string]interface{}) + reservationCommittedUsePrototype := &vpcv1.ReservationCommittedUsePrototype{} + + if resCommittedUse[isReservationComittedUseTerm] != nil && resCommittedUse[isReservationComittedUseTerm].(string) != "" { + reservationCommittedUsePrototype.Term = core.StringPtr(resCommittedUse[isReservationComittedUseTerm].(string)) + } + if resCommittedUse[isReservationComittedUseExpirationPolicy] != nil && resCommittedUse[isReservationComittedUseExpirationPolicy].(string) != "" { + reservationCommittedUsePrototype.ExpirationPolicy = core.StringPtr(resCommittedUse[isReservationComittedUseExpirationPolicy].(string)) + } + createReservationOptions.CommittedUse = reservationCommittedUsePrototype + } + + if _, ok := d.GetOk(isReservationProfile); ok { + resProfile := d.Get(isReservationProfile + ".0").(map[string]interface{}) + reservationProfilePrototype := &vpcv1.ReservationProfilePrototype{} + + if resProfile[isReservationProfileName] != nil && resProfile[isReservationProfileName].(string) != "" { + reservationProfilePrototype.Name = core.StringPtr(resProfile[isReservationProfileName].(string)) + } + if resProfile[isReservationProfileResourceType] != nil && resProfile[isReservationProfileResourceType].(string) != "" { + reservationProfilePrototype.ResourceType = core.StringPtr(resProfile[isReservationProfileResourceType].(string)) + } + createReservationOptions.Profile = reservationProfilePrototype + } + + if _, ok := d.GetOk(isReservationResourceGroup); ok { + resGroup := d.Get(isReservationResourceGroup + ".0").(map[string]interface{}) + if resGroup[isReservationResourceGroupId] != nil && resGroup[isReservationResourceGroupId].(string) != "" { + createReservationOptions.ResourceGroup = &vpcv1.ResourceGroupIdentity{ + ID: core.StringPtr(resGroup[isReservationResourceGroupId].(string)), + } + } + } + + if zone, ok := d.GetOk(isReservationZone); ok { + if zone.(string) != "" { + createReservationOptions.Zone = &vpcv1.ZoneIdentity{Name: core.StringPtr(zone.(string))} + } + } + + if name, ok := d.GetOk(isReservationName); ok { + if name.(string) != "" { + createReservationOptions.Name = core.StringPtr(name.(string)) + } + } + + if affPol, ok := d.GetOk(isReservationAffinityPolicy); ok { + if affPol.(string) != "" { + createReservationOptions.AffinityPolicy = core.StringPtr(affPol.(string)) + } + } + sess, err := vpcClient(meta) + + reservation, response, err := sess.CreateReservation(createReservationOptions) + if err != nil { + log.Printf("[DEBUG] Reservation creation err %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error while creating Reservation %s\n%v", err, response) + } + d.SetId(*reservation.ID) + log.Printf("[INFO] Reservation : %s", *reservation.ID) + + return resourceIBMISReservationRead(d, meta) +} + +func resourceIBMISReservationRead(d *schema.ResourceData, meta interface{}) error { + + id := d.Id() + + sess, err := vpcClient(meta) + if err != nil { + return err + } + getReservationOptions := &vpcv1.GetReservationOptions{ + ID: &id, + } + reservation, response, err := sess.GetReservation(getReservationOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error Getting Reservation (%s): %s\n%s", id, err, response) + } + + if reservation.AffinityPolicy != nil { + if err = d.Set(isReservationAffinityPolicy, reservation.AffinityPolicy); err != nil { + log.Printf("[ERROR] Error setting %s: %s", isReservationAffinityPolicy, err) + return fmt.Errorf("[ERROR] Error setting %s: %s", isReservationAffinityPolicy, err) + } + } + + if reservation.Capacity != nil { + capacityMap := []map[string]interface{}{} + finalList := map[string]interface{}{} + + if reservation.Capacity.Allocated != nil { + finalList[isReservationCapacityAllocated] = flex.IntValue(reservation.Capacity.Allocated) + } + if reservation.Capacity.Available != nil { + finalList[isReservationCapacityAvailable] = flex.IntValue(reservation.Capacity.Available) + } + if reservation.Capacity.Total != nil { + finalList[isReservationCapacityTotal] = flex.IntValue(reservation.Capacity.Total) + } + if reservation.Capacity.Used != nil { + finalList[isReservationCapacityUsed] = flex.IntValue(reservation.Capacity.Used) + } + if reservation.Capacity.Status != nil { + finalList[isReservationCapacityStatus] = reservation.Capacity.Status + } + capacityMap = append(capacityMap, finalList) + d.Set(isReservationCapacity, capacityMap) + } + + if reservation.CommittedUse != nil { + committedUseMap := []map[string]interface{}{} + finalList := map[string]interface{}{} + + if reservation.CommittedUse.ExpirationAt != nil { + finalList[isReservationCommittedUseExpirationAt] = flex.DateTimeToString(reservation.CommittedUse.ExpirationAt) + } + if reservation.CommittedUse.ExpirationPolicy != nil { + finalList[isReservationComittedUseExpirationPolicy] = *reservation.CommittedUse.ExpirationPolicy + } + if reservation.CommittedUse.Term != nil { + finalList[isReservationComittedUseTerm] = *reservation.CommittedUse.Term + } + committedUseMap = append(committedUseMap, finalList) + d.Set(isReservationCommittedUse, committedUseMap) + } + + if reservation.CreatedAt != nil { + if err = d.Set(isReservationCreatedAt, flex.DateTimeToString(reservation.CreatedAt)); err != nil { + log.Printf("[ERROR] Error setting %s: %s", isReservationCreatedAt, err) + return fmt.Errorf("[ERROR] Error setting %s: %s", isReservationCreatedAt, err) + } + } + + if reservation.CRN != nil { + if err = d.Set(isReservationCrn, reservation.CRN); err != nil { + log.Printf("[ERROR] Error setting %s: %s", isReservationCrn, err) + return fmt.Errorf("[ERROR] Error setting %s: %s", isReservationCrn, err) + } + } + + if reservation.Href != nil { + if err = d.Set(isReservationHref, reservation.Href); err != nil { + log.Printf("[ERROR] Error setting %s: %s", isReservationHref, err) + return fmt.Errorf("[ERROR] Error setting %s: %s", isReservationHref, err) + } + } + + if reservation.LifecycleState != nil { + if err = d.Set(isReservationLifecycleState, reservation.LifecycleState); err != nil { + log.Printf("[ERROR] Error setting %s: %s", isReservationLifecycleState, err) + return fmt.Errorf("[ERROR] Error setting %s: %s", isReservationLifecycleState, err) + } + } + + if reservation.Name != nil { + if err = d.Set(isReservationName, reservation.Name); err != nil { + log.Printf("[ERROR] Error setting %s: %s", isReservationName, err) + return fmt.Errorf("[ERROR] Error setting %s: %s", isReservationName, err) + } + } + + if reservation.Profile != nil { + profileMap := []map[string]interface{}{} + finalList := map[string]interface{}{} + + profileItem := reservation.Profile + + if profileItem.Href != nil { + finalList[isReservationProfileHref] = profileItem.Href + } + if profileItem.Name != nil { + finalList[isReservationProfileName] = profileItem.Name + } + if profileItem.ResourceType != nil { + finalList[isReservationProfileResourceType] = profileItem.ResourceType + } + profileMap = append(profileMap, finalList) + d.Set(isReservationProfile, profileMap) + } + + if reservation.ResourceGroup != nil { + rgMap := []map[string]interface{}{} + finalList := map[string]interface{}{} + + if reservation.ResourceGroup.Href != nil { + finalList[isReservationResourceGroupHref] = reservation.ResourceGroup.Href + } + if reservation.ResourceGroup.ID != nil { + finalList[isReservationResourceGroupId] = reservation.ResourceGroup.ID + } + if reservation.ResourceGroup.Name != nil { + finalList[isReservationResourceGroupName] = reservation.ResourceGroup.Name + } + rgMap = append(rgMap, finalList) + d.Set(isReservationResourceGroup, rgMap) + } + + if reservation.ResourceType != nil { + if err = d.Set(isReservationResourceType, reservation.ResourceType); err != nil { + log.Printf("[ERROR] Error setting %s: %s", isReservationResourceType, err) + return fmt.Errorf("[ERROR] Error setting %s: %s", isReservationResourceType, err) + } + } + + if reservation.Status != nil { + if err = d.Set(isReservationStatus, reservation.Status); err != nil { + log.Printf("[ERROR] Error setting %s: %s", isReservationStatus, err) + return fmt.Errorf("[ERROR] Error setting %s: %s", isReservationStatus, err) + } + } + + if reservation.StatusReasons != nil { + srLen := len(reservation.StatusReasons) + srList := []vpcv1.ReservationStatusReason{} + + for i := 0; i < srLen; i++ { + srList = append(srList, reservation.StatusReasons[i]) + } + d.Set(isReservationStatusReasons, srList) + } + + if reservation.Zone != nil && reservation.Zone.Name != nil { + if err = d.Set(isReservationZone, reservation.Zone.Name); err != nil { + log.Printf("[ERROR] Error setting %s: %s", isReservationZone, err) + return fmt.Errorf("[ERROR] Error setting %s: %s", isReservationZone, err) + } + } + return nil +} + +func resourceIBMISReservationUpdate(d *schema.ResourceData, meta interface{}) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + hasChanged := false + name := "" + + reservationPatchModel := &vpcv1.ReservationPatch{} + if d.HasChange(isReservationName) { + name = d.Get(isReservationName).(string) + if name != "" { + reservationPatchModel.Name = &name + hasChanged = true + } + } + if d.HasChange(isReservationCapacity) { + capacityIntf := d.Get(isReservationCapacity) + capacityMap := capacityIntf.([]interface{})[0].(map[string]interface{}) + if d.HasChange(isReservationCapacity + ".0." + isReservationCapacityTotal) { + if totalIntf, ok := capacityMap[isReservationCapacityTotal]; ok { + reservationPatchModel.Capacity = &vpcv1.ReservationCapacityPatch{ + Total: core.Int64Ptr(int64(totalIntf.(int))), + } + } + } + } + if d.HasChange(isReservationCommittedUse) { + committedUseIntf := d.Get(isReservationCommittedUse) + committedUseMap := committedUseIntf.([]interface{})[0].(map[string]interface{}) + cuPatch := &vpcv1.ReservationCommittedUsePatch{} + if d.HasChange(isReservationCommittedUse + ".0." + isReservationComittedUseExpirationPolicy) { + if expPolIntf, ok := committedUseMap[isReservationComittedUseExpirationPolicy]; ok { + if expPolIntf.(string) != "" { + cuPatch.ExpirationPolicy = core.StringPtr(string(expPolIntf.(string))) + } + } + } + if d.HasChange(isReservationCommittedUse + ".0." + isReservationComittedUseTerm) { + if termIntf, ok := committedUseMap[isReservationComittedUseTerm]; ok { + cuPatch.Term = core.StringPtr(string(termIntf.(string))) + } + } + reservationPatchModel.CommittedUse = cuPatch + } + if d.HasChange(isReservationProfile) { + profileIntf := d.Get(isReservationProfile) + profileMap := profileIntf.([]interface{})[0].(map[string]interface{}) + profPatch := &vpcv1.ReservationProfilePatch{} + if d.HasChange(isReservationProfile + ".0." + isReservationProfileName) { + if profNameIntf, ok := profileMap[isReservationProfileName]; ok { + if profNameIntf.(string) != "" { + profPatch.Name = core.StringPtr(string(profNameIntf.(string))) + } + } + } + if d.HasChange(isReservationProfile + ".0." + isReservationProfileResourceType) { + if resTypeIntf, ok := profileMap[isReservationProfileResourceType]; ok { + if resTypeIntf.(string) != "" { + profPatch.ResourceType = core.StringPtr(string(resTypeIntf.(string))) + } + } + } + reservationPatchModel.Profile = profPatch + } + if hasChanged { + reservationPatch, err := reservationPatchModel.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error calling asPatch for ReservationPatch: %s", err) + } + updateReservationOptions := &vpcv1.UpdateReservationOptions{} + updateReservationOptions.ReservationPatch = reservationPatch + updateReservationOptions.ID = core.StringPtr(d.Id()) + _, response, err := sess.UpdateReservation(updateReservationOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Updating Reservation : %s\n%s", err, response) + } + } + return resourceIBMISReservationRead(d, meta) +} + +func resourceIBMISReservationDelete(d *schema.ResourceData, meta interface{}) error { + id := d.Id() + sess, err := vpcClient(meta) + if err != nil { + return err + } + + deleteReservationOptions := &vpcv1.DeleteReservationOptions{ + ID: &id, + } + _, _, err = sess.DeleteReservation(deleteReservationOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Deleting Reservation : %s", err) + } + d.SetId("") + return nil +} diff --git a/ibm/service/vpc/resource_ibm_is_reservation_activate.go b/ibm/service/vpc/resource_ibm_is_reservation_activate.go new file mode 100644 index 0000000000..96ac3c4753 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_reservation_activate.go @@ -0,0 +1,421 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "fmt" + "log" + "runtime/debug" + + "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/helper/schema" +) + +func ResourceIBMISReservationActivate() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMISReservationActivateCreate, + Read: resourceIBMISReservationActivateRead, + Delete: resourceIBMISReservationActivateDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + isReservation: &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The unique identifier for this reservation.", + }, + isReservationAffinityPolicy: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The affinity policy to use for this reservation", + }, + isReservationCapacity: &schema.Schema{ + Type: schema.TypeList, + ForceNew: true, + Computed: true, + Description: "The capacity reservation configuration to use", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isReservationCapacityTotal: &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The total amount to use for this capacity reservation.", + }, + isReservationCapacityAllocated: &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The amount allocated to this capacity reservation.", + }, + isReservationCapacityAvailable: &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The amount of this capacity reservation available for new attachments.", + }, + isReservationCapacityUsed: &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The amount of this capacity reservation used by existing attachments.", + }, + isReservationCapacityStatus: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The status of the capacity reservation.", + }, + }, + }, + }, + isReservationCommittedUse: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The committed use configuration to use for this reservation", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isReservationComittedUseExpirationPolicy: &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The maximum number of days to keep each backup after creation.", + }, + isReservationComittedUseTerm: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The maximum number of recent backups to keep. If unspecified, there will be no maximum.", + }, + isReservationCommittedUseExpirationAt: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The expiration date and time for this committed use reservation.", + }, + }, + }, + }, + isReservationCreatedAt: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the reservation was created.", + }, + isReservationCrn: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this reservation.", + }, + isReservationHref: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reservation.", + }, + isReservationId: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this reservation.", + }, + isReservationLifecycleState: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of this reservation.", + }, + isReservationName: { + Type: schema.TypeString, + Computed: true, + Description: "Reservation name", + }, + isReservationProfile: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The profile used for this reservation.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isReservationProfileName: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for this virtual server instance profile.", + }, + isReservationProfileResourceType: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type of the profile.", + }, + isReservationProfileHref: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this virtual server instance profile.", + }, + }, + }, + }, + isReservationResourceGroup: &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Computed: true, + Description: "The committed use configuration to use for this reservation", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isReservationResourceGroupHref: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this resource group.", + }, + isReservationResourceGroupId: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this resource group", + }, + isReservationResourceGroupName: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this resource group.", + }, + }, + }, + }, + isReservationResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + isReservationStatus: { + Type: schema.TypeString, + Computed: true, + Description: "The status of the reservation.", + }, + isReservationStatusReasons: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The committed use configuration to use for this reservation", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isReservationStatusReasonCode: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: " snake case string succinctly identifying the status reason.", + }, + isReservationStatusReasonMessage: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the status reason", + }, + isReservationStatusReasonMoreInfo: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Optional: true, + Description: "Link to documentation about this status reason.", + }, + }, + }, + }, + isReservationZone: { + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for this zone.", + }, + }, + } +} +func resourceIBMISReservationActivateCreate(d *schema.ResourceData, meta interface{}) error { + + id := d.Get(isReservation).(string) + activateReservationOptions := &vpcv1.ActivateReservationOptions{ + ID: core.StringPtr(id), + } + + sess, err := vpcClient(meta) + if err != nil { + return err + } + + response, err := sess.ActivateReservation(activateReservationOptions) + if err != nil { + log.Printf("[DEBUG] Reservation activation err %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error while activating Reservation %s\n%v", err, response) + } + log.Printf("[INFO] Reservation activated: %s", id) + d.SetId(id) + + return resourceIBMISReservationActivateRead(d, meta) +} + +func resourceIBMISReservationActivateRead(d *schema.ResourceData, meta interface{}) error { + + id := d.Id() + + sess, err := vpcClient(meta) + defer func() { + + log.Println("stacktrace from panic: \n", err, string(debug.Stack())) + + }() + if err != nil { + return err + } + getReservationOptions := &vpcv1.GetReservationOptions{ + ID: &id, + } + reservation, response, err := sess.GetReservation(getReservationOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error Getting Reservation (%s): %s\n%s", id, err, response) + } + + if reservation.AffinityPolicy != nil { + if err = d.Set(isReservationAffinityPolicy, reservation.AffinityPolicy); err != nil { + log.Printf("[ERROR] Error setting %s: %s", isReservationAffinityPolicy, err) + return fmt.Errorf("[ERROR] Error setting %s: %s", isReservationAffinityPolicy, err) + } + } + + if reservation.Capacity != nil { + capacityMap := []map[string]interface{}{} + finalList := map[string]interface{}{} + + if reservation.Capacity.Allocated != nil { + finalList[isReservationCapacityAllocated] = flex.IntValue(reservation.Capacity.Allocated) + } + if reservation.Capacity.Available != nil { + finalList[isReservationCapacityAvailable] = flex.IntValue(reservation.Capacity.Available) + } + if reservation.Capacity.Total != nil { + finalList[isReservationCapacityTotal] = flex.IntValue(reservation.Capacity.Total) + } + if reservation.Capacity.Used != nil { + finalList[isReservationCapacityUsed] = flex.IntValue(reservation.Capacity.Used) + } + if reservation.Capacity.Status != nil { + finalList[isReservationCapacityStatus] = reservation.Capacity.Status + } + capacityMap = append(capacityMap, finalList) + d.Set(isReservationCapacity, capacityMap) + } + + if reservation.CommittedUse != nil { + committedUseMap := []map[string]interface{}{} + finalList := map[string]interface{}{} + + if reservation.CommittedUse.ExpirationAt != nil { + finalList[isReservationCommittedUseExpirationAt] = flex.DateTimeToString(reservation.CommittedUse.ExpirationAt) + } + if reservation.CommittedUse.ExpirationPolicy != nil { + finalList[isReservationComittedUseExpirationPolicy] = *reservation.CommittedUse.ExpirationPolicy + } + if reservation.CommittedUse.Term != nil { + finalList[isReservationComittedUseTerm] = *reservation.CommittedUse.Term + } + committedUseMap = append(committedUseMap, finalList) + d.Set(isReservationCommittedUse, committedUseMap) + } + + if reservation.CreatedAt != nil { + if err = d.Set(isReservationCreatedAt, flex.DateTimeToString(reservation.CreatedAt)); err != nil { + log.Printf("[ERROR] Error setting %s: %s", isReservationCreatedAt, err) + return fmt.Errorf("[ERROR] Error setting %s: %s", isReservationCreatedAt, err) + } + } + + if reservation.CRN != nil { + if err = d.Set(isReservationCrn, reservation.CRN); err != nil { + log.Printf("[ERROR] Error setting %s: %s", isReservationCrn, err) + return fmt.Errorf("[ERROR] Error setting %s: %s", isReservationCrn, err) + } + } + + if reservation.Href != nil { + if err = d.Set(isReservationHref, reservation.Href); err != nil { + log.Printf("[ERROR] Error setting %s: %s", isReservationHref, err) + return fmt.Errorf("[ERROR] Error setting %s: %s", isReservationHref, err) + } + } + + if reservation.LifecycleState != nil { + if err = d.Set(isReservationLifecycleState, reservation.LifecycleState); err != nil { + log.Printf("[ERROR] Error setting %s: %s", isReservationLifecycleState, err) + return fmt.Errorf("[ERROR] Error setting %s: %s", isReservationLifecycleState, err) + } + } + + if reservation.Name != nil { + if err = d.Set(isReservationName, reservation.Name); err != nil { + log.Printf("[ERROR] Error setting %s: %s", isReservationName, err) + return fmt.Errorf("[ERROR] Error setting %s: %s", isReservationName, err) + } + } + + if reservation.Profile != nil { + profileMap := []map[string]interface{}{} + finalList := map[string]interface{}{} + + profileItem := reservation.Profile + + if profileItem.Href != nil { + finalList[isReservationProfileHref] = profileItem.Href + } + if profileItem.Name != nil { + finalList[isReservationProfileName] = profileItem.Name + } + if profileItem.ResourceType != nil { + finalList[isReservationProfileResourceType] = profileItem.ResourceType + } + profileMap = append(profileMap, finalList) + d.Set(isReservationProfile, profileMap) + } + + if reservation.ResourceGroup != nil { + rgMap := []map[string]interface{}{} + finalList := map[string]interface{}{} + + if reservation.ResourceGroup.Href != nil { + finalList[isReservationResourceGroupHref] = reservation.ResourceGroup.Href + } + if reservation.ResourceGroup.ID != nil { + finalList[isReservationResourceGroupId] = reservation.ResourceGroup.ID + } + if reservation.ResourceGroup.Name != nil { + finalList[isReservationResourceGroupName] = reservation.ResourceGroup.Name + } + rgMap = append(rgMap, finalList) + d.Set(isReservationResourceGroup, rgMap) + } + + if reservation.ResourceType != nil { + if err = d.Set(isReservationResourceType, reservation.ResourceType); err != nil { + log.Printf("[ERROR] Error setting %s: %s", isReservationResourceType, err) + return fmt.Errorf("[ERROR] Error setting %s: %s", isReservationResourceType, err) + } + } + + if reservation.Status != nil { + if err = d.Set(isReservationStatus, reservation.Status); err != nil { + log.Printf("[ERROR] Error setting %s: %s", isReservationStatus, err) + return fmt.Errorf("[ERROR] Error setting %s: %s", isReservationStatus, err) + } + } + + if reservation.StatusReasons != nil { + srLen := len(reservation.StatusReasons) + srList := []vpcv1.ReservationStatusReason{} + + for i := 0; i < srLen; i++ { + srList = append(srList, reservation.StatusReasons[i]) + } + d.Set(isReservationStatusReasons, srList) + } + + if reservation.Zone != nil && reservation.Zone.Name != nil { + if err = d.Set(isReservationZone, reservation.Zone.Name); err != nil { + log.Printf("[ERROR] Error setting %s: %s", isReservationZone, err) + return fmt.Errorf("[ERROR] Error setting %s: %s", isReservationZone, err) + } + } + return nil +} + +func resourceIBMISReservationActivateDelete(d *schema.ResourceData, meta interface{}) error { + d.SetId("") + return nil +} diff --git a/ibm/service/vpc/resource_ibm_is_reservation_activate_test.go b/ibm/service/vpc/resource_ibm_is_reservation_activate_test.go new file mode 100644 index 0000000000..eef1f6127c --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_reservation_activate_test.go @@ -0,0 +1,110 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "errors" + "fmt" + "testing" + + 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" + "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 TestAccIBMISReservationActivate_basic(t *testing.T) { + var reservation string + name := fmt.Sprintf("tfresa-name-%d", acctest.RandIntRange(10, 100)) + zone := "us-east-3" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheckImage(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: checkReservationActivateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISReservationActivateConfig(name, zone), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISReservationActivateExists("ibm_is_reservation.isExampleReservation", reservation), + resource.TestCheckResourceAttr( + "ibm_is_reservation.isExampleReservation", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_reservation.isExampleReservation", "status", "active"), + ), + }, + }, + }) +} + +func checkReservationActivateDestroy(s *terraform.State) error { + + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_reservation" { + continue + } + + getresoptions := &vpcv1.GetReservationOptions{ + ID: &rs.Primary.ID, + } + _, _, err := sess.GetReservation(getresoptions) + if err == nil { + fmt.Printf("Reservation %s still exists: %s", rs.Primary.ID, err.Error()) + } + } + + return nil +} + +func testAccCheckIBMISReservationActivateExists(n, image string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + getimgoptions := &vpcv1.GetReservationOptions{ + ID: &rs.Primary.ID, + } + foundReservation, _, err := sess.GetReservation(getimgoptions) + if err != nil { + return err + } + image = *foundReservation.ID + + return nil + } +} + +func testAccCheckIBMISReservationActivateConfig(name, zone string) string { + return fmt.Sprintf(` + resource "ibm_is_reservation" "isExampleReservation" { + capacity { + total = 10 + } + committed_use { + term = "one_year" + } + profile { + name = "ba2-2x8" + resource_type = "instance_profile" + } + name = "%s" + zone = "%s" + } + resource ibm_is_reservation_activate activate { + reservation = ibm_is_reservation.isExampleReservation.id + } + `, name, zone) +} diff --git a/ibm/service/vpc/resource_ibm_is_reservation_test.go b/ibm/service/vpc/resource_ibm_is_reservation_test.go new file mode 100644 index 0000000000..28a53efddb --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_reservation_test.go @@ -0,0 +1,111 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "errors" + "fmt" + "testing" + + 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" + "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 TestAccIBMISReservation_basic(t *testing.T) { + var reservation string + name := fmt.Sprintf("tfres-name-%d", acctest.RandIntRange(10, 100)) + zone := "us-south-1" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: checkReservationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISReservationConfig(name, zone), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISReservationExists("ibm_is_reservation.isExampleReservation", reservation), + resource.TestCheckResourceAttr("ibm_is_reservation.isExampleReservation", "name", name), + resource.TestCheckResourceAttr("ibm_is_reservation.isExampleReservation", "zone", zone), + resource.TestCheckResourceAttrSet("ibm_is_reservation.isExampleReservation", "affinity_policy"), + resource.TestCheckResourceAttrSet("ibm_is_reservation.isExampleReservation", "created_at"), + resource.TestCheckResourceAttrSet("ibm_is_reservation.isExampleReservation", "crn"), + resource.TestCheckResourceAttrSet("ibm_is_reservation.isExampleReservation", "id"), + resource.TestCheckResourceAttrSet("ibm_is_reservation.isExampleReservation", "lifecycle_state"), + resource.TestCheckResourceAttrSet("ibm_is_reservation.isExampleReservation", "resource_type"), + resource.TestCheckResourceAttrSet("ibm_is_reservation.isExampleReservation", "status"), + ), + }, + }, + }) +} + +func checkReservationDestroy(s *terraform.State) error { + + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_reservation" { + continue + } + + getresoptions := &vpcv1.GetReservationOptions{ + ID: &rs.Primary.ID, + } + _, _, err := sess.GetReservation(getresoptions) + if err == nil { + fmt.Printf("Reservation %s still exists: %s", rs.Primary.ID, err.Error()) + } + } + + return nil +} + +func testAccCheckIBMISReservationExists(n, image string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + getimgoptions := &vpcv1.GetReservationOptions{ + ID: &rs.Primary.ID, + } + foundReservation, _, err := sess.GetReservation(getimgoptions) + if err != nil { + return err + } + image = *foundReservation.ID + + return nil + } +} + +func testAccCheckIBMISReservationConfig(name, zone string) string { + return fmt.Sprintf(` + resource "ibm_is_reservation" "isExampleReservation" { + capacity { + total = 10 + } + committed_use { + term = "one_year" + } + profile { + name = "cx2-2x4" + resource_type = "instance_profile" + } + name = "%s" + zone = "%s" + }`, name, zone) +} diff --git a/ibm/service/vpc/resource_ibm_is_share.go b/ibm/service/vpc/resource_ibm_is_share.go index 39fcaa0d72..fb41ab16f5 100644 --- a/ibm/service/vpc/resource_ibm_is_share.go +++ b/ibm/service/vpc/resource_ibm_is_share.go @@ -155,6 +155,7 @@ func ResourceIbmIsShare() *schema.Resource { }, "id": { Type: schema.TypeString, + Optional: true, Computed: true, Description: "ID of this VNI", }, @@ -164,6 +165,22 @@ func ResourceIbmIsShare() *schema.Resource { Computed: true, Description: "Name of this VNI", }, + "allow_ip_spoofing": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether source IP spoofing is allowed on this interface. If `false`, source IP spoofing is prevented on this interface. If `true`, source IP spoofing is allowed on this interface.", + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Indicates whether this virtual network interface will be automatically deleted when`target` is deleted.", + }, + "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 network interface, allowing the workload to perform any needed NAT operations.- `allow_ip_spoofing` must be `false`.- If the virtual network interface is attached: - The target `resource_type` must be `bare_metal_server_network_attachment`. - The target `interface_type` must not be `hipersocket`.", + }, "primary_ip": { Type: schema.TypeList, Optional: true, @@ -230,6 +247,7 @@ func ResourceIbmIsShare() *schema.Resource { "subnet": { Type: schema.TypeString, Optional: true, + Computed: true, Description: "The associated subnet. Required if primary_ip is not specified.", }, }, @@ -388,6 +406,7 @@ func ResourceIbmIsShare() *schema.Resource { }, "id": { Type: schema.TypeString, + Optional: true, Computed: true, Description: "ID of this VNI", }, @@ -397,6 +416,22 @@ func ResourceIbmIsShare() *schema.Resource { Computed: true, Description: "Name of this VNI", }, + "allow_ip_spoofing": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether source IP spoofing is allowed on this interface. If `false`, source IP spoofing is prevented on this interface. If `true`, source IP spoofing is allowed on this interface.", + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Indicates whether this virtual network interface will be automatically deleted when`target` is deleted.", + }, + "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 network interface, allowing the workload to perform any needed NAT operations.- `allow_ip_spoofing` must be `false`.- If the virtual network interface is attached: - The target `resource_type` must be `bare_metal_server_network_attachment`. - The target `interface_type` must not be `hipersocket`.", + }, "primary_ip": { Type: schema.TypeList, Optional: true, @@ -463,6 +498,7 @@ func ResourceIbmIsShare() *schema.Resource { "subnet": { Type: schema.TypeString, Optional: true, + Computed: true, Description: "The associated subnet. Required if primary_ip is not specified.", }, }, @@ -819,9 +855,10 @@ func resourceIbmIsShareCreate(context context.Context, d *schema.ResourceData, m if ok { var targets []vpcv1.ShareMountTargetPrototypeIntf targetsIntf := replicaTargets.([]interface{}) - for _, targetIntf := range targetsIntf { + for tergetIdx, targetIntf := range targetsIntf { target := targetIntf.(map[string]interface{}) - targetsItem, err := resourceIbmIsShareMapToShareMountTargetPrototype(d, target) + autoDeleteSchema := fmt.Sprintf("replica_share.0.mount_targets.%d.virtual_network_interface.0.auto_delete", tergetIdx) + targetsItem, err := resourceIbmIsShareMapToShareMountTargetPrototype(d, target, autoDeleteSchema) if err != nil { return diag.FromErr(err) } @@ -887,9 +924,10 @@ func resourceIbmIsShareCreate(context context.Context, d *schema.ResourceData, m if shareTargetPrototypeIntf, ok := d.GetOk("mount_targets"); ok { var targets []vpcv1.ShareMountTargetPrototypeIntf - for _, e := range shareTargetPrototypeIntf.([]interface{}) { + for targetIdx, e := range shareTargetPrototypeIntf.([]interface{}) { value := e.(map[string]interface{}) - targetsItem, err := resourceIbmIsShareMapToShareMountTargetPrototype(d, value) + autoDeleteSchema := fmt.Sprintf("mount_targets.%d.virtual_network_interface.0.auto_delete", targetIdx) + targetsItem, err := resourceIbmIsShareMapToShareMountTargetPrototype(d, value, autoDeleteSchema) if err != nil { return diag.FromErr(err) } @@ -962,7 +1000,7 @@ func resourceIbmIsShareCreate(context context.Context, d *schema.ResourceData, m return resourceIbmIsShareRead(context, d, meta) } -func resourceIbmIsShareMapToShareMountTargetPrototype(d *schema.ResourceData, shareTargetPrototypeMap map[string]interface{}) (vpcv1.ShareMountTargetPrototype, error) { +func resourceIbmIsShareMapToShareMountTargetPrototype(d *schema.ResourceData, shareTargetPrototypeMap map[string]interface{}, autoDeleteSchema string) (vpcv1.ShareMountTargetPrototype, error) { shareTargetPrototype := vpcv1.ShareMountTargetPrototype{} if nameIntf, ok := shareTargetPrototypeMap["name"]; ok && nameIntf != "" { @@ -977,11 +1015,20 @@ func resourceIbmIsShareMapToShareMountTargetPrototype(d *schema.ResourceData, sh } else if vniIntf, ok := shareTargetPrototypeMap["virtual_network_interface"]; ok { vniPrototype := vpcv1.ShareMountTargetVirtualNetworkInterfacePrototype{} vniMap := vniIntf.([]interface{})[0].(map[string]interface{}) - vniPrototype, err := ShareMountTargetMapToShareMountTargetPrototype(d, vniMap) - if err != nil { - return shareTargetPrototype, err + + VNIIdIntf, ok := vniMap["id"] + VNIId := VNIIdIntf.(string) + if ok && VNIId != "" { + vniPrototype.ID = &VNIId + shareTargetPrototype.VirtualNetworkInterface = &vniPrototype + } else { + vniPrototype, err := ShareMountTargetMapToShareMountTargetPrototype(d, vniMap, autoDeleteSchema) + if err != nil { + return shareTargetPrototype, err + } + shareTargetPrototype.VirtualNetworkInterface = &vniPrototype } - shareTargetPrototype.VirtualNetworkInterface = &vniPrototype + } if transitEncryptionIntf, ok := shareTargetPrototypeMap["transit_encryption"]; ok && transitEncryptionIntf != "" { transitEncryption := transitEncryptionIntf.(string) @@ -1663,6 +1710,7 @@ func shareUpdate(vpcClient *vpcv1.VpcV1, context context.Context, d *schema.Reso for targetIdx := range target_prototype { targetName := fmt.Sprintf("%s.%d.name", shareMountTargetSchema, targetIdx) vniName := fmt.Sprintf("%s.%d.virtual_network_interface.0.name", shareMountTargetSchema, targetIdx) + vniAutoDelete := fmt.Sprintf("%s.%d.virtual_network_interface.0.auto_delete", shareMountTargetSchema, targetIdx) vniId := fmt.Sprintf("%s.%d.virtual_network_interface.0.id", shareMountTargetSchema, targetIdx) targetId := fmt.Sprintf("%s.%d.id", shareMountTargetSchema, targetIdx) securityGroups := fmt.Sprintf("%s.%d.virtual_network_interface.0.security_groups", shareMountTargetSchema, targetIdx) @@ -1699,10 +1747,15 @@ func shareUpdate(vpcClient *vpcv1.VpcV1, context context.Context, d *schema.Reso } } - if d.HasChange(vniName) { - vniNameStr := d.Get(vniName).(string) - vniPatchModel := &vpcv1.VirtualNetworkInterfacePatch{ - Name: &vniNameStr, + if d.HasChange(vniName) || d.HasChange(vniAutoDelete) { + vniPatchModel := &vpcv1.VirtualNetworkInterfacePatch{} + if d.HasChange(vniName) { + vniNameStr := d.Get(vniName).(string) + vniPatchModel.Name = &vniNameStr + } + if d.HasChange(vniAutoDelete) { + autoDelete := d.Get(vniAutoDelete).(bool) + vniPatchModel.AutoDelete = &autoDelete } vniPatch, err := vniPatchModel.AsPatch() if err != nil { diff --git a/ibm/service/vpc/resource_ibm_is_share_mount_target.go b/ibm/service/vpc/resource_ibm_is_share_mount_target.go index c723dd3338..536e378303 100644 --- a/ibm/service/vpc/resource_ibm_is_share_mount_target.go +++ b/ibm/service/vpc/resource_ibm_is_share_mount_target.go @@ -16,6 +16,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/IBM/go-sdk-core/v5/core" "github.com/IBM/vpc-go-sdk/vpcv1" ) @@ -69,9 +70,11 @@ func ResourceIBMIsShareMountTarget() *schema.Resource { Description: "href of virtual network interface", }, "id": { - Type: schema.TypeString, - Computed: true, - Description: "ID of this VNI", + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"virtual_network_interface.0.primary_ip", "virtual_network_interface.0.subnet"}, + Computed: true, + Description: "ID of this VNI", }, "crn": { Type: schema.TypeString, @@ -80,9 +83,26 @@ func ResourceIBMIsShareMountTarget() *schema.Resource { }, "name": { Type: schema.TypeString, - Required: true, + Optional: true, + Computed: true, Description: "Name of this VNI", }, + "allow_ip_spoofing": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether source IP spoofing is allowed on this interface. If `false`, source IP spoofing is prevented on this interface. If `true`, source IP spoofing is allowed on this interface.", + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Indicates whether this virtual network interface will be automatically deleted when`target` is deleted.", + }, + "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 network interface, allowing the workload to perform any needed NAT operations.- `allow_ip_spoofing` must be `false`.- If the virtual network interface is attached: - The target `resource_type` must be `bare_metal_server_network_attachment`. - The target `interface_type` must not be `hipersocket`.", + }, "primary_ip": { Type: schema.TypeList, MinItems: 0, @@ -161,12 +181,14 @@ func ResourceIBMIsShareMountTarget() *schema.Resource { "subnet": { Type: schema.TypeString, Optional: true, + Computed: true, //ConflictsWith: []string{"virtual_network_interface.0.primary_ip"}, Description: "The associated subnet. Required if primary_ip is not specified.", }, }, }, }, + "vpc": { Type: schema.TypeString, Optional: true, @@ -294,9 +316,16 @@ func resourceIBMIsShareMountTargetCreate(context context.Context, d *schema.Reso } else if vniIntf, ok := d.GetOk("virtual_network_interface"); ok { vniPrototype := vpcv1.ShareMountTargetVirtualNetworkInterfacePrototype{} vniMap := vniIntf.([]interface{})[0].(map[string]interface{}) - vniPrototype, err = ShareMountTargetMapToShareMountTargetPrototype(d, vniMap) - if err != nil { - return diag.FromErr(err) + + VNIIdIntf, ok := vniMap["id"] + VNIId := VNIIdIntf.(string) + if ok && VNIId != "" { + vniPrototype.ID = &VNIId + } else { + vniPrototype, err = ShareMountTargetMapToShareMountTargetPrototype(d, vniMap, "virtual_network_interface.0.auto_delete") + if err != nil { + return diag.FromErr(err) + } } shareMountTargetPrototype.VirtualNetworkInterface = &vniPrototype } @@ -428,10 +457,15 @@ func resourceIBMIsShareMountTargetUpdate(context context.Context, d *schema.Reso hasChange = true } - if d.HasChange("virtual_network_interface.0.name") { - vniName := d.Get("virtual_network_interface.0.name").(string) - vniPatchModel := &vpcv1.VirtualNetworkInterfacePatch{ - Name: &vniName, + if d.HasChange("virtual_network_interface.0.name") || d.HasChange("virtual_network_interface.0.auto_delete") { + vniPatchModel := &vpcv1.VirtualNetworkInterfacePatch{} + if d.HasChange("virtual_network_interface.0.name") { + vniName := d.Get("virtual_network_interface.0.name").(string) + vniPatchModel.Name = &vniName + } + if d.HasChange("virtual_network_interface.0.auto_delete") { + autoDelete := d.Get("virtual_network_interface.0.auto_delete").(bool) + vniPatchModel.AutoDelete = &autoDelete } vniPatch, err := vniPatchModel.AsPatch() if err != nil { @@ -669,6 +703,39 @@ func isWaitForMountTargetDelete(context context.Context, vpcClient *vpcv1.VpcV1, return stateConf.WaitForState() } +func ShareMountTargetVNIReservedIPInterfaceToMap(context context.Context, vpcClient *vpcv1.VpcV1, d *schema.ResourceData, ripRef *vpcv1.ReservedIPReference, subnetId string) (map[string]interface{}, error) { + + currentPrimIp := map[string]interface{}{} + if ripRef.Address != nil { + currentPrimIp["address"] = ripRef.Address + } + if ripRef.Name != nil { + currentPrimIp["name"] = *ripRef.Name + } + if ripRef.ID != nil { + currentPrimIp["reserved_ip"] = *ripRef.ID + } + if ripRef.Href != nil { + currentPrimIp["href"] = *ripRef.Href + } + + if ripRef.ResourceType != nil { + currentPrimIp["resource_type"] = *ripRef.ResourceType + } + + rIpOptions := &vpcv1.GetSubnetReservedIPOptions{ + SubnetID: &subnetId, + ID: ripRef.ID, + } + rIp, response, err := vpcClient.GetSubnetReservedIP(rIpOptions) + if err != nil { + return nil, fmt.Errorf("[ERROR] Error getting network interface reserved ip(%s) from the subnet(%s): %s\n%s", *ripRef.ID, *&subnetId, err, response) + } + currentPrimIp["auto_delete"] = rIp.AutoDelete + + return currentPrimIp, nil +} + func ShareMountTargetVirtualNetworkInterfaceToMap(context context.Context, vpcClient *vpcv1.VpcV1, d *schema.ResourceData, vniId string) ([]map[string]interface{}, error) { vniSlice := make([]map[string]interface{}, 0) @@ -690,39 +757,27 @@ func ShareMountTargetVirtualNetworkInterfaceToMap(context context.Context, vpcCl vniMap["name"] = vni.Name vniMap["href"] = vni.Href - primaryIpList := make([]map[string]interface{}, 0) - currentPrimIp := map[string]interface{}{} - if vni.PrimaryIP != nil { - if vni.PrimaryIP.Address != nil { - currentPrimIp["address"] = vni.PrimaryIP.Address - } - if vni.PrimaryIP.Name != nil { - currentPrimIp["name"] = *vni.PrimaryIP.Name - } - if vni.PrimaryIP.ID != nil { - currentPrimIp["reserved_ip"] = *vni.PrimaryIP.ID - } - if vni.PrimaryIP.Href != nil { - currentPrimIp["href"] = *vni.PrimaryIP.Href - } + if vni.AllowIPSpoofing != nil { + vniMap["allow_ip_spoofing"] = *vni.AllowIPSpoofing + } + if vni.AutoDelete != nil { + vniMap["auto_delete"] = *vni.AutoDelete + } + if vni.EnableInfrastructureNat != nil { + vniMap["enable_infrastructure_nat"] = *vni.EnableInfrastructureNat + } - if vni.PrimaryIP.ResourceType != nil { - currentPrimIp["resource_type"] = *vni.PrimaryIP.ResourceType - } + if vni.PrimaryIP != nil { + primaryIpList := make([]map[string]interface{}, 0) - rIpOptions := &vpcv1.GetSubnetReservedIPOptions{ - SubnetID: vni.Subnet.ID, - ID: vni.PrimaryIP.ID, - } - rIp, response, err := vpcClient.GetSubnetReservedIP(rIpOptions) + currentPrimIp, err := ShareMountTargetVNIReservedIPInterfaceToMap(context, vpcClient, d, vni.PrimaryIP, *vni.Subnet.ID) if err != nil { - return nil, fmt.Errorf("[ERROR] Error getting network interface reserved ip(%s) attached to the virtual instance network interface(%s): %s\n%s", *vni.PrimaryIP.ID, *vni.ID, err, response) + return nil, err } - currentPrimIp["auto_delete"] = rIp.AutoDelete - primaryIpList = append(primaryIpList, currentPrimIp) vniMap["primary_ip"] = primaryIpList } + vniMap["subnet"] = vni.Subnet.ID vniMap["resource_type"] = vni.ResourceType vniMap["resource_group"] = vni.ResourceGroup.ID @@ -737,7 +792,7 @@ func ShareMountTargetVirtualNetworkInterfaceToMap(context context.Context, vpcCl return vniSlice, nil } -func ShareMountTargetMapToShareMountTargetPrototype(d *schema.ResourceData, vniMap map[string]interface{}) (vpcv1.ShareMountTargetVirtualNetworkInterfacePrototype, error) { +func ShareMountTargetMapToShareMountTargetPrototype(d *schema.ResourceData, vniMap map[string]interface{}, autoDeleteSchema string) (vpcv1.ShareMountTargetVirtualNetworkInterfacePrototype, error) { vniPrototype := vpcv1.ShareMountTargetVirtualNetworkInterfacePrototype{} name, _ := vniMap["name"].(string) if name != "" { @@ -771,6 +826,12 @@ func ShareMountTargetMapToShareMountTargetPrototype(d *schema.ResourceData, vniM } vniPrototype.PrimaryIP = primaryIpPrototype } + + if autoDeleteIntf, ok := d.GetOkExists(autoDeleteSchema); ok { + autoDeleteBool := autoDeleteIntf.(bool) + vniPrototype.AutoDelete = &autoDeleteBool + } + if subnet := vniMap["subnet"].(string); subnet != "" { vniPrototype.Subnet = &vpcv1.SubnetIdentity{ ID: &subnet, @@ -895,3 +956,38 @@ func mountTargetRefreshFunc(context context.Context, vpcClient *vpcv1.VpcV1, sha return target, "pending", nil } } +func virtualNetworkInterfaceIPsReservedIPPrototypeMapToModel(modelMap map[string]interface{}) (vpcv1.VirtualNetworkInterfaceIPPrototypeIntf, error) { + model := &vpcv1.VirtualNetworkInterfaceIPPrototype{} + + reservedIp := modelMap["reserved_ip"].(string) + reservedIpAddress := modelMap["address"].(string) + reservedIpName := modelMap["name"].(string) + reservedIpAutoDelete, autoDeleteOk := modelMap["auto_delete"] + if reservedIp != "" && (reservedIpAddress != "" || reservedIpName != "" || autoDeleteOk) { + return model, fmt.Errorf("[ERROR] Error creating mount target, virtual_network_interface, reserved_ip(%s) is mutually exclusive with other primary_ip attributes", reservedIp) + } + if reservedIp != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } else { + if reservedIpAddress != "" { + model.Address = &reservedIpAddress + } + if reservedIpName != "" { + model.Name = &reservedIpName + } + if autoDeleteOk { + reservedIpAutoDeleteBool := reservedIpAutoDelete.(bool) + model.AutoDelete = &reservedIpAutoDeleteBool + } + } + + return model, nil +} + +func virtualNetworkInterfaceIPsToReservedIPPrototype(modelMap map[string]interface{}) (vpcv1.VirtualNetworkInterfaceIPPrototypeIntf, error) { + model := &vpcv1.VirtualNetworkInterfaceIPPrototype{} + if modelMap["reserved_ip"] != nil && modelMap["reserved_ip"].(string) != "" { + model.ID = core.StringPtr(modelMap["reserved_ip"].(string)) + } + return model, nil +} diff --git a/ibm/service/vpc/resource_ibm_is_share_mount_target_test.go b/ibm/service/vpc/resource_ibm_is_share_mount_target_test.go index 3001e5b8e9..fb4a0d6597 100644 --- a/ibm/service/vpc/resource_ibm_is_share_mount_target_test.go +++ b/ibm/service/vpc/resource_ibm_is_share_mount_target_test.go @@ -176,6 +176,68 @@ func TestAccIbmIsShareMountTargetVNI(t *testing.T) { }) } +func TestAccIbmIsShareMountTargetVNIID(t *testing.T) { + var conf vpcv1.ShareMountTarget + vpcname := fmt.Sprintf("tf-vpc-name-%d", acctest.RandIntRange(10, 100)) + targetName := fmt.Sprintf("tf-target-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfvpngw-subnet-%d", acctest.RandIntRange(10, 100)) + sname := fmt.Sprintf("tf-fs-name-%d", acctest.RandIntRange(10, 100)) + vniname := fmt.Sprintf("tf-vni-name-%d", acctest.RandIntRange(10, 100)) + + allowIPSpoofing := true + enableInfrastructureNat := false + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIbmIsShareMountTargetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmIsShareMountTargetConfigVNIID(vpcname, sname, targetName, subnetname, vniname, allowIPSpoofing, enableInfrastructureNat), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIbmIsShareMountTargetExists("ibm_is_share_mount_target.is_share_target", conf), + resource.TestCheckResourceAttr("ibm_is_share_mount_target.is_share_target", "name", targetName), + ), + }, + }, + }) +} + +func testAccCheckIbmIsShareMountTargetConfigVNIID(vpcName, sname, targetName, subnetName, vniName string, enablenat, allowipspoofing bool) string { + return fmt.Sprintf(` + data "ibm_resource_group" "group" { + is_default = "true" + } + resource "ibm_is_share" "is_share" { + zone = "us-south-1" + size = 200 + name = "%s" + profile = "%s" + } + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "us-south-1" + ipv4_cidr_block = "%s" + } + resource "ibm_is_virtual_network_interface" "testacc_vni"{ + name = "%s" + subnet = ibm_is_subnet.testacc_subnet.id + enable_infrastructure_nat = %t + allow_ip_spoofing = %t + } + resource "ibm_is_share_mount_target" "is_share_target" { + share = ibm_is_share.is_share.id + virtual_network_interface { + id = ibm_is_virtual_network_interface.testacc_vni.id + } + + name = "%s" + } + `, sname, acc.ShareProfileName, vpcName, subnetName, acc.ISCIDR, vniName, enablenat, allowipspoofing, targetName) +} func testAccCheckIbmIsShareMountTargetConfigVNISubnet(vpcName, sname, targetName, subnetName, vniName string) string { return fmt.Sprintf(` data "ibm_resource_group" "group" { diff --git a/ibm/service/vpc/resource_ibm_is_share_replica_operations.go b/ibm/service/vpc/resource_ibm_is_share_replica_operations.go index 3e47ac3fbf..e3a1d58273 100644 --- a/ibm/service/vpc/resource_ibm_is_share_replica_operations.go +++ b/ibm/service/vpc/resource_ibm_is_share_replica_operations.go @@ -97,22 +97,7 @@ func resourceIbmIsShareReplicaOperationsCreate(context context.Context, d *schem share_id := d.Get("share_replica").(string) splitShare := d.Get("split_share").(bool) - getShareSourceOptions := &vpcv1.GetShareSourceOptions{ - ShareID: &share_id, - } - sourceShare, response, err := vpcClient.GetShareSourceWithContext(context, getShareSourceOptions) - if err != nil || sourceShare == 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)) - } if !splitShare { fallback_policy := d.Get("fallback_policy").(string) timeout := d.Get("timeout").(int) @@ -142,10 +127,6 @@ func resourceIbmIsShareReplicaOperationsCreate(context context.Context, d *schem if err != nil { return diag.FromErr(err) } - _, err = isWaitForShareReplicationJobDone(context, vpcClient, *sourceShare.ID, d, d.Timeout(schema.TimeoutCreate)) - if err != nil { - return diag.FromErr(err) - } d.SetId(share_id) return nil } diff --git a/ibm/service/vpc/resource_ibm_is_share_test.go b/ibm/service/vpc/resource_ibm_is_share_test.go index b5f4c0d6ae..5b08126d32 100644 --- a/ibm/service/vpc/resource_ibm_is_share_test.go +++ b/ibm/service/vpc/resource_ibm_is_share_test.go @@ -169,6 +169,67 @@ func TestAccIbmIsShareReplicaInline(t *testing.T) { }) } +func TestAccIbmIsShareVNIID(t *testing.T) { + var conf vpcv1.Share + + name := fmt.Sprintf("tf-fs-name-%d", acctest.RandIntRange(10, 100)) + subnetName := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + shareTargetName := fmt.Sprintf("tf-fs-tg-name-%d", acctest.RandIntRange(10, 100)) + vpcname := fmt.Sprintf("tf-vpc-name-%d", acctest.RandIntRange(10, 100)) + vniname := fmt.Sprintf("tf-vni-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIbmIsShareDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmIsShareConfigVNIID(vpcname, subnetName, shareTargetName, vniname, name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIbmIsShareExists("ibm_is_share.is_share", conf), + resource.TestCheckResourceAttr("ibm_is_share.is_share", "name", name), + resource.TestCheckResourceAttrSet("ibm_is_share.is_share", "id"), + resource.TestCheckResourceAttrSet("ibm_is_share.is_share", "mount_targets.0.virtual_network_interface.0.id"), + resource.TestCheckResourceAttrSet("ibm_is_share.is_share", "mount_targets.0.virtual_network_interface.0.name"), + ), + }, + }, + }) +} + +func testAccCheckIbmIsShareConfigVNIID(vpcName, sname, targetName, vniName, shareName string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "group" { + is_default = "true" + } + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "us-south-1" + ipv4_cidr_block = "%s" + } + resource "ibm_is_virtual_network_interface" "testacc_vni"{ + name = "%s" + subnet = ibm_is_subnet.testacc_subnet.id + } + resource "ibm_is_share" "is_share" { + zone = "us-south-1" + size = 220 + name = "%s" + profile = "dp2" + mount_targets { + name = "%s" + virtual_network_interface { + id = ibm_is_virtual_network_interface.testacc_vni.id + } + } + } + `, vpcName, sname, acc.ISCIDR, vniName, shareName, targetName) +} + func testAccCheckIbmIsShareConfigBasic(name string) string { return fmt.Sprintf(` resource "ibm_is_share" "is_share" { diff --git a/ibm/service/vpc/resource_ibm_is_virtual_network_interface.go b/ibm/service/vpc/resource_ibm_is_virtual_network_interface.go new file mode 100644 index 0000000000..0913b46fc2 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_virtual_network_interface.go @@ -0,0 +1,1174 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "bytes" + "context" + "fmt" + "log" + "os" + "time" + + "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" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceIBMIsVirtualNetworkInterface() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMIsVirtualNetworkInterfaceCreate, + ReadContext: resourceIBMIsVirtualNetworkInterfaceRead, + UpdateContext: resourceIBMIsVirtualNetworkInterfaceUpdate, + DeleteContext: resourceIBMIsVirtualNetworkInterfaceDelete, + 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.All( + customdiff.Sequence( + func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { + return flex.ResourceTagsCustomizeDiff(diff) + }, + ), + customdiff.Sequence( + func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { + return flex.ResourceValidateAccessTags(diff, v) + }), + ), + + Schema: map[string]*schema.Schema{ + "allow_ip_spoofing": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Indicates whether source IP spoofing is allowed on this interface. If `false`, source IP spoofing is prevented on this interface. If `true`, source IP spoofing is allowed on this interface.", + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Indicates whether this virtual network interface will be automatically deleted when`target` is deleted.", + }, + "enable_infrastructure_nat": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + 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 network interface, allowing the workload to perform any needed NAT operations.- `allow_ip_spoofing` must be `false`.- If the virtual network interface is attached: - The target `resource_type` must be `bare_metal_server_network_attachment`. - The target `interface_type` must not be `hipersocket`.", + }, + "tags": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_volume", "tags")}, + Set: flex.ResourceIBMVPCHash, + Description: "UserTags for the vni instance", + }, + "access_tags": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_volume", "accesstag")}, + Set: flex.ResourceIBMVPCHash, + Description: "Access management tags for the vni instance", + }, + + "ips": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Computed: true, + Set: hashIpsList, + // DiffSuppressFunc: suppressIPsVNI, + Description: "The reserved IPs bound to this virtual network interface.May be empty when `lifecycle_state` is `pending`.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + // Optional: true, + Computed: true, + Description: "The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "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.", + }, + }, + }, + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + // Default: true, + // DiffSuppressFunc: flex.ApplyOnce, + Description: "Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP.", + }, + "reserved_ip": &schema.Schema{ + Type: schema.TypeString, + Required: true, + // Computed: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + // Optional: true, + Computed: true, + Description: "The name for this reserved IP. The name is unique across all reserved IPs in a subnet.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_virtual_network_interface", "name"), + Description: "The name for this virtual network interface. The name is unique across all virtual network interfaces in the VPC.", + }, + "primary_ip": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "The reserved IP for this virtual network interface.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: "Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound.", + }, + "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 reserved IP.", + }, + "reserved_ip": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The unique identifier for this reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The name for this reserved IP. The name is unique across all reserved IPs in a subnet.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "resource_group": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The resource group id for this virtual network interface.", + }, + "security_groups": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "The security groups for this virtual network interface.", + }, + "subnet": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The associated subnet id.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the virtual network interface was created.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this virtual network interface.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this virtual network interface.", + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the virtual network interface.", + }, + "mac_address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The MAC address of the interface. Absent when the interface is not attached to a target.", + }, + "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 virtual network interface.If absent, this virtual network interface is not attached to a target.", + 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 share mount target.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this share mount target.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this share mount target. The name is unique across all mount targets for the file share.", + }, + "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 virtual 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.TypeString, + Computed: true, + Description: "The zone name this virtual network interface resides in.", + }, + }, + } +} + +func ResourceIBMIsVirtualNetworkInterfaceValidator() *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_virtual_network_interface", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMIsVirtualNetworkInterfaceCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + createVirtualNetworkInterfaceOptions := &vpcv1.CreateVirtualNetworkInterfaceOptions{} + + if _, ok := d.GetOkExists("allow_ip_spoofing"); ok { + createVirtualNetworkInterfaceOptions.SetAllowIPSpoofing(d.Get("allow_ip_spoofing").(bool)) + } + if _, ok := d.GetOkExists("auto_delete"); ok { + createVirtualNetworkInterfaceOptions.SetAutoDelete(d.Get("auto_delete").(bool)) + } + if _, ok := d.GetOkExists("enable_infrastructure_nat"); ok { + createVirtualNetworkInterfaceOptions.SetEnableInfrastructureNat(d.Get("enable_infrastructure_nat").(bool)) + } + if _, ok := d.GetOk("ips"); ok { + var ips []vpcv1.VirtualNetworkInterfaceIPPrototypeIntf + for _, v := range d.Get("ips").(*schema.Set).List() { + value := v.(map[string]interface{}) + ipsItem, err := resourceIBMIsVirtualNetworkInterfaceMapToVirtualNetworkInterfaceIPsReservedIPPrototype(value) + if err != nil { + return diag.FromErr(err) + } + ips = append(ips, ipsItem) + } + createVirtualNetworkInterfaceOptions.SetIps(ips) + } + if _, ok := d.GetOk("name"); ok { + createVirtualNetworkInterfaceOptions.SetName(d.Get("name").(string)) + } + if _, ok := d.GetOk("primary_ip"); ok { + autodelete := true + if autodeleteOk, ok := d.GetOkExists("primary_ip.0.auto_delete"); ok { + autodelete = autodeleteOk.(bool) + } + primaryIPModel, err := resourceIBMIsVirtualNetworkInterfaceMapToVirtualNetworkInterfacePrimaryIPReservedIPPrototype(d.Get("primary_ip.0").(map[string]interface{}), autodelete) + if err != nil { + return diag.FromErr(err) + } + createVirtualNetworkInterfaceOptions.SetPrimaryIP(primaryIPModel) + } + if rgOk, ok := d.GetOk("resource_group"); ok { + rg := rgOk.(string) + createVirtualNetworkInterfaceOptions.ResourceGroup = &vpcv1.ResourceGroupIdentity{ + ID: &rg, + } + } + if _, ok := d.GetOk("security_groups"); ok { + var securityGroups []vpcv1.SecurityGroupIdentityIntf + sg := d.Get("security_groups").(*schema.Set) + for _, v := range sg.List() { + value := v.(string) + securityGroupsItem := &vpcv1.SecurityGroupIdentity{ + ID: &value, + } + securityGroups = append(securityGroups, securityGroupsItem) + } + createVirtualNetworkInterfaceOptions.SetSecurityGroups(securityGroups) + } + if subnetOk, ok := d.GetOk("subnet"); ok { + subnetid := subnetOk.(string) + subnetModel := &vpcv1.SubnetIdentity{ + ID: &subnetid, + } + createVirtualNetworkInterfaceOptions.SetSubnet(subnetModel) + } + // log.Printf("[INFO] vnip2 request map is %s", output(createVirtualNetworkInterfaceOptions)) + + virtualNetworkInterface, response, err := sess.CreateVirtualNetworkInterfaceWithContext(context, createVirtualNetworkInterfaceOptions) + if err != nil { + log.Printf("[DEBUG] CreateVirtualNetworkInterfaceWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateVirtualNetworkInterfaceWithContext failed %s\n%s", err, response)) + } + + d.SetId(*virtualNetworkInterface.ID) + v := os.Getenv("IC_ENV_TAGS") + if _, ok := d.GetOk("tags"); ok || v != "" { + oldList, newList := d.GetChange("tags") + err = flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, *virtualNetworkInterface.CRN, "", isUserTagType) + if err != nil { + log.Printf( + "Error on create of resource vni (%s) tags: %s", d.Id(), err) + } + } + if _, ok := d.GetOk("access_tags"); ok { + oldList, newList := d.GetChange("access_tags") + err = flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, *virtualNetworkInterface.CRN, "", isAccessTagType) + if err != nil { + log.Printf( + "Error on create of resource vni (%s) access tags: %s", d.Id(), err) + } + } + return resourceIBMIsVirtualNetworkInterfaceRead(context, d, meta) +} + +func resourceIBMIsVirtualNetworkInterfaceRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + getVirtualNetworkInterfaceOptions := &vpcv1.GetVirtualNetworkInterfaceOptions{} + + getVirtualNetworkInterfaceOptions.SetID(d.Id()) + + virtualNetworkInterface, response, err := sess.GetVirtualNetworkInterfaceWithContext(context, getVirtualNetworkInterfaceOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetVirtualNetworkInterfaceWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetVirtualNetworkInterfaceWithContext failed %s\n%s", err, response)) + } + + if !core.IsNil(virtualNetworkInterface.AllowIPSpoofing) { + if err = d.Set("allow_ip_spoofing", virtualNetworkInterface.AllowIPSpoofing); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting allow_ip_spoofing: %s", err)) + } + } + if !core.IsNil(virtualNetworkInterface.AutoDelete) { + if err = d.Set("auto_delete", virtualNetworkInterface.AutoDelete); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting auto_delete: %s", err)) + } + } + if !core.IsNil(virtualNetworkInterface.EnableInfrastructureNat) { + if err = d.Set("enable_infrastructure_nat", virtualNetworkInterface.EnableInfrastructureNat); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting enable_infrastructure_nat: %s", err)) + } + } + if !core.IsNil(virtualNetworkInterface.Ips) { + ips := []map[string]interface{}{} + for _, ipsItem := range virtualNetworkInterface.Ips { + if *virtualNetworkInterface.PrimaryIP.ID != *ipsItem.ID { + ipsItemMap, err := resourceIBMIsVirtualNetworkInterfaceReservedIPReferenceToMap(&ipsItem, false) + if err != nil { + return diag.FromErr(err) + } + ips = append(ips, ipsItemMap) + } + } + if err = d.Set("ips", ips); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting ips: %s", err)) + } + } + if !core.IsNil(virtualNetworkInterface.Name) { + if err = d.Set("name", virtualNetworkInterface.Name); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) + } + } + if !core.IsNil(virtualNetworkInterface.PrimaryIP) { + autodelete := d.Get("primary_ip.0.auto_delete").(bool) + primaryIPMap, err := resourceIBMIsVirtualNetworkInterfaceReservedIPReferenceToMap(virtualNetworkInterface.PrimaryIP, autodelete) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("primary_ip", []map[string]interface{}{primaryIPMap}); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting primary_ip: %s", err)) + } + } + if !core.IsNil(virtualNetworkInterface.ResourceGroup) { + d.Set("resource_group", virtualNetworkInterface.ResourceGroup.ID) + } + if !core.IsNil(virtualNetworkInterface.SecurityGroups) { + securityGroups := make([]string, 0) + for _, securityGroupsItem := range virtualNetworkInterface.SecurityGroups { + if securityGroupsItem.ID != nil { + securityGroups = append(securityGroups, *securityGroupsItem.ID) + } + } + if err = d.Set("security_groups", securityGroups); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting security_groups for vni: %s", err)) + } + } + if !core.IsNil(virtualNetworkInterface.Subnet) { + d.Set("subnet", virtualNetworkInterface.Subnet.ID) + } + if err = d.Set("created_at", flex.DateTimeToString(virtualNetworkInterface.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting created_at: %s", err)) + } + if err = d.Set("crn", virtualNetworkInterface.CRN); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting crn: %s", err)) + } + if err = d.Set("href", virtualNetworkInterface.Href); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting href: %s", err)) + } + if err = d.Set("lifecycle_state", virtualNetworkInterface.LifecycleState); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting lifecycle_state: %s", err)) + } + if !core.IsNil(virtualNetworkInterface.MacAddress) { + if err = d.Set("mac_address", virtualNetworkInterface.MacAddress); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting mac_address: %s", err)) + } + } + if err = d.Set("resource_type", virtualNetworkInterface.ResourceType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting resource_type: %s", err)) + } + if !core.IsNil(virtualNetworkInterface.Target) { + targetMap, err := resourceIBMIsVirtualNetworkInterfaceVirtualNetworkInterfaceTargetToMap(virtualNetworkInterface.Target) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("target", []map[string]interface{}{targetMap}); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting target: %s", err)) + } + } else { + d.Set("target", nil) + } + vpcMap, err := resourceIBMIsVirtualNetworkInterfaceVPCReferenceToMap(virtualNetworkInterface.VPC) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("vpc", []map[string]interface{}{vpcMap}); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting vpc: %s", err)) + } + + if virtualNetworkInterface.Zone != nil { + d.Set("zone", *virtualNetworkInterface.Zone.Name) + } + + tags, err := flex.GetGlobalTagsUsingCRN(meta, *virtualNetworkInterface.CRN, "", isUserTagType) + if err != nil { + log.Printf( + "Error on get of resource vni (%s) tags: %s", d.Id(), err) + } + + accesstags, err := flex.GetGlobalTagsUsingCRN(meta, *virtualNetworkInterface.CRN, "", isAccessTagType) + if err != nil { + log.Printf( + "Error on get of resource vni (%s) access tags: %s", d.Id(), err) + } + + d.Set("tags", tags) + d.Set("access_tags", accesstags) + + return nil +} + +func resourceIBMIsVirtualNetworkInterfaceUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + id := d.Id() + + if d.HasChange("tags") { + oldList, newList := d.GetChange("tags") + err := flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, d.Get("crn").(string), "", isUserTagType) + if err != nil { + log.Printf( + "Error on update of resource vni (%s) tags: %s", d.Id(), err) + } + } + + if d.HasChange("access_tags") { + oldList, newList := d.GetChange("access_tags") + err := flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, d.Get("crn").(string), "", isAccessTagType) + if err != nil { + log.Printf( + "Error on update of resource vni (%s) access tags: %s", d.Id(), err) + } + } + updateVirtualNetworkInterfaceOptions := &vpcv1.UpdateVirtualNetworkInterfaceOptions{} + + updateVirtualNetworkInterfaceOptions.SetID(id) + + hasChange := false + + patchVals := &vpcv1.VirtualNetworkInterfacePatch{} + if d.HasChange("allow_ip_spoofing") { + newAllowIPSpoofing := d.Get("allow_ip_spoofing").(bool) + patchVals.AllowIPSpoofing = &newAllowIPSpoofing + hasChange = true + } + if d.HasChange("auto_delete") { + newAutoDelete := d.Get("auto_delete").(bool) + patchVals.AutoDelete = &newAutoDelete + hasChange = true + } + if d.HasChange("enable_infrastructure_nat") { + newEnableInfrastructureNat := d.Get("enable_infrastructure_nat").(bool) + patchVals.EnableInfrastructureNat = &newEnableInfrastructureNat + hasChange = true + } + if d.HasChange("name") { + newName := d.Get("name").(string) + patchVals.Name = &newName + hasChange = true + } + + if d.HasChange("ips") { + oldips, newips := d.GetChange("ips") + os := oldips.(*schema.Set) + ns := newips.(*schema.Set) + var oldset, newset *schema.Set + + var out = make([]interface{}, ns.Len(), ns.Len()) + for i, nA := range ns.List() { + newPack := nA.(map[string]interface{}) + out[i] = newPack["reserved_ip"].(string) + } + newset = schema.NewSet(schema.HashString, out) + + out = make([]interface{}, os.Len(), os.Len()) + for i, oA := range os.List() { + oldPack := oA.(map[string]interface{}) + out[i] = oldPack["reserved_ip"].(string) + } + oldset = schema.NewSet(schema.HashString, out) + + remove := flex.ExpandStringList(oldset.Difference(newset).List()) + add := flex.ExpandStringList(newset.Difference(oldset).List()) + + // log.Printf("[INFO] vnip2 during patch old set is %s", output(os)) + // log.Printf("[INFO] vnip2 during patch new set is %s", output(ns)) + + // for _, nA := range ns.List() { + // newPack := nA.(map[string]interface{}) + // for _, oA := range os.List() { + // oldPack := oA.(map[string]interface{}) + // if strings.Compare(newPack["address"].(string), oldPack["address"].(string)) == 0 { + // reserved_ip := oldPack["reserved_ip"].(string) + // subnetId := d.Get("subnet").(string) + // newName := newPack["name"].(string) + // newAutoDelete := newPack["auto_delete"].(bool) + + // oldName := oldPack["name"].(string) + // oldAutoDelete := oldPack["auto_delete"].(bool) + + // if newName != oldName || newAutoDelete != oldAutoDelete { + + // updatereservedipoptions := &vpcv1.UpdateSubnetReservedIPOptions{ + // SubnetID: &subnetId, + // ID: &reserved_ip, + // } + + // reservedIpPatchModel := &vpcv1.ReservedIPPatch{} + // if strings.Compare(newName, oldName) != 0 { + // reservedIpPatchModel.Name = &newName + // } + + // if newAutoDelete != oldAutoDelete { + // reservedIpPatchModel.AutoDelete = &newAutoDelete + // } + + // reservedIpPatch, err := reservedIpPatchModel.AsPatch() + // if err != nil { + // return diag.FromErr(fmt.Errorf("[ERROR] Error calling asPatch for ReservedIPPatch: %s", err)) + // } + // updatereservedipoptions.ReservedIPPatch = reservedIpPatch + // log.Printf("[INFO] vnip2 updatereservedipoptions %s", output(updatereservedipoptions)) + // _, response, err := sess.UpdateSubnetReservedIP(updatereservedipoptions) + // if err != nil { + // return diag.FromErr(fmt.Errorf("[ERROR] Error while updating reserved ip(%s) of vni(%s) \n%s: %q", reserved_ip, d.Id(), err, response)) + // } + // ns.Remove(nA) + // os.Remove(oA) + // } + // } + // } + // } + // remove := os.Difference(ns).List() + // log.Printf("[INFO] vnip2 remove map %s", output(remove)) + // if remove != nil && len(remove) > 0 { + // subnetId := d.Get("subnet").(string) + // for _, ipItem := range remove { + // value := ipItem.(map[string]interface{}) + // if value["reserved_ip"] != nil && value["reserved_ip"].(string) != "" { + // reservedipid := value["reserved_ip"].(string) + // removeVirtualNetworkInterfaceIPOptions := &vpcv1.RemoveVirtualNetworkInterfaceIPOptions{} + // removeVirtualNetworkInterfaceIPOptions.SetVirtualNetworkInterfaceID(id) + // removeVirtualNetworkInterfaceIPOptions.SetID(reservedipid) + // response, err := sess.RemoveVirtualNetworkInterfaceIPWithContext(context, removeVirtualNetworkInterfaceIPOptions) + // if err != nil { + // log.Printf("[DEBUG] RemoveVirtualNetworkInterfaceIPWithContext failed in VirtualNetworkInterface patch %s\n%s", err, response) + // return diag.FromErr(fmt.Errorf("RemoveVirtualNetworkInterfaceIPWithContext failed in VirtualNetworkInterface patch %s\n%s", err, response)) + // } + // } + // if value["address"] != nil && value["address"].(string) != "" { + // reservedipid := value["reserved_ip"].(string) + // removeSubnetReservedIPOptions := &vpcv1.DeleteSubnetReservedIPOptions{} + // removeSubnetReservedIPOptions.SetSubnetID(subnetId) + // removeSubnetReservedIPOptions.SetID(reservedipid) + // response, err := sess.DeleteSubnetReservedIPWithContext(context, removeSubnetReservedIPOptions) + // if err != nil { + // log.Printf("[DEBUG] DeleteSubnetReservedIPWithContext failed in VirtualNetworkInterface patch %s\n%s", err, response) + // return diag.FromErr(fmt.Errorf("DeleteSubnetReservedIPWithContext failed in VirtualNetworkInterface patch %s\n%s", err, response)) + // } + // } + // } + // } + // add := ns.Difference(os).List() + // log.Printf("[INFO] vnip2 add map %s", output(add)) + + if add != nil && len(add) > 0 { + for _, ipItem := range add { + if ipItem != "" { + + addVirtualNetworkInterfaceIPOptions := &vpcv1.AddVirtualNetworkInterfaceIPOptions{} + addVirtualNetworkInterfaceIPOptions.SetVirtualNetworkInterfaceID(id) + addVirtualNetworkInterfaceIPOptions.SetID(ipItem) + _, response, err := sess.AddVirtualNetworkInterfaceIPWithContext(context, addVirtualNetworkInterfaceIPOptions) + if err != nil { + log.Printf("[DEBUG] AddVirtualNetworkInterfaceIPWithContext failed in VirtualNetworkInterface patch %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("AddVirtualNetworkInterfaceIPWithContext failed in VirtualNetworkInterface patch %s\n%s", err, response)) + } + } + } + } + if remove != nil && len(remove) > 0 { + for _, ipItem := range remove { + if ipItem != "" { + + removeVirtualNetworkInterfaceIPOptions := &vpcv1.RemoveVirtualNetworkInterfaceIPOptions{} + removeVirtualNetworkInterfaceIPOptions.SetVirtualNetworkInterfaceID(id) + removeVirtualNetworkInterfaceIPOptions.SetID(ipItem) + response, err := sess.RemoveVirtualNetworkInterfaceIPWithContext(context, removeVirtualNetworkInterfaceIPOptions) + if err != nil { + log.Printf("[DEBUG] RemoveVirtualNetworkInterfaceIPWithContext failed in VirtualNetworkInterface patch %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("RemoveVirtualNetworkInterfaceIPWithContext failed in VirtualNetworkInterface patch %s\n%s", err, response)) + } + } + } + } + + } + if !d.IsNewResource() && d.HasChange("primary_ip") { + subnetId := d.Get("subnet").(string) + ripId := d.Get("primary_ip.0.reserved_ip").(string) + updateripoptions := &vpcv1.UpdateSubnetReservedIPOptions{ + SubnetID: &subnetId, + ID: &ripId, + } + reservedIpPath := &vpcv1.ReservedIPPatch{} + if d.HasChange("primary_ip.0.name") { + name := d.Get("primary_ip.0.name").(string) + reservedIpPath.Name = &name + } + if d.HasChange("primary_ip.0.auto_delete") { + auto := d.Get("primary_ip.0.auto_delete").(bool) + reservedIpPath.AutoDelete = &auto + } + reservedIpPathAsPatch, err := reservedIpPath.AsPatch() + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error calling reserved ip as patch on vni patch \n%s", err)) + } + updateripoptions.ReservedIPPatch = reservedIpPathAsPatch + _, response, err := sess.UpdateSubnetReservedIP(updateripoptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating vni reserved ip(%s): %s\n%s", ripId, err, response)) + } + } + if d.HasChange("security_groups") && !d.IsNewResource() { + ovs, nvs := d.GetChange("security_groups") + vniId := d.Id() + ov := ovs.(*schema.Set) + nv := nvs.(*schema.Set) + remove := flex.ExpandStringList(ov.Difference(nv).List()) + add := flex.ExpandStringList(nv.Difference(ov).List()) + if len(add) > 0 { + for i := range add { + createsgnicoptions := &vpcv1.CreateSecurityGroupTargetBindingOptions{ + SecurityGroupID: &add[i], + ID: &vniId, + } + _, response, err := sess.CreateSecurityGroupTargetBinding(createsgnicoptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error while creating security group %q for virtual network interface %s\n%s: %q", add[i], d.Id(), err, response)) + } + _, err = isWaitForVirtualNetworkInterfaceAvailable(sess, vniId, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return diag.FromErr(err) + } + } + + } + if len(remove) > 0 { + for i := range remove { + deletesgnicoptions := &vpcv1.DeleteSecurityGroupTargetBindingOptions{ + SecurityGroupID: &remove[i], + ID: &vniId, + } + response, err := sess.DeleteSecurityGroupTargetBinding(deletesgnicoptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error while removing security group %q for virtual network interface %s\n%s: %q", remove[i], d.Id(), err, response)) + } + _, err = isWaitForVirtualNetworkInterfaceAvailable(sess, vniId, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return diag.FromErr(err) + } + } + } + } + + if hasChange { + updateVirtualNetworkInterfaceOptions.VirtualNetworkInterfacePatch, _ = patchVals.AsPatch() + _, response, err := sess.UpdateVirtualNetworkInterfaceWithContext(context, updateVirtualNetworkInterfaceOptions) + if err != nil { + log.Printf("[DEBUG] UpdateVirtualNetworkInterfaceWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateVirtualNetworkInterfaceWithContext failed %s\n%s", err, response)) + } + } + + return resourceIBMIsVirtualNetworkInterfaceRead(context, d, meta) +} + +func resourceIBMIsVirtualNetworkInterfaceDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + deleteVirtualNetworkInterfacesOptions := &vpcv1.DeleteVirtualNetworkInterfacesOptions{} + + deleteVirtualNetworkInterfacesOptions.SetID(d.Id()) + + response, err := sess.DeleteVirtualNetworkInterfacesWithContext(context, deleteVirtualNetworkInterfacesOptions) + if err != nil { + log.Printf("[DEBUG] DeleteVirtualNetworkInterfacesWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteVirtualNetworkInterfacesWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIBMIsVirtualNetworkInterfaceMapToVirtualNetworkInterfaceIPsReservedIPPrototype(modelMap map[string]interface{}) (vpcv1.VirtualNetworkInterfaceIPPrototypeIntf, error) { + model := &vpcv1.VirtualNetworkInterfaceIPPrototype{} + if modelMap["reserved_ip"] != nil && modelMap["reserved_ip"].(string) != "" { + model.ID = core.StringPtr(modelMap["reserved_ip"].(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 resourceIBMIsVirtualNetworkInterfaceMapToVirtualNetworkInterfacePrimaryIPReservedIPPrototype(modelMap map[string]interface{}, autodelete bool) (vpcv1.VirtualNetworkInterfacePrimaryIPPrototypeIntf, error) { + model := &vpcv1.VirtualNetworkInterfacePrimaryIPPrototype{} + if modelMap["reserved_ip"] != nil && modelMap["reserved_ip"].(string) != "" { + model.ID = core.StringPtr(modelMap["reserved_ip"].(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)) + } + model.AutoDelete = core.BoolPtr(autodelete) + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + return model, nil +} + +func resourceIBMIsVirtualNetworkInterfaceReservedIPReferenceToMap(model *vpcv1.ReservedIPReference, autodelete bool) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["address"] = model.Address + modelMap["auto_delete"] = autodelete + if model.Deleted != nil { + deletedMap, err := resourceIBMIsVirtualNetworkInterfaceReservedIPReferenceDeletedToMap(model.Deleted) + if err != nil { + return modelMap, err + } + modelMap["deleted"] = []map[string]interface{}{deletedMap} + } + modelMap["href"] = model.Href + modelMap["reserved_ip"] = model.ID + modelMap["name"] = model.Name + modelMap["resource_type"] = model.ResourceType + return modelMap, nil +} + +func resourceIBMIsVirtualNetworkInterfaceReservedIPReferenceDeletedToMap(model *vpcv1.ReservedIPReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = model.MoreInfo + return modelMap, nil +} + +func resourceIBMIsVirtualNetworkInterfaceSecurityGroupReferenceToMap(model *vpcv1.SecurityGroupReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = model.CRN + if model.Deleted != nil { + deletedMap, err := resourceIBMIsVirtualNetworkInterfaceSecurityGroupReferenceDeletedToMap(model.Deleted) + if err != nil { + return modelMap, err + } + modelMap["deleted"] = []map[string]interface{}{deletedMap} + } + modelMap["href"] = model.Href + modelMap["security_group"] = model.ID + modelMap["name"] = model.Name + return modelMap, nil +} + +func resourceIBMIsVirtualNetworkInterfaceSecurityGroupReferenceDeletedToMap(model *vpcv1.SecurityGroupReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = model.MoreInfo + return modelMap, nil +} + +func resourceIBMIsVirtualNetworkInterfaceVirtualNetworkInterfaceTargetToMap(model vpcv1.VirtualNetworkInterfaceTargetIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.VirtualNetworkInterfaceTargetShareMountTargetReference); ok { + return resourceIBMIsVirtualNetworkInterfaceVirtualNetworkInterfaceTargetShareMountTargetReferenceToMap(model.(*vpcv1.VirtualNetworkInterfaceTargetShareMountTargetReference)) + } else if _, ok := model.(*vpcv1.VirtualNetworkInterfaceTargetInstanceNetworkAttachmentReferenceVirtualNetworkInterfaceContext); ok { + return resourceIBMIsVirtualNetworkInterfaceVirtualNetworkInterfaceTargetInstanceNetworkAttachmentReferenceVirtualNetworkInterfaceContextToMap(model.(*vpcv1.VirtualNetworkInterfaceTargetInstanceNetworkAttachmentReferenceVirtualNetworkInterfaceContext)) + } else if _, ok := model.(*vpcv1.VirtualNetworkInterfaceTargetBareMetalServerNetworkAttachmentReferenceVirtualNetworkInterfaceContext); ok { + return resourceIBMIsVirtualNetworkInterfaceVirtualNetworkInterfaceTargetBareMetalServerNetworkAttachmentReferenceVirtualNetworkInterfaceContextToMap(model.(*vpcv1.VirtualNetworkInterfaceTargetBareMetalServerNetworkAttachmentReferenceVirtualNetworkInterfaceContext)) + } else if _, ok := model.(*vpcv1.VirtualNetworkInterfaceTarget); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.VirtualNetworkInterfaceTarget) + if model.Deleted != nil { + deletedMap, err := resourceIBMIsVirtualNetworkInterfaceShareMountTargetReferenceDeletedToMap(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.VirtualNetworkInterfaceTargetIntf subtype encountered") + } +} + +func resourceIBMIsVirtualNetworkInterfaceShareMountTargetReferenceDeletedToMap(model *vpcv1.ShareMountTargetReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = model.MoreInfo + return modelMap, nil +} + +func resourceIBMIsVirtualNetworkInterfaceVirtualNetworkInterfaceTargetShareMountTargetReferenceToMap(model *vpcv1.VirtualNetworkInterfaceTargetShareMountTargetReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Deleted != nil { + deletedMap, err := resourceIBMIsVirtualNetworkInterfaceShareMountTargetReferenceDeletedToMap(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 isWaitForVirtualNetworkInterfaceAvailable(client *vpcv1.VpcV1, id string, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for VirtualNetworkInterface (%s) to be available.", id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"", "pending"}, + Target: []string{"done", "failed", "stable"}, + Refresh: isVirtualNetworkInterfaceRefreshFunc(client, id), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func isVirtualNetworkInterfaceRefreshFunc(client *vpcv1.VpcV1, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + vnigetoptions := &vpcv1.GetVirtualNetworkInterfaceOptions{ + ID: &id, + } + vni, response, err := client.GetVirtualNetworkInterface(vnigetoptions) + if err != nil { + return nil, "failed", fmt.Errorf("[ERROR] Error getting vni: %s\n%s", err, response) + } + if *vni.LifecycleState == "failed" || *vni.LifecycleState == "suspended" { + return vni, *vni.LifecycleState, fmt.Errorf("[ERROR] Error VirtualNetworkInterface in : %s state", *vni.LifecycleState) + } + return vni, *vni.LifecycleState, nil + } +} + +func resourceIBMIsVirtualNetworkInterfaceVirtualNetworkInterfaceTargetInstanceNetworkAttachmentReferenceVirtualNetworkInterfaceContextToMap(model *vpcv1.VirtualNetworkInterfaceTargetInstanceNetworkAttachmentReferenceVirtualNetworkInterfaceContext) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + // if model.Deleted != nil { + // deletedMap, err := resourceIBMIsVirtualNetworkInterfaceInstanceNetworkAttachmentReferenceVirtualNetworkInterfaceContextDeletedToMap(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 resourceIBMIsVirtualNetworkInterfaceInstanceNetworkAttachmentReferenceVirtualNetworkInterfaceContextDeletedToMap(model *vpcv1.InstanceNetworkAttachmentReferenceVirtualNetworkInterfaceContextDeleted) (map[string]interface{}, error) { +// modelMap := make(map[string]interface{}) +// modelMap["more_info"] = model.MoreInfo +// return modelMap, nil +// } + +func resourceIBMIsVirtualNetworkInterfaceVirtualNetworkInterfaceTargetBareMetalServerNetworkAttachmentReferenceVirtualNetworkInterfaceContextToMap(model *vpcv1.VirtualNetworkInterfaceTargetBareMetalServerNetworkAttachmentReferenceVirtualNetworkInterfaceContext) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + // if model.Deleted != nil { + // deletedMap, err := resourceIBMIsVirtualNetworkInterfaceBareMetalServerNetworkAttachmentReferenceVirtualNetworkInterfaceContextDeletedToMap(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 resourceIBMIsVirtualNetworkInterfaceBareMetalServerNetworkAttachmentReferenceVirtualNetworkInterfaceContextDeletedToMap(model *vpcv1.BareMetalServerNetworkAttachmentReferenceVirtualNetworkInterfaceContextDeleted) (map[string]interface{}, error) { +// modelMap := make(map[string]interface{}) +// modelMap["more_info"] = model.MoreInfo +// return modelMap, nil +// } + +func resourceIBMIsVirtualNetworkInterfaceVPCReferenceToMap(model *vpcv1.VPCReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = model.CRN + if model.Deleted != nil { + deletedMap, err := resourceIBMIsVirtualNetworkInterfaceVPCReferenceDeletedToMap(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 resourceIBMIsVirtualNetworkInterfaceVPCReferenceDeletedToMap(model *vpcv1.VPCReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = model.MoreInfo + return modelMap, nil +} + +func hashIpsList(v interface{}) int { + var buf bytes.Buffer + a := v.(map[string]interface{}) + // buf.WriteString(fmt.Sprintf("%s-", a["address"].(string))) + buf.WriteString(fmt.Sprintf("%s-", a["reserved_ip"].(string))) + return conns.String(buf.String()) +} + +// func suppressIPsVNI(k, old, new string, d *schema.ResourceData) bool { +// oldips, newips := d.GetChange("ips") +// os := oldips.(*schema.Set) +// ns := newips.(*schema.Set) +// if os.Len() == ns.Len() { +// for _, nA := range ns.List() { +// newPack := nA.(map[string]interface{}) +// for _, oA := range os.List() { +// oldPack := oA.(map[string]interface{}) +// if strings.Compare(newPack["name"].(string), oldPack["address"].(string)) == 0 { +// } +// } +// } +// return true +// } else { +// return false +// } +// } diff --git a/ibm/service/vpc/resource_ibm_is_virtual_network_interface_floating_ip.go b/ibm/service/vpc/resource_ibm_is_virtual_network_interface_floating_ip.go new file mode 100644 index 0000000000..d1815061a7 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_virtual_network_interface_floating_ip.go @@ -0,0 +1,193 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func ResourceIBMIsVirtualNetworkInterfaceFloatingIP() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMIsVirtualNetworkInterfaceFloatingIPCreate, + ReadContext: resourceIBMIsVirtualNetworkInterfaceFloatingIPRead, + DeleteContext: resourceIBMIsVirtualNetworkInterfaceFloatingIPDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "virtual_network_interface": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The virtual network interface identifier", + }, + "floating_ip": &schema.Schema{ + Type: schema.TypeString, + ForceNew: true, + Required: true, + Description: "The floating IP identifier", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this floating IP. The name is unique across all floating IPs in the region.", + }, + + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted, and provides some 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", + }, + }, + }, + }, + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The globally unique IP address.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this floating IP.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this floating IP.", + }, + }, + } +} + +func resourceIBMIsVirtualNetworkInterfaceFloatingIPCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + createVirtualNetworkInterfaceFloatingIPOptions := &vpcv1.AddNetworkInterfaceFloatingIPOptions{} + vniId := d.Get("virtual_network_interface").(string) + fipId := d.Get("floating_ip").(string) + createVirtualNetworkInterfaceFloatingIPOptions.VirtualNetworkInterfaceID = &vniId + createVirtualNetworkInterfaceFloatingIPOptions.ID = &fipId + + floatingIP, response, err := sess.AddNetworkInterfaceFloatingIPWithContext(context, createVirtualNetworkInterfaceFloatingIPOptions) + if err != nil { + log.Printf("[DEBUG] AddNetworkInterfaceFloatingIPOptions failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("AddNetworkInterfaceFloatingIPOptions failed %s\n%s", err, response)) + } + d.SetId(MakeTerraformVNIFloatingIpID(vniId, fipId)) + resourceIBMIsVirtualNetworkInterfaceFloatingIPGet(d, floatingIP) + + return nil +} + +func resourceIBMIsVirtualNetworkInterfaceFloatingIPRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + vniId, fipId, err := ParseVNIFloatingIpTerraformID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + getNetworkInterfaceFloatingIPOptions := &vpcv1.GetNetworkInterfaceFloatingIPOptions{} + getNetworkInterfaceFloatingIPOptions.SetVirtualNetworkInterfaceID(vniId) + getNetworkInterfaceFloatingIPOptions.SetID(fipId) + + floatingIP, response, err := sess.GetNetworkInterfaceFloatingIPWithContext(context, getNetworkInterfaceFloatingIPOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetVirtualNetworkInterfaceFloatingIPWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetVirtualNetworkInterfaceFloatingIPWithContext failed %s\n%s", err, response)) + } + resourceIBMIsVirtualNetworkInterfaceFloatingIPGet(d, floatingIP) + + return nil +} +func resourceIBMIsVirtualNetworkInterfaceFloatingIPGet(d *schema.ResourceData, floatingIP *vpcv1.FloatingIPReference) diag.Diagnostics { + if !core.IsNil(floatingIP.Name) { + if err := d.Set("name", floatingIP.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + } + if err := d.Set("address", floatingIP.Address); err != nil { + return diag.FromErr(fmt.Errorf("Error setting address: %s", err)) + } + + if err := d.Set("crn", floatingIP.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + if err := d.Set("href", floatingIP.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + deleted := make(map[string]interface{}) + + if floatingIP.Deleted != nil && floatingIP.Deleted.MoreInfo != nil { + deleted["more_info"] = floatingIP.Deleted + } + d.Set("deleted", []map[string]interface{}{deleted}) + + return nil +} + +func resourceIBMIsVirtualNetworkInterfaceFloatingIPDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + vniId, fipId, err := ParseVNIFloatingIpTerraformID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + removeNetworkInterfaceFloatingIPOptions := &vpcv1.RemoveNetworkInterfaceFloatingIPOptions{} + + removeNetworkInterfaceFloatingIPOptions.SetVirtualNetworkInterfaceID(vniId) + removeNetworkInterfaceFloatingIPOptions.SetID(fipId) + + response, err := sess.RemoveNetworkInterfaceFloatingIPWithContext(context, removeNetworkInterfaceFloatingIPOptions) + if err != nil { + log.Printf("[DEBUG] RemoveNetworkInterfaceFloatingIPWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("RemoveNetworkInterfaceFloatingIPWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func MakeTerraformVNIFloatingIpID(id1, id2 string) string { + // Include both virtual network interface id and floating ip id to create a unique Terraform id. As a bonus, + // we can extract the bare metal sever id as needed for API calls such as READ. + return fmt.Sprintf("%s/%s", id1, id2) +} + +func ParseVNIFloatingIpTerraformID(s string) (string, string, error) { + segments := strings.Split(s, "/") + if len(segments) != 2 { + return "", "", fmt.Errorf("invalid terraform Id %s (incorrect number of segments for vitual network interface floating ip)", s) + } + if segments[0] == "" || segments[1] == "" { + return "", "", fmt.Errorf("invalid terraform Id %s (one or more empty segments) for vitual network interface floating ip", s) + } + return segments[0], segments[1], nil +} diff --git a/ibm/service/vpc/resource_ibm_is_virtual_network_interface_floating_ip_test.go b/ibm/service/vpc/resource_ibm_is_virtual_network_interface_floating_ip_test.go new file mode 100644 index 0000000000..ee8a5ff5e6 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_virtual_network_interface_floating_ip_test.go @@ -0,0 +1,137 @@ +// Copyright IBM Corp. 2023 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/service/vpc" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func TestAccIBMIsVirtualNetworkInterfaceFloatingIPBasic(t *testing.T) { + var conf vpcv1.FloatingIPReference + vpcname := fmt.Sprintf("tfp-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfp-subnet-%d", acctest.RandIntRange(10, 100)) + vniname := fmt.Sprintf("tfp-createname-%d", acctest.RandIntRange(10, 100)) + floatingipname := fmt.Sprintf("tfp-reservedip-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIsVirtualNetworkInterfaceFloatingIPDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsVirtualNetworkInterfaceFloatingIPConfigBasic(vpcname, subnetname, vniname, floatingipname), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIsVirtualNetworkInterfaceFloatingIPExists("ibm_is_virtual_network_interface_floating_ip.testacc_vni_floatingip", conf), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface_floating_ip.testacc_vni_floatingip", "address"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface_floating_ip.testacc_vni_floatingip", "crn"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface_floating_ip.testacc_vni_floatingip", "href"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface_floating_ip.testacc_vni_floatingip", "id"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface_floating_ip.testacc_vni_floatingip", "name"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface_floating_ip.testacc_vni_floatingip", "virtual_network_interface"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface_floating_ip.testacc_vni_floatingip", "floating_ip"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsVirtualNetworkInterfaceFloatingIPConfigBasic(vpcname, subnetname, vniname, floatingipname 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_virtual_network_interface" "testacc_vni"{ + name = "%s" + subnet = ibm_is_subnet.testacc_subnet.id + } + + resource "ibm_is_floating_ip" "testacc_floatingip" { + name = "%s" + zone = ibm_is_subnet.testacc_subnet.zone + } + resource "ibm_is_virtual_network_interface_floating_ip" "testacc_vni_floatingip" { + virtual_network_interface = ibm_is_virtual_network_interface.testacc_vni.id + floating_ip = ibm_is_floating_ip.testacc_floatingip.id + } + `, vpcname, subnetname, acc.ISZoneName, vniname, floatingipname) +} +func testAccCheckIBMIsVirtualNetworkInterfaceFloatingIPExists(n string, obj vpcv1.FloatingIPReference) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + sess, err := vpcClient(acc.TestAccProvider.Meta()) + if err != nil { + return err + } + vniid, fipid, err := vpc.ParseVNIFloatingIpTerraformID(rs.Primary.ID) + if err != nil { + return err + } + getVirtualNetworkInterfaceFloatingIPOptions := &vpcv1.GetNetworkInterfaceFloatingIPOptions{} + + getVirtualNetworkInterfaceFloatingIPOptions.SetVirtualNetworkInterfaceID(vniid) + getVirtualNetworkInterfaceFloatingIPOptions.SetID(fipid) + + floatingIP, _, err := sess.GetNetworkInterfaceFloatingIP(getVirtualNetworkInterfaceFloatingIPOptions) + if err != nil { + return err + } + + obj = *floatingIP + return nil + } +} + +func testAccCheckIBMIsVirtualNetworkInterfaceFloatingIPDestroy(s *terraform.State) error { + sess, err := vpcClient(acc.TestAccProvider.Meta()) + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_virtual_network_interface_floating_ip" { + continue + } + vniid, fipid, err := vpc.ParseVNIFloatingIpTerraformID(rs.Primary.ID) + if err != nil { + return err + } + getVirtualNetworkInterfaceFloatingIPOptions := &vpcv1.GetNetworkInterfaceFloatingIPOptions{} + + getVirtualNetworkInterfaceFloatingIPOptions.SetVirtualNetworkInterfaceID(vniid) + getVirtualNetworkInterfaceFloatingIPOptions.SetID(fipid) + + // Try to find the key + _, response, err := sess.GetNetworkInterfaceFloatingIP(getVirtualNetworkInterfaceFloatingIPOptions) + + if err == nil { + return fmt.Errorf("VirtualNetworkInterfaceFloatingIP still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for VirtualNetworkInterfaceFloatingIP (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/vpc/resource_ibm_is_virtual_network_interface_ip.go b/ibm/service/vpc/resource_ibm_is_virtual_network_interface_ip.go new file mode 100644 index 0000000000..4b226ede55 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_virtual_network_interface_ip.go @@ -0,0 +1,156 @@ +// Copyright IBM Corp. 2023 All Rights VirtualNetworkInterface. +// 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/flex" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func ResourceIBMIsVirtualNetworkInterfaceIP() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMIsVirtualNetworkInterfaceIPCreate, + ReadContext: resourceIBMIsVirtualNetworkInterfaceIPRead, + DeleteContext: resourceIBMIsVirtualNetworkInterfaceIPDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "virtual_network_interface": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The virtual network interface identifier.", + }, + "reserved_ip": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The reserved ip identifier.", + }, + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this reserved IP. The name is unique across all reserved IPs in a subnet.", + }, + + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP.", + }, + + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + } +} +func resourceIBMIsVirtualNetworkInterfaceIPCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + addVirtualNetworkInterfaceIPOptions := &vpcv1.AddVirtualNetworkInterfaceIPOptions{} + + addVirtualNetworkInterfaceIPOptions.SetVirtualNetworkInterfaceID(d.Get("virtual_network_interface").(string)) + addVirtualNetworkInterfaceIPOptions.SetID(d.Get("reserved_ip").(string)) + + reservedIP, response, err := vpcClient.AddVirtualNetworkInterfaceIPWithContext(context, addVirtualNetworkInterfaceIPOptions) + if err != nil { + log.Printf("[DEBUG] AddVirtualNetworkInterfaceIPWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("AddVirtualNetworkInterfaceIPWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *addVirtualNetworkInterfaceIPOptions.VirtualNetworkInterfaceID, *reservedIP.ID)) + + return resourceIBMIsVirtualNetworkInterfaceIPRead(context, d, meta) +} + +func resourceIBMIsVirtualNetworkInterfaceIPRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + getVirtualNetworkInterfaceIPOptions := &vpcv1.GetVirtualNetworkInterfaceIPOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getVirtualNetworkInterfaceIPOptions.SetVirtualNetworkInterfaceID(parts[0]) + getVirtualNetworkInterfaceIPOptions.SetID(parts[1]) + + reservedIP, response, err := vpcClient.GetVirtualNetworkInterfaceIPWithContext(context, getVirtualNetworkInterfaceIPOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetVirtualNetworkInterfaceIPWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetVirtualNetworkInterfaceIPWithContext failed for resource %s\n%s", err, response)) + } + + if !core.IsNil(reservedIP.Address) { + if err = d.Set("address", reservedIP.Address); err != nil { + return diag.FromErr(fmt.Errorf("Error setting address: %s", err)) + } + } + if !core.IsNil(reservedIP.Name) { + if err = d.Set("name", reservedIP.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + } + if err = d.Set("href", reservedIP.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + if err = d.Set("resource_type", reservedIP.ResourceType); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_type: %s", err)) + } + return nil +} + +func resourceIBMIsVirtualNetworkInterfaceIPDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + return diag.FromErr(err) + } + + removeVirtualNetworkInterfaceIPOptions := &vpcv1.RemoveVirtualNetworkInterfaceIPOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + removeVirtualNetworkInterfaceIPOptions.SetVirtualNetworkInterfaceID(parts[0]) + removeVirtualNetworkInterfaceIPOptions.SetID(parts[1]) + + response, err := vpcClient.RemoveVirtualNetworkInterfaceIPWithContext(context, removeVirtualNetworkInterfaceIPOptions) + if err != nil { + log.Printf("[DEBUG] RemoveVirtualNetworkInterfaceIPWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("RemoveVirtualNetworkInterfaceIPWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} diff --git a/ibm/service/vpc/resource_ibm_is_virtual_network_interface_ip_test.go b/ibm/service/vpc/resource_ibm_is_virtual_network_interface_ip_test.go new file mode 100644 index 0000000000..3b333d5788 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_virtual_network_interface_ip_test.go @@ -0,0 +1,136 @@ +// Copyright IBM Corp. 2023 All Rights VirtualNetworkInterface. +// 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/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func TestAccIBMIsVirtualNetworkInterfaceIPBasic(t *testing.T) { + var conf vpcv1.ReservedIPReference + vpcname := fmt.Sprintf("tfp-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfp-subnet-%d", acctest.RandIntRange(10, 100)) + vniname := fmt.Sprintf("tfp-createname-%d", acctest.RandIntRange(10, 100)) + reservedipname := fmt.Sprintf("tfp-reservedip-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIsVirtualNetworkInterfaceIPDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsVirtualNetworkInterfaceIPConfigBasic(vpcname, subnetname, vniname, reservedipname), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIsVirtualNetworkInterfaceIPExists("ibm_is_virtual_network_interface_ip.testacc_vni_reservedip", conf), + resource.TestCheckResourceAttr("ibm_is_virtual_network_interface_ip.testacc_vni_reservedip", "resource_type", "subnet_reserved_ip"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface_ip.testacc_vni_reservedip", "address"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface_ip.testacc_vni_reservedip", "href"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface_ip.testacc_vni_reservedip", "id"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface_ip.testacc_vni_reservedip", "name"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface_ip.testacc_vni_reservedip", "reserved_ip"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface_ip.testacc_vni_reservedip", "virtual_network_interface"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsVirtualNetworkInterfaceIPConfigBasic(vpcname, subnetname, vniname, reservedipname 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_virtual_network_interface" "testacc_vni"{ + name = "%s" + subnet = ibm_is_subnet.testacc_subnet.id + } + + resource "ibm_is_subnet_reserved_ip" "testacc_reservedip" { + subnet = ibm_is_subnet.testacc_subnet.id + name = "%s" + } + resource "ibm_is_virtual_network_interface_ip" "testacc_vni_reservedip" { + virtual_network_interface = ibm_is_virtual_network_interface.testacc_vni.id + reserved_ip = ibm_is_subnet_reserved_ip.testacc_reservedip.reserved_ip + } + + `, vpcname, subnetname, acc.ISZoneName, vniname, reservedipname) +} + +func testAccCheckIBMIsVirtualNetworkInterfaceIPExists(n string, obj vpcv1.ReservedIPReference) 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 := vpcClient(acc.TestAccProvider.Meta()) + if err != nil { + return err + } + + getSubnetVirtualNetworkInterfaceIPOptions := &vpcv1.GetVirtualNetworkInterfaceIPOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + getSubnetVirtualNetworkInterfaceIPOptions.SetVirtualNetworkInterfaceID(parts[0]) + getSubnetVirtualNetworkInterfaceIPOptions.SetID(parts[1]) + + reservedIP, _, err := vpcClient.GetVirtualNetworkInterfaceIP(getSubnetVirtualNetworkInterfaceIPOptions) + if err != nil { + return err + } + obj = *reservedIP + return nil + } +} + +func testAccCheckIBMIsVirtualNetworkInterfaceIPDestroy(s *terraform.State) error { + vpcClient, err := vpcClient(acc.TestAccProvider.Meta()) + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_virtual_network_interface_ip" { + continue + } + getSubnetVirtualNetworkInterfaceIPOptions := &vpcv1.GetVirtualNetworkInterfaceIPOptions{} + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + getSubnetVirtualNetworkInterfaceIPOptions.SetVirtualNetworkInterfaceID(parts[0]) + getSubnetVirtualNetworkInterfaceIPOptions.SetID(parts[1]) + + // Try to find the key + _, response, err := vpcClient.GetVirtualNetworkInterfaceIP(getSubnetVirtualNetworkInterfaceIPOptions) + + if err == nil { + return fmt.Errorf("VirtualNetworkInterfaceIP still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for VirtualNetworkInterfaceIP (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + return nil +} diff --git a/ibm/service/vpc/resource_ibm_is_virtual_network_interface_test.go b/ibm/service/vpc/resource_ibm_is_virtual_network_interface_test.go new file mode 100644 index 0000000000..021e95a510 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_virtual_network_interface_test.go @@ -0,0 +1,345 @@ +// Copyright IBM Corp. 2023 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/vpc-go-sdk/vpcv1" +) + +func TestAccIBMIsVirtualNetworkInterfaceBasic(t *testing.T) { + var conf vpcv1.VirtualNetworkInterface + vpcname := fmt.Sprintf("tfvpngw-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfvpngw-subnet-%d", acctest.RandIntRange(10, 100)) + vniname := fmt.Sprintf("tfvpngw-createname-%d", acctest.RandIntRange(10, 100)) + tag1 := "env:test" + tag2 := "env:dev" + tag3 := "env:prod" + enable_infrastructure_nat := true + allow_ip_spoofing := true + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIsVirtualNetworkInterfaceDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsVirtualNetworkInterfaceConfigBasic(vpcname, subnetname, vniname, tag1, tag2, tag3, enable_infrastructure_nat, allow_ip_spoofing, false), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIsVirtualNetworkInterfaceExists("ibm_is_virtual_network_interface.testacc_vni", conf), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "subnet"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "name"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "created_at"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "crn"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "href"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "vpc.#"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "zone"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "primary_ip.#"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "ips.#"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "id"), + resource.TestCheckResourceAttr("ibm_is_virtual_network_interface.testacc_vni", "enable_infrastructure_nat", "true"), + resource.TestCheckResourceAttr("ibm_is_virtual_network_interface.testacc_vni", "lifecycle_state", "stable"), + resource.TestCheckResourceAttr("ibm_is_virtual_network_interface.testacc_vni", "resource_type", "virtual_network_interface"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "resource_group"), + resource.TestCheckResourceAttr("ibm_is_virtual_network_interface.testacc_vni", "tags.#", "3"), + resource.TestCheckResourceAttr("ibm_is_virtual_network_interface.testacc_vni", "allow_ip_spoofing", "true"), + ), + }, + resource.TestStep{ + Config: testAccCheckIBMIsVirtualNetworkInterfaceConfigBasic(vpcname, subnetname, vniname, tag1, tag2, tag3, enable_infrastructure_nat, allow_ip_spoofing, true), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIsVirtualNetworkInterfaceExists("ibm_is_virtual_network_interface.testacc_vni", conf), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "subnet"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "name"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "created_at"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "crn"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "href"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "vpc.#"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "zone"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "primary_ip.#"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "ips.#"), + resource.TestCheckResourceAttr("ibm_is_virtual_network_interface.testacc_vni", "tags.#", "2"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "id"), + resource.TestCheckResourceAttr("ibm_is_virtual_network_interface.testacc_vni", "enable_infrastructure_nat", "true"), + resource.TestCheckResourceAttr("ibm_is_virtual_network_interface.testacc_vni", "lifecycle_state", "stable"), + resource.TestCheckResourceAttr("ibm_is_virtual_network_interface.testacc_vni", "resource_type", "virtual_network_interface"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "resource_group"), + resource.TestCheckResourceAttr("ibm_is_virtual_network_interface.testacc_vni", "allow_ip_spoofing", "true"), + ), + }, + }, + }) +} +func TestAccIBMIsVirtualNetworkInterfaceResourceGroup(t *testing.T) { + var conf vpcv1.VirtualNetworkInterface + vpcname := fmt.Sprintf("tfvpngw-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfvpngw-subnet-%d", acctest.RandIntRange(10, 100)) + vniname := fmt.Sprintf("tfvpngw-createname-%d", acctest.RandIntRange(10, 100)) + enable_infrastructure_nat := true + allow_ip_spoofing := true + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIsVirtualNetworkInterfaceDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsVirtualNetworkInterfaceConfigResourceGroup(vpcname, subnetname, vniname, enable_infrastructure_nat, allow_ip_spoofing), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIsVirtualNetworkInterfaceExists("ibm_is_virtual_network_interface.testacc_vni", conf), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "subnet"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "name"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "created_at"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "crn"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "href"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "vpc.#"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "zone"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "primary_ip.#"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "ips.#"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "id"), + resource.TestCheckResourceAttr("ibm_is_virtual_network_interface.testacc_vni", "enable_infrastructure_nat", "true"), + resource.TestCheckResourceAttr("ibm_is_virtual_network_interface.testacc_vni", "lifecycle_state", "stable"), + resource.TestCheckResourceAttr("ibm_is_virtual_network_interface.testacc_vni", "resource_type", "virtual_network_interface"), + resource.TestCheckResourceAttr("ibm_is_virtual_network_interface.testacc_vni", "resource_group", acc.IsResourceGroupID), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "resource_group"), + resource.TestCheckResourceAttr("ibm_is_virtual_network_interface.testacc_vni", "allow_ip_spoofing", "true"), + ), + }, + }, + }) +} + +func TestAccIBMIsVirtualNetworkInterfaceAllArgs(t *testing.T) { + var conf vpcv1.VirtualNetworkInterface + vpcname := fmt.Sprintf("tfvpngw-vpc-%d", acctest.RandIntRange(10, 100)) + sgname1 := fmt.Sprintf("tfvpngw-sg-%d", acctest.RandIntRange(10, 100)) + sgname2 := fmt.Sprintf("tfvpngw-sg-%d", acctest.RandIntRange(10, 100)) + reservedipname := fmt.Sprintf("tfvpngw-ip-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfvpngw-subnet-%d", acctest.RandIntRange(10, 100)) + vniname := fmt.Sprintf("tfvpngw-createname-%d", acctest.RandIntRange(10, 100)) + enable_infrastructure_nat := true + allow_ip_spoofing := true + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIsVirtualNetworkInterfaceDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsVirtualNetworkInterfaceConfig(vpcname, subnetname, vniname, enable_infrastructure_nat, allow_ip_spoofing), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIsVirtualNetworkInterfaceExists("ibm_is_virtual_network_interface.testacc_vni", conf), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "subnet"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "name"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "created_at"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "crn"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "href"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "vpc.#"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "zone"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "primary_ip.#"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "ips.#"), + resource.TestCheckResourceAttr("ibm_is_virtual_network_interface.testacc_vni", "ips.#", "1"), + resource.TestCheckResourceAttr("ibm_is_virtual_network_interface.testacc_vni", "security_groups.#", "1"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "id"), + resource.TestCheckResourceAttr("ibm_is_virtual_network_interface.testacc_vni", "enable_infrastructure_nat", "true"), + resource.TestCheckResourceAttr("ibm_is_virtual_network_interface.testacc_vni", "lifecycle_state", "stable"), + resource.TestCheckResourceAttr("ibm_is_virtual_network_interface.testacc_vni", "resource_type", "virtual_network_interface"), + resource.TestCheckResourceAttrSet("ibm_is_virtual_network_interface.testacc_vni", "resource_group"), + resource.TestCheckResourceAttr("ibm_is_virtual_network_interface.testacc_vni", "allow_ip_spoofing", "true"), + ), + }, + resource.TestStep{ + Config: testAccCheckIBMIsVirtualNetworkInterfaceConfigUpdate(vpcname, subnetname, vniname, sgname1, sgname2, reservedipname, enable_infrastructure_nat, allow_ip_spoofing), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_is_virtual_network_interface.testacc_vni", "ips.#", "2"), + resource.TestCheckResourceAttr("ibm_is_virtual_network_interface.testacc_vni", "security_groups.#", "2"), + ), + }, + // resource.TestStep{ + // ResourceName: "ibm_is_virtual_network_interface.testacc_vni", + // ImportState: true, + // ImportStateVerify: true, + // }, + }, + }) +} + +func testAccCheckIBMIsVirtualNetworkInterfaceConfigBasic(vpcname, subnetname, vniname, tag1, tag2, tag3 string, enablenat, allowipspoofing, isUpdate bool) 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_virtual_network_interface" "testacc_vni"{ + name = "%s" + subnet = ibm_is_subnet.testacc_subnet.id + enable_infrastructure_nat = %t + allow_ip_spoofing = %t + tags = %t ? ["%s", "%s"] : ["%s", "%s", "%s"] + } + `, vpcname, subnetname, acc.ISZoneName, vniname, enablenat, allowipspoofing, isUpdate, tag1, tag2, tag1, tag2, tag3) +} + +func testAccCheckIBMIsVirtualNetworkInterfaceConfigResourceGroup(vpcname, subnetname, vniname string, enablenat, allowipspoofing bool) 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_virtual_network_interface" "testacc_vni"{ + name = "%s" + subnet = ibm_is_subnet.testacc_subnet.id + enable_infrastructure_nat = %t + allow_ip_spoofing = %t + resource_group = "%s" + } + `, vpcname, subnetname, acc.ISZoneName, vniname, enablenat, allowipspoofing, acc.IsResourceGroupID) +} + +func testAccCheckIBMIsVirtualNetworkInterfaceConfig(vpcname, subnetname, vniname string, enablenat, allowipspoofing bool) 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_virtual_network_interface" "testacc_vni" { + name = "%s" + subnet = ibm_is_subnet.testacc_subnet.id + enable_infrastructure_nat = %t + allow_ip_spoofing = %t + ips { + address = "10.240.0.7" + } + primary_ip { + address = "10.240.0.9" + } + } + `, vpcname, subnetname, acc.ISZoneName, vniname, enablenat, allowipspoofing) +} +func testAccCheckIBMIsVirtualNetworkInterfaceConfigUpdate(vpcname, subnetname, vniname, sgname1, sgname2, reservedipname string, enablenat, allowipspoofing bool) 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_security_group" "testacc_security_group1" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + } + resource "ibm_is_security_group" "testacc_security_group2" { + name = "%s" + vpc =ibm_is_vpc.testacc_vpc.id + } + resource "ibm_is_subnet_reserved_ip" "testacc_reservedips" { + subnet = ibm_is_subnet.testacc_subnet.id + name = "%s" + } + resource "ibm_is_virtual_network_interface" "testacc_vni" { + name = "%s" + subnet = ibm_is_subnet.testacc_subnet.id + enable_infrastructure_nat = %t + allow_ip_spoofing = %t + ips { + address = "10.240.0.7" + } + ips { + reserved_ip = ibm_is_subnet_reserved_ip.testacc_reservedips.reserved_ip + } + primary_ip { + address = "10.240.0.9" + } + security_groups = [ibm_is_security_group.testacc_security_group2.id, ibm_is_security_group.testacc_security_group1.id] + } + `, vpcname, subnetname, acc.ISZoneName, sgname1, sgname2, reservedipname, vniname, enablenat, allowipspoofing) +} + +func testAccCheckIBMIsVirtualNetworkInterfaceExists(n string, obj vpcv1.VirtualNetworkInterface) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + sess, err := vpcClient(acc.TestAccProvider.Meta()) + if err != nil { + return err + } + + getVirtualNetworkInterfaceOptions := &vpcv1.GetVirtualNetworkInterfaceOptions{} + + getVirtualNetworkInterfaceOptions.SetID(rs.Primary.ID) + + virtualNetworkInterface, _, err := sess.GetVirtualNetworkInterface(getVirtualNetworkInterfaceOptions) + if err != nil { + return err + } + + obj = *virtualNetworkInterface + return nil + } +} + +func testAccCheckIBMIsVirtualNetworkInterfaceDestroy(s *terraform.State) error { + sess, err := vpcClient(acc.TestAccProvider.Meta()) + if err != nil { + return err + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_virtual_network_interface" { + continue + } + + getVirtualNetworkInterfaceOptions := &vpcv1.GetVirtualNetworkInterfaceOptions{} + + getVirtualNetworkInterfaceOptions.SetID(rs.Primary.ID) + + // Try to find the key + _, response, err := sess.GetVirtualNetworkInterface(getVirtualNetworkInterfaceOptions) + + if err == nil { + return fmt.Errorf("VirtualNetworkInterface still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for VirtualNetworkInterface (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/vpc/resource_ibm_is_vpc_routing_table_route.go b/ibm/service/vpc/resource_ibm_is_vpc_routing_table_route.go index 2862c247f6..dd5c23d053 100644 --- a/ibm/service/vpc/resource_ibm_is_vpc_routing_table_route.go +++ b/ibm/service/vpc/resource_ibm_is_vpc_routing_table_route.go @@ -343,20 +343,11 @@ func resourceIBMISVPCRoutingTableRouteUpdate(d *schema.ResourceData, meta interf // Construct an instance of the RoutePatch model routePatchModel := new(vpcv1.RoutePatch) - if d.HasChange(rName) || d.HasChange("advertise") { - // Construct an instance of the RoutePatch model - routePatchModel := new(vpcv1.RoutePatch) - if d.HasChange(rName) { - name := d.Get(rName).(string) - routePatchModel.Name = &name - hasChange = true - } + if d.HasChange("advertise") { + advertiseVal := d.Get("advertise").(bool) + routePatchModel.Advertise = &advertiseVal + hasChange = true - if d.HasChange("advertise") { - advertiseVal := d.Get("advertise").(bool) - routePatchModel.Advertise = &advertiseVal - hasChange = true - } } if d.HasChange(rName) { name := d.Get(rName).(string) diff --git a/metadata/provider_metadata.json b/metadata/provider_metadata.json index 35b141da83..ce535fcbe0 100644 --- a/metadata/provider_metadata.json +++ b/metadata/provider_metadata.json @@ -19792,6 +19792,11 @@ "type": "TypeString", "computed": true }, + { + "name": "vpe_service_endpoint_url", + "type": "TypeString", + "computed": true + }, { "name": "tags", "type": "TypeSet", @@ -94360,7 +94365,8 @@ "name": "min_tls_version", "type": "TypeString", "description": "Minimum version of TLS required", - "optional": true + "optional": true, + "default_value": "1.2" }, { "name": "ipv6", @@ -96013,7 +96019,8 @@ "type": "TypeString", "description": "Minimum version of TLS required", "options": "1.1, 1.2, 1.3, 1.4", - "optional": true + "optional": true, + "default_value": "1.2" } ], "ibm_cis_waf_group": [ @@ -107563,6 +107570,11 @@ "type": "TypeString", "computed": true }, + { + "name": "vpe_service_endpoint_url", + "type": "TypeString", + "computed": true + }, { "name": "disable_public_service_endpoint", "type": "TypeBool", diff --git a/version/version.go b/version/version.go index 69b40ff553..a65eb79ffd 100644 --- a/version/version.go +++ b/version/version.go @@ -5,7 +5,7 @@ import ( ) // Version is the current provider main version -const Version = "1.62.0-beta0" +const Version = "1.63.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/docs/d/cbr_rule.html.markdown b/website/docs/d/cbr_rule.html.markdown index 07925ccca9..cf89cc6106 100644 --- a/website/docs/d/cbr_rule.html.markdown +++ b/website/docs/d/cbr_rule.html.markdown @@ -31,7 +31,7 @@ In addition to all argument references listed, you can access the following attr * `id` - The unique identifier of the cbr_rule. * `contexts` - (List) The contexts this rule applies to. - * Constraints: The maximum length is `1000` items. The minimum length is `1` item. + * Constraints: The maximum length is `1000` items. The minimum length is `0` items. Nested scheme for **contexts**: * `attributes` - (List) The attributes. * Constraints: The minimum length is `1` item. diff --git a/website/docs/d/cbr_zone.html.markdown b/website/docs/d/cbr_zone.html.markdown index e91a07c493..a0f495a59a 100644 --- a/website/docs/d/cbr_zone.html.markdown +++ b/website/docs/d/cbr_zone.html.markdown @@ -36,7 +36,7 @@ In addition to all argument references listed, you can access the following attr * `address_count` - (Integer) The number of addresses in the zone. * `addresses` - (List) The list of addresses in the zone. - * Constraints: The maximum length is `1000` items. The minimum length is `1` item. + * Constraints: The maximum length is `1000` items. The minimum length is `0` items. Nested scheme for **addresses**: * `ref` - (List) A service reference value. Nested scheme for **ref**: diff --git a/website/docs/d/container_vpc_cluster.html.markdown b/website/docs/d/container_vpc_cluster.html.markdown index 8408a34c0c..4cc27d261d 100644 --- a/website/docs/d/container_vpc_cluster.html.markdown +++ b/website/docs/d/container_vpc_cluster.html.markdown @@ -56,6 +56,7 @@ In addition to all argument reference list, you can access the following attribu - `public_service_endpoint_url` - (String) The URL of the public service endpoint for your cluster. - `private_service_endpoint` - (Bool) Indicates if the private service endpoint is enabled (**true**) or disabled (**false**) for a cluster. - `private_service_endpoint_url` - (String) The URL of the private service endpoint for your cluster. +- `vpe_service_endpoint_url` - (String) The URL of the virtual private endpoint for your cluster. - `status` - (String) The status of the cluster master. - `worker_count` - (Integer) The number of worker nodes per zone in the default worker pool. Default value ‘1’. - `workers` - List of objects - A list of worker nodes that belong to the cluster. diff --git a/website/docs/d/en_destination_android.html.markdown b/website/docs/d/en_destination_android.html.markdown index 51163511ce..ed8617b771 100644 --- a/website/docs/d/en_destination_android.html.markdown +++ b/website/docs/d/en_destination_android.html.markdown @@ -43,6 +43,8 @@ In addition to all argument references listed, you can access the following attr - `type` - (String) Destination type push_android. +- `collect_failed_events` - (boolean) Toggle switch to enable collect failed event in Cloud Object Storage bucket. + - `config` - (List) Payload describing a destination configuration. Nested scheme for **config**: diff --git a/website/docs/d/en_destination_ce.html.markdown b/website/docs/d/en_destination_ce.html.markdown index bb41f24d23..e3175021bd 100644 --- a/website/docs/d/en_destination_ce.html.markdown +++ b/website/docs/d/en_destination_ce.html.markdown @@ -43,6 +43,8 @@ In addition to all argument references listed, you can access the following attr - `type` - (String) Destination type ibmce. +- `collect_failed_events` - (boolean) Toggle switch to enable collect failed event in Cloud Object Storage bucket. + - `config` - (List) Payload describing a destination configuration. Nested scheme for **config**: diff --git a/website/docs/d/en_destination_cf.html.markdown b/website/docs/d/en_destination_cf.html.markdown index cd8605864b..f139ed06d5 100644 --- a/website/docs/d/en_destination_cf.html.markdown +++ b/website/docs/d/en_destination_cf.html.markdown @@ -43,6 +43,8 @@ In addition to all argument references listed, you can access the following attr - `type` - (String) Destination type ibmcf. +- `collect_failed_events` - (boolean) Toggle switch to enable collect failed event in Cloud Object Storage bucket. + - `config` - (List) Payload describing a destination configuration. Nested scheme for **config**: diff --git a/website/docs/d/en_destination_chrome.html.markdown b/website/docs/d/en_destination_chrome.html.markdown index f332470f6f..09175ea823 100644 --- a/website/docs/d/en_destination_chrome.html.markdown +++ b/website/docs/d/en_destination_chrome.html.markdown @@ -43,6 +43,8 @@ In addition to all argument references listed, you can access the following attr - `type` - (String) Destination type push_chrome. +- `collect_failed_events` - (boolean) Toggle switch to enable collect failed event in Cloud Object Storage bucket. + - `config` - (List) Payload describing a destination configuration. Nested scheme for **config**: diff --git a/website/docs/d/en_destination_cos.html.markdown b/website/docs/d/en_destination_cos.html.markdown index 36974b7e75..695f12e7bc 100644 --- a/website/docs/d/en_destination_cos.html.markdown +++ b/website/docs/d/en_destination_cos.html.markdown @@ -43,6 +43,8 @@ In addition to all argument references listed, you can access the following attr - `type` - (String) Destination type ibmcos. +- `collect_failed_events` - (boolean) Toggle switch to enable collect failed event in Cloud Object Storage bucket. + - `config` - (List) Payload describing a destination configuration. Nested scheme for **config**: diff --git a/website/docs/d/en_destination_custom_email.html.markdown b/website/docs/d/en_destination_custom_email.html.markdown index 355ff086ea..89c589a4ba 100644 --- a/website/docs/d/en_destination_custom_email.html.markdown +++ b/website/docs/d/en_destination_custom_email.html.markdown @@ -43,6 +43,8 @@ In addition to all argument references listed, you can access the following attr - `type` - (String) Destination type smtp_custom. +- `collect_failed_events` - (boolean) Toggle switch to enable collect failed event in Cloud Object Storage bucket. + - `config` - (List) Payload describing a destination configuration. Nested scheme for **config**: diff --git a/website/docs/d/en_destination_custom_sms.html.markdown b/website/docs/d/en_destination_custom_sms.html.markdown new file mode 100644 index 0000000000..c54da30cc5 --- /dev/null +++ b/website/docs/d/en_destination_custom_sms.html.markdown @@ -0,0 +1,57 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_destination_custom_sms' +description: |- + Get information about a Custom SMS destination +--- + +# ibm_en_destination_custom_sms + +Provides a read-only data source for Custom SMS destination. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example usage + +```terraform +data "ibm_en_destination_custom_sms" "custom_sms_en_destination" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + destination_id = ibm_en_destination_custom_sms.destination1.destination_id +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `destination_id` - (Required, String) Unique identifier for Destination. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the `custom_sms_en_destination`. + +- `name` - (String) Destination name. + +- `description` - (String) Destination description. + +- `subscription_count` - (Integer) Number of subscriptions. + +- `subscription_names` - (List) List of subscriptions. + +- `type` - (String) Destination type smtp_custom. + +- `collect_failed_events` - (boolean) Toggle switch to enable collect failed event in Cloud Object Storage bucket. + +- `config` - (List) Payload describing a destination configuration. + Nested scheme for **config**: + + - `params` - (List) + + Nested scheme for **params**: + + - `domain` - (String) The Custom Domain. + +- `updated_at` - (String) Last updated time. diff --git a/website/docs/d/en_destination_firefox.html.markdown b/website/docs/d/en_destination_firefox.html.markdown index ec4255cb98..4aacf93e6c 100644 --- a/website/docs/d/en_destination_firefox.html.markdown +++ b/website/docs/d/en_destination_firefox.html.markdown @@ -43,6 +43,8 @@ In addition to all argument references listed, you can access the following attr - `type` - (String) Destination type push_firefox. +- `collect_failed_events` - (boolean) Toggle switch to enable collect failed event in Cloud Object Storage bucket. + - `config` - (List) Payload describing a destination configuration. Nested scheme for **config**: diff --git a/website/docs/d/en_destination_huawei.html copy.markdown b/website/docs/d/en_destination_huawei.html copy.markdown index 1b474e6812..d0f0f0ba7e 100644 --- a/website/docs/d/en_destination_huawei.html copy.markdown +++ b/website/docs/d/en_destination_huawei.html copy.markdown @@ -43,6 +43,8 @@ In addition to all argument references listed, you can access the following attr - `type` - (String) Destination type push_huawei. +- `collect_failed_events` - (boolean) Toggle switch to enable collect failed event in Cloud Object Storage bucket. + - `config` - (List) Payload describing a destination configuration. Nested scheme for **config**: diff --git a/website/docs/d/en_destination_ios.html.markdown b/website/docs/d/en_destination_ios.html.markdown index 03f73c52fa..3dd470ad53 100644 --- a/website/docs/d/en_destination_ios.html.markdown +++ b/website/docs/d/en_destination_ios.html.markdown @@ -43,6 +43,8 @@ In addition to all argument references listed, you can access the following attr - `type` - (String) Destination type push_ios. +- `collect_failed_events` - (boolean) Toggle switch to enable collect failed event in Cloud Object Storage bucket. + - `certificate_content_type` - (String) The type of certificate, Values are p8/p12. - `certificate` - (binary) Certificate file. The file type allowed is .p8 and .p12 diff --git a/website/docs/d/en_destination_msteams.html.markdown b/website/docs/d/en_destination_msteams.html.markdown index 2fd44df828..6c9dbca0fa 100644 --- a/website/docs/d/en_destination_msteams.html.markdown +++ b/website/docs/d/en_destination_msteams.html.markdown @@ -43,6 +43,8 @@ In addition to all argument references listed, you can access the following attr - `type` - (String) Destination type msteams. +- `collect_failed_events` - (boolean) Toggle switch to enable collect failed event in Cloud Object Storage bucket. + - `config` - (List) Payload describing a destination configuration. Nested scheme for **config**: diff --git a/website/docs/d/en_destination_pagerduty.html.markdown b/website/docs/d/en_destination_pagerduty.html.markdown index 777d64cf7d..689990b2f0 100644 --- a/website/docs/d/en_destination_pagerduty.html.markdown +++ b/website/docs/d/en_destination_pagerduty.html.markdown @@ -43,6 +43,8 @@ In addition to all argument references listed, you can access the following attr - `type` - (String) Destination type pagerduty. +- `collect_failed_events` - (boolean) Toggle switch to enable collect failed event in Cloud Object Storage bucket. + - `config` - (List) Payload describing a destination configuration. Nested scheme for **config**: diff --git a/website/docs/d/en_destination_safari.html.markdown b/website/docs/d/en_destination_safari.html.markdown index 3102882dbd..70b4a70ef1 100644 --- a/website/docs/d/en_destination_safari.html.markdown +++ b/website/docs/d/en_destination_safari.html.markdown @@ -43,6 +43,8 @@ In addition to all argument references listed, you can access the following attr - `type` - (String) Destination type push_safari. +- `collect_failed_events` - (boolean) Toggle switch to enable collect failed event in Cloud Object Storage bucket. + - `config` - (List) Payload describing a destination configuration. Nested scheme for **config**: diff --git a/website/docs/d/en_destination_slack.html.markdown b/website/docs/d/en_destination_slack.html.markdown index bc3554c658..44c4e4eede 100644 --- a/website/docs/d/en_destination_slack.html.markdown +++ b/website/docs/d/en_destination_slack.html.markdown @@ -43,6 +43,8 @@ In addition to all argument references listed, you can access the following attr - `type` - (String) Destination type slack. +- `collect_failed_events` - (boolean) Toggle switch to enable collect failed event in Cloud Object Storage bucket. + - `config` - (List) Payload describing a destination configuration. Nested scheme for **config**: diff --git a/website/docs/d/en_destination_sn.html.markdown b/website/docs/d/en_destination_sn.html.markdown index b1f5628949..c7776ca8d6 100644 --- a/website/docs/d/en_destination_sn.html.markdown +++ b/website/docs/d/en_destination_sn.html.markdown @@ -43,6 +43,8 @@ In addition to all argument references listed, you can access the following attr - `type` - (String) Destination type servicenow. +- `collect_failed_events` - (boolean) Toggle switch to enable collect failed event in Cloud Object Storage bucket. + - `config` - (List) Payload describing a destination configuration. Nested scheme for **config**: diff --git a/website/docs/d/en_destination_webhook.html.markdown b/website/docs/d/en_destination_webhook.html.markdown index d04a8fe431..3f4e7a05d0 100644 --- a/website/docs/d/en_destination_webhook.html.markdown +++ b/website/docs/d/en_destination_webhook.html.markdown @@ -43,6 +43,8 @@ In addition to all argument references listed, you can access the following attr - `type` - (String) Destination type Webhook. +- `collect_failed_events` - (boolean) Toggle switch to enable collect failed event in Cloud Object Storage bucket. + - `config` - (List) Payload describing a destination configuration. Nested scheme for **config**: diff --git a/website/docs/d/en_destinations.html.markdown b/website/docs/d/en_destinations.html.markdown index 4edb067056..00929f7cbc 100644 --- a/website/docs/d/en_destinations.html.markdown +++ b/website/docs/d/en_destinations.html.markdown @@ -46,6 +46,8 @@ In addition to all argument references listed, you can access the following attr - `type` - (String) Destination type Email/SMS/Webhook. + - `collect_failed_events` - (boolean) Toggle switch to enable collect failed event in Cloud Object Storage bucket. + - `updated_at` - (String) Lats updated time. - `total_count` - (Integer) Total number of destinations. diff --git a/website/docs/d/en_email_template.html.markdown b/website/docs/d/en_email_template.html.markdown new file mode 100644 index 0000000000..b4c27f15b3 --- /dev/null +++ b/website/docs/d/en_email_template.html.markdown @@ -0,0 +1,46 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_email_template' +description: |- + Get information about a Email Template +--- + +# ibm_en_email_template + +Provides a read-only data source for Email template. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example usage + +```terraform +data "ibm_en_email_template" "email_template" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + template_id = ibm_en_email_template.en_email_template.template_id +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `template_id` - (Required, String) Unique identifier for Template. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the `email_template`. + +- `name` - (String) The Template name. + +- `description` - (String) The template description. + +- `subscription_count` - (Integer) Number of subscriptions. + +- `subscription_names` - (List) List of subscriptions. + +- `type` - (String) Template type smtp_custom.notification/smtp_custom.invitation. + +- `updated_at` - (String) Last updated time. diff --git a/website/docs/d/en_email_templates.html.markdown b/website/docs/d/en_email_templates.html.markdown new file mode 100644 index 0000000000..e9994196fd --- /dev/null +++ b/website/docs/d/en_email_templates.html.markdown @@ -0,0 +1,51 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_email_templates' +description: |- + List all the Email Templates +--- + +# ibm_en_email_templates + +Provides a read-only data source for templates. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example usage + +```terraform +data "ibm_en_email_templates" "email_templates" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `search_key` - (Optional, String) Filter the template by name or type. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the `en_email_templates`. + +- `templates` - (List) List of templates. + + - `id` - The unique identifier of the `email_templates`. + + - `name` - (String) The Template name. + + - `description` - (String) The template description. + + - `subscription_count` - (Integer) Number of subscriptions. + + - `subscription_names` - (List) List of subscriptions. + + - `type` - (String) Template type smtp_custom.notification/smtp_custom.invitation. + + - `updated_at` - (String) Last updated time. + +- `total_count` - (Integer) Total number of destinations. diff --git a/website/docs/d/en_integration.html.markdown b/website/docs/d/en_integration.html.markdown index 7a9cfac00c..cfe03d8d28 100644 --- a/website/docs/d/en_integration.html.markdown +++ b/website/docs/d/en_integration.html.markdown @@ -3,25 +3,19 @@ subcategory: 'Event Notifications' layout: 'ibm' page_title: 'IBM : ibm_en_integration' description: |- - Manages Event Notifications Integrations. + Get information about kms integration. --- # ibm_en_integration -update integration using IBM Cloudâ„¢ Event Notifications. +Provides a read-only data source for kms/hs-crypto Integration. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. ## Example usage ```terraform resource "ibm_en_integration" "en_kms_integration" { instance_guid = ibm_resource_instance.en_terraform_test_resource.guid - integration_id = "xyz-rdserr-froyth-lowhbw" - type = "kms" - metadata { - endpoint = "https://us-south.kms.cloud.ibm.com" - crn = "crn:v1:bluemix:public:kms:us-south:a/tyyeeuuii2637390003hehhhhi:fgsyysbnjiios::" - root_key_id = "gyyebvhy-34673783-nshuwubw" - } + integration_id = ibm_en_integration.kms_integration.integration_id } ``` @@ -46,27 +40,7 @@ Review the argument reference that you can specify for your resource. ## Attribute reference -In addition to all argument references listed, you can access the following attribute references after your resource is created. +In addition to all argument references listed, you can access the following attribute references after your data source is created. -- `id` - (String) The unique identifier of the `en_integration`. -- `updated_at` - (String) Last updated time. - -## Import - -You can import the `ibm_en_integration` resource by using `id`. - -The `id` property can be formed from `instance_guid`, and `integration_id` in the following format: - -``` -/ -``` - -- `instance_guid`: A string. Unique identifier for IBM Cloud Event Notifications instance. - -- `integration_id`: A string. Unique identifier for Destination. - -**Example** - -``` -$ terraform import ibm_en_integration.en_integration / -``` +- `id` - (String) The unique identifier of the `en_kms_integration`. +- `updated_at` - (String) Last updated time. \ No newline at end of file diff --git a/website/docs/d/en_integration_cos.html.markdown b/website/docs/d/en_integration_cos.html.markdown new file mode 100644 index 0000000000..4f7fe73712 --- /dev/null +++ b/website/docs/d/en_integration_cos.html.markdown @@ -0,0 +1,46 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_integration_cos' +description: |- + Get information about COS integration. +--- + +# ibm_en_integration_cos + +Provides a read-only data source for COS Integration. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example usage + +```terraform +resource "ibm_en_integration_cos" "cos_integration" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + integration_id = ibm_en_integration_cos.cos_integration.integration_id +} +``` + +## Argument reference + +Review the argument reference that you can specify for your resource. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `integration_id` - (Required, String) Unique identifier for Integration created with . + +- `type` - (Required, String) The integration type collect_failed_events. + +- `metadata` - (Required, List) + + Nested scheme for **params**: + + - `endpoint` - (Required, String) endpoint url for COS bucket region. + - `crn` - (Required, String) CRN of the COS instance. + - `bucket_name` - (Required, String) cloud object storage bucket name. + + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - (String) The unique identifier of the `cos_integration`. +- `updated_at` - (String) Last updated time. \ No newline at end of file diff --git a/website/docs/d/en_subscription_custom_sms.html.markdown b/website/docs/d/en_subscription_custom_sms.html.markdown new file mode 100644 index 0000000000..4e8770a63b --- /dev/null +++ b/website/docs/d/en_subscription_custom_sms.html.markdown @@ -0,0 +1,52 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_subscription_custom_sms' +description: |- + Get information about a custom sms subscription +--- + +# ibm_en_subscription_custom_sms + +Provides a read-only data source for Custom SMS subscription. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + +## Example usage + +```terraform +data "ibm_en_subscription_custom_sms" "custom_sms_subscription" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + subscription_id = ibm_en_subscription_custom_sms.subscription_custom_sms.subscription_id +} +``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `subscription_id` - (Required, String) Unique identifier for Subscription. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +- `id` - The unique identifier of the custom_sms_subscription. + +- `name` - (String) Subscription name. + +- `description` - (String) Subscription description. + +- `destination_id` - (String) The destination ID. + +- `topic_id` - (String) Topic ID. + +- `additional_properties` - (Required, List) + + - `susbscribed`- (Map) The phone number who have subscribed for topic. + + - `unsubscribed`- (List) The phone number which has opted for unsusbscribtion from that topic. + + - `invited`- (List) The phone number for invitation. + +- `updated_at` - (String) Last updated time. diff --git a/website/docs/d/is_bare_metal_server.markdown b/website/docs/d/is_bare_metal_server.markdown index 8bcabd6fab..046bd65620 100644 --- a/website/docs/d/is_bare_metal_server.markdown +++ b/website/docs/d/is_bare_metal_server.markdown @@ -76,6 +76,35 @@ In addition to all argument reference list, you can access the following attribu - `keys` - (String) Image used in the bare metal server. - `memory` - (Integer) The amount of memory, truncated to whole gibibytes - `name` - (String) The name of the bare metal server. +- `network_attachments` - (List) The network attachments for this bare metal server, including the primary network attachment. + Nested schema for **network_attachments**: + - `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 network attachment. + - `id` - (String) The unique identifier for this network attachment. + - `name` - (String) + - `primary_ip` - (List) The primary IP address of the virtual network interface for the network attachment. + Nested schema for **primary_ip**: + - `address` - (String) The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `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 reserved IP. + - `id` - (String) The unique identifier for this reserved IP. + - `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. + - `resource_type` - (String) The resource type. + - `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. + Nested schema for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this subnet. + - `id` - (String) The unique identifier for this subnet. + - `name` - (String) The name for this subnet. The name is unique across all subnets in the VPC. + - `resource_type` - (String) The resource type. - `network_interfaces` - (List) A nested block describing the additional network interface of this instance. Nested scheme for `network_interfaces`: - `allow_ip_spoofing` - (Bool) Indicates whether source IP spoofing is allowed on this interface. If false, source IP spoofing is prevented on this interface. If true, source IP spoofing is allowed on this interface. @@ -93,6 +122,35 @@ In addition to all argument reference list, you can access the following attribu - `security_groups` - (Array) List of security groups. - `subnet` - (String) ID of the subnet. +- `primary_network_attachment` - (List) The primary network attachment. + Nested schema for **primary_network_attachment**: + - `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 network attachment. + - `id` - (String) The unique identifier for this network attachment. + - `name` - (String) + - `primary_ip` - (List) The primary IP address of the virtual network interface for the network attachment. + Nested schema for **primary_ip**: + - `address` - (String) The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `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 reserved IP. + - `id` - (String) The unique identifier for this reserved IP. + - `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. + - `resource_type` - (String) The resource type. + - `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. + Nested schema for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this subnet. + - `id` - (String) The unique identifier for this subnet. + - `name` - (String) The name for this subnet. The name is unique across all subnets in the VPC. + - `resource_type` - (String) The resource type. - `primary_network_interface` - (List) A nested block describing the primary network interface of this bare metal server. Nested scheme for `primary_network_interface`: - `allow_ip_spoofing` - (Bool) Indicates whether source IP spoofing is allowed on this interface. If false, source IP spoofing is prevented on this interface. If true, source IP spoofing is allowed on this interface. diff --git a/website/docs/d/is_bare_metal_server_network_attachment.html.markdown b/website/docs/d/is_bare_metal_server_network_attachment.html.markdown new file mode 100644 index 0000000000..dd5895eba4 --- /dev/null +++ b/website/docs/d/is_bare_metal_server_network_attachment.html.markdown @@ -0,0 +1,87 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_bare_metal_server_network_attachment" +description: |- + Get information about is_bare_metal_server_network_attachment +subcategory: "Virtual Private Cloud API" +--- + +# ibm_is_bare_metal_server_network_attachment + +Provides a read-only data source to retrieve information about an is_bare_metal_server_network_attachment. You can then reference the fields of the data source in other resources within the same configuration by using interpolation syntax. + +## Example Usage + +```terraform +data "ibm_is_bare_metal_server_network_attachment" "example" { + bare_metal_server = ibm_is_bare_metal_server_network_attachment.example.bare_metal_server + network_attachment = ibm_is_bare_metal_server_network_attachment.example.network_attachment +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +- `bare_metal_server` - (Required, Forces new resource, String) The bare metal server identifier. +- `network_attachment` - (Required, Forces new resource, String) The bare metal server 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 is_bare_metal_server_network_attachment. +- `allow_to_float` - (Boolean) Indicates if the bare metal server network attachment can automatically float to any other server within the same `resource_group`. The bare metal server network attachment will float automatically if the network detects a GARP or RARP on another bare metal server in the resource group. Applies only to bare metal server network attachments with `vlan` interface type. + +- `allowed_vlans` - (List) + +- `bare_metal_server_network_attachment_id` - (String) The unique identifier for this bare metal server network attachment. + +- `created_at` - (String) The date and time that the bare metal server network attachment was created. + +- `href` - (String) The URL for this bare metal server network attachment. + +- `interface_type` - (String) The network attachment's interface type:- ``pci`: a physical PCI device which can only be created or deleted when the bare metal server is stopped - Has an `allowed_vlans` property which controls the VLANs that will be permitted to use the PCI attachment - Cannot directly use an IEEE 802.1q VLAN tag.- `vlan`: a virtual device, used through a `pci` device that has the `vlan` in its array of `allowed_vlans`. - Must use an IEEE 802.1q tag.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered. + +- `lifecycle_state` - (String) The lifecycle state of the bare metal server network attachment. + +- `name` - (String) The name for this bare metal server network attachment. The name is unique across all network attachments for the bare metal server. + +- `port_speed` - (Integer) The port speed for this bare metal server network attachment in Mbps. + +- `primary_ip` - (List) The primary IP address of the virtual network interface for the bare metal servernetwork attachment. + Nested schema for **primary_ip**: + - `address` - (String) The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `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 reserved IP. + - `id` - (String) The unique identifier for this reserved IP. + - `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. + +- `resource_type` - (String) The resource type. + +- `subnet` - (List) The subnet of the virtual network interface for the bare metal server networkattachment. + 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. + Nested schema for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this subnet. + - `id` - (String) The unique identifier for this subnet. + - `name` - (String) The name for this subnet. The name is unique across all subnets in the VPC. + - `resource_type` - (String) The resource type. + +- `type` - (String) The bare metal server network attachment type. + +- `virtual_network_interface` - (List) The virtual network interface for this bare metal server network attachment. + Nested schema for **virtual_network_interface**: + - `crn` - (String) The CRN for this virtual network interface. + - `href` - (String) The URL for this virtual network interface. + - `id` - (String) The unique identifier for this virtual network interface. + - `name` - (String) The name for this virtual network interface. The name is unique across all virtual network interfaces in the VPC. + - `resource_type` - (String) The resource type. + +- `vlan` - (Integer) Indicates the 802.1Q VLAN ID tag that must be used for all traffic on this attachment. + diff --git a/website/docs/d/is_bare_metal_server_network_attachments.html.markdown b/website/docs/d/is_bare_metal_server_network_attachments.html.markdown new file mode 100644 index 0000000000..a65f93b1da --- /dev/null +++ b/website/docs/d/is_bare_metal_server_network_attachments.html.markdown @@ -0,0 +1,72 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_bare_metal_server_network_attachments" +description: |- + Get information about BareMetalServerNetworkAttachmentCollection +subcategory: "Virtual Private Cloud API" +--- + +# ibm_is_bare_metal_server_network_attachments + +Provides a read-only data source to retrieve information about a BareMetalServerNetworkAttachmentCollection. You can then reference the fields of the data source in other resources within the same configuration by using interpolation syntax. + +## Example Usage + +```terraform +data "ibm_is_bare_metal_server_network_attachments" "example" { + bare_metal_server = ibm_is_bare_metal_server_network_attachment.example.bare_metal_server +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +- `bare_metal_server` - (Required, Forces new resource, String) The bare metal server identifier. + +## Attribute Reference + +After your data source is created, you can read values from the following attributes. + +- `id` - The unique identifier of the BareMetalServerNetworkAttachmentCollection. +- `network_attachments` - (List) Collection of bare metal server network attachments. + Nested schema for **network_attachments**: + - `allow_to_float` - (Boolean) Indicates if the bare metal server network attachment can automatically float to any other server within the same `resource_group`. The bare metal server network attachment will float automatically if the network detects a GARP or RARP on another bare metal server in the resource group. Applies only to bare metal server network attachments with `vlan` interface type. + - `allowed_vlans` - (List) + - `created_at` - (String) The date and time that the bare metal server network attachment was created. + - `href` - (String) The URL for this bare metal server network attachment. + - `id` - (String) The unique identifier for this bare metal server network attachment. + - `interface_type` - (String) The network attachment's interface type:- `pci`: a physical PCI device which can only be created or deleted when the bare metal server is stopped - Has an `allowed_vlans` property which controls the VLANs that will be permitted to use the PCI attachment - Cannot directly use an IEEE 802.1q VLAN tag.- `vlan`: a virtual device, used through a `pci` device that has the `vlan` in its array of `allowed_vlans`. - Must use an IEEE 802.1q tag.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered. + - `lifecycle_state` - (String) The lifecycle state of the bare metal server network attachment. + - `name` - (String) The name for this bare metal server network attachment. The name is unique across all network attachments for the bare metal server. + - `port_speed` - (Integer) The port speed for this bare metal server network attachment in Mbps. + - `primary_ip` - (List) The primary IP address of the virtual network interface for the bare metal servernetwork attachment. + Nested schema for **primary_ip**: + - `address` - (String) The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `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 reserved IP. + - `id` - (String) The unique identifier for this reserved IP. + - `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. + - `resource_type` - (String) The resource type. + - `subnet` - (List) The subnet of the virtual network interface for the bare metal server networkattachment. + 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. + Nested schema for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this subnet. + - `id` - (String) The unique identifier for this subnet. + - `name` - (String) The name for this subnet. The name is unique across all subnets in the VPC. + - `resource_type` - (String) The resource type. + - `type` - (String) The bare metal server network attachment type. + - `virtual_network_interface` - (List) The virtual network interface for this bare metal server network attachment. + Nested schema for **virtual_network_interface**: + - `crn` - (String) The CRN for this virtual network interface. + - `href` - (String) The URL for this virtual network interface. + - `id` - (String) The unique identifier for this virtual network interface. + - `name` - (String) The name for this virtual network interface. The name is unique across all virtual network interfaces in the VPC. + - `resource_type` - (String) The resource type. + - `vlan` - (Integer) Indicates the 802.1Q VLAN ID tag that must be used for all traffic on this attachment. \ No newline at end of file diff --git a/website/docs/d/is_bare_metal_server_profile.markdown b/website/docs/d/is_bare_metal_server_profile.markdown index 5ba2e07f68..9709dd8e5b 100644 --- a/website/docs/d/is_bare_metal_server_profile.markdown +++ b/website/docs/d/is_bare_metal_server_profile.markdown @@ -43,8 +43,13 @@ In addition to all argument reference list, you can access the following attribu - `bandwidth` - (List) The total bandwidth (in megabits per second) shared across the network interfaces of a bare metal server with this profile. Nested scheme for `bandwidth`: + - `default` - (Integer) The default value for this profile field. + - `max` - (Integer) The maximum value for this profile field. + - `min` - (Integer) The minimum value for this profile field. + - `step` - (Integer) The increment step value for this profile field. - `type` - (String) The type for this profile field. - `value` - (Integer) The value for this profile field. + - `values` - (List) The permitted values for this profile field. - `console_types` - (List) The console type configuration for a bare metal server with this profile. Nested schema for `console_types`: @@ -94,6 +99,13 @@ In addition to all argument reference list, you can access the following attribu - `type` - (String) The type for this profile field. - `value` - (String) The value for this profile field. - `name` - (String) The name of the profile. +- `network_attachment_count` - (List) + + Nested schema for **network_attachment_count**: + - `max` - (Integer) The maximum value for this profile field. + - `min` - (Integer) The minimum value for this profile field. + - `type` - (String) The type for this profile field. + - `network_interface_count` - (List) Nested schema for **network_interface_count**: @@ -112,3 +124,10 @@ In addition to all argument reference list, you can access the following attribu Nested scheme for `supported_trusted_platform_module_modes`: - `type` - (String) The type for this profile field. - `values` - (Array) The supported trusted platform module (TPM) modes. + +- `virtual_network_interfaces_supported` - (List) Indicates whether this profile supports virtual network interfaces. + + Nested schema for **virtual_network_interfaces_supported**: + - `type` - (String) The type for this profile field. + - `value` - (Boolean) The value for this profile field. + diff --git a/website/docs/d/is_bare_metal_server_profiles.markdown b/website/docs/d/is_bare_metal_server_profiles.markdown index 78f4628e2a..bf719f6e81 100644 --- a/website/docs/d/is_bare_metal_server_profiles.markdown +++ b/website/docs/d/is_bare_metal_server_profiles.markdown @@ -38,8 +38,13 @@ Review the attribute references that you can access after you retrieve your data - `bandwidth` - (List) The total bandwidth (in megabits per second) shared across the network interfaces of a bare metal server with this profile. Nested scheme for `bandwidth`: + - `default` - (Integer) The default value for this profile field. + - `max` - (Integer) The maximum value for this profile field. + - `min` - (Integer) The minimum value for this profile field. + - `step` - (Integer) The increment step value for this profile field. - `type` - (String) The type for this profile field. - `value` - (Integer) The value for this profile field. + - `values` - (List) The permitted values for this profile field. - `cpu_architecture` - (List) The CPU architecture for a bare metal server with this profile. Nested scheme for `cpu_architecture`: @@ -108,3 +113,9 @@ Review the attribute references that you can access after you retrieve your data Nested scheme for `supported_trusted_platform_module_modes`: - `type` - (String) The type for this profile field. - `values` - (Array) The supported trusted platform module (TPM) modes. + + - `virtual_network_interfaces_supported` - (List) Indicates whether this profile supports virtual network interfaces. + + Nested schema for **virtual_network_interfaces_supported**: + - `type` - (String) The type for this profile field. + - `value` - (Boolean) The value for this profile field. \ No newline at end of file diff --git a/website/docs/d/is_bare_metal_servers.markdown b/website/docs/d/is_bare_metal_servers.markdown index f94867efd5..6518ded3ce 100644 --- a/website/docs/d/is_bare_metal_servers.markdown +++ b/website/docs/d/is_bare_metal_servers.markdown @@ -68,6 +68,36 @@ Review the attribute references that you can access after you retrieve your data - `keys` - (String) Image used in the bare metal server. - `memory` - (Integer) The amount of memory, truncated to whole gibibytes - `name` - (String) The name of the bare metal server. + - `network_attachments` - (List) The network attachments for this bare metal server, including the primary network attachment. + Nested schema for **network_attachments**: + - `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 network attachment. + - `id` - (String) The unique identifier for this network attachment. + - `name` - (String) + - `primary_ip` - (List) The primary IP address of the virtual network interface for the network attachment. + Nested schema for **primary_ip**: + - `address` - (String) The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `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 reserved IP. + - `id` - (String) The unique identifier for this reserved IP. + - `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. + - `resource_type` - (String) The resource type. + - `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. + Nested schema for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this subnet. + - `id` - (String) The unique identifier for this subnet. + - `name` - (String) The name for this subnet. The name is unique across all subnets in the VPC. + - `resource_type` - (String) The resource type. + - `network_interfaces` - (List) A nested block describing the additional network interface of this instance. Nested scheme for `network_interfaces`: @@ -86,6 +116,35 @@ 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. + - `primary_network_attachment` - (List) The primary network attachment. + Nested schema for **primary_network_attachment**: + - `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 network attachment. + - `id` - (String) The unique identifier for this network attachment. + - `name` - (String) + - `primary_ip` - (List) The primary IP address of the virtual network interface for the network attachment. + Nested schema for **primary_ip**: + - `address` - (String) The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `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 reserved IP. + - `id` - (String) The unique identifier for this reserved IP. + - `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. + - `resource_type` - (String) The resource type. + - `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. + Nested schema for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this subnet. + - `id` - (String) The unique identifier for this subnet. + - `name` - (String) The name for this subnet. The name is unique across all subnets in the VPC. + - `resource_type` - (String) The resource type. - `primary_network_interface` - (List) A nested block describing the primary network interface of this bare metal server. Nested scheme for `primary_network_interface`: @@ -132,8 +191,8 @@ Review the attribute references that you can access after you retrieve your data - `mode` - (String) The trusted platform module mode to use. The specified value must be listed in the bare metal server profile's supported_trusted_platform_module_modes. Updating trusted_platform_module mode would require the server to be stopped then started again. - Constraints: Allowable values are: `disabled`, `tpm_2`. - `supported_modes` - (Array) The trusted platform module (TPM) mode: - - **disabled: No TPM functionality** - - **tpm_2: TPM 2.0** - - The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered. + - **disabled: No TPM functionality** + - **tpm_2: TPM 2.0** + - The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered. - `vpc` - (String) The VPC this bare metal server resides in. - `zone` - (String) The zone this bare metal server resides in. diff --git a/website/docs/d/is_flow_log.html.markdown b/website/docs/d/is_flow_log.html.markdown index 21c3342f07..8aee722c25 100644 --- a/website/docs/d/is_flow_log.html.markdown +++ b/website/docs/d/is_flow_log.html.markdown @@ -74,6 +74,13 @@ In addition to all argument references listed, you can access the following attr - `name` - (String) The user-defined name for this network interface. - `resource_type` - (String) The resource type. Allowable values are: `network_interface`. + -> **Note:** + **•** If the target is an instance network attachment, flow logs will be collected for that instance network attachment.
+ **•** If the target is an instance network interface, flow logs will be collected for that instance network interface.
+ **•** If the target is a virtual network interface, flow logs will be collected for the the virtual network interface's `target` resource if the resource is: - an instance network attachment.
+ **•** If the target is a virtual server instance, flow logs will be collected for all network attachments or network interfaces on that instance.- If the target is a subnet, flow logs will be collected for all instance network interfaces and virtual network interfaces attached to that subnet.
+ **•** If the target is a VPC, flow logs will be collected for all instance network interfaces and virtual network interfaces attached to all subnets within that VPC. If the target is an instance, subnet, or VPC, flow logs will not be collectedfor any instance network attachments or instance network interfaces within the targetthat are themselves the target of a more specific flow log collector.
+ - `vpc` - (List) The VPC this flow log collector is associated with. Nested scheme for `vpc`: diff --git a/website/docs/d/is_flow_logs.html.markdown b/website/docs/d/is_flow_logs.html.markdown index c0f1040358..82c158d72e 100644 --- a/website/docs/d/is_flow_logs.html.markdown +++ b/website/docs/d/is_flow_logs.html.markdown @@ -48,7 +48,7 @@ Review the argument references that you can specify for your data source. - `vpc` - (String) The ID of the VPC this flow log collector resides in - `resource_group` - (String) The ID of the Resource group this flow log collector belongs to - `target` - (String) The ID of the target this collector is collecting flow logs for. -- `target_resource_type` - (String) The target resource type for this flow log collector. Available options are `instance`, `network_interface`, `subnet`, `vpc` +- `target_resource_type` - (String) The target resource type for this flow log collector. Available options are `instance`, `instance_network_attachment`, `network_interface`, `subnet`, `vpc`, `virtual_network_interface` ## Attribute reference Review the attribute references that you can access after you retrieve your data source. diff --git a/website/docs/d/is_images.html.markdown b/website/docs/d/is_images.html.markdown index 012e1beb74..a8dc652a19 100644 --- a/website/docs/d/is_images.html.markdown +++ b/website/docs/d/is_images.html.markdown @@ -36,11 +36,11 @@ data "ibm_is_images" "ds_images" { Review the argument references that you can specify for your data source. -* `catalog_managed` - (Optional, bool) Lists only those images which are managed as part of a catalog offering. -* `resource_group` - (Optional, string) The id of the resource group. -* `name` - (Optional, string) The name of the image. -* `visibility` - (Optional, string) Visibility of the image. -* `status` - (Optional, string) Status of the image. +- `catalog_managed` - (Optional, bool) Lists only those images which are managed as part of a catalog offering. +- `resource_group` - (Optional, string) The id of the resource group. +- `name` - (Optional, string) The name of the image. +- `visibility` - (Optional, string) Visibility of the image. Accepted values : **private**, **public** +- `status` - (Optional, string) Status of the image. Accepted value : **available**, **deleting**, **deprecated**, **failed**, **obsolete**, **pending**, **unusable** ## Attribute reference You can access the following attribute references after your data source is created. diff --git a/website/docs/d/is_instance.html.markdown b/website/docs/d/is_instance.html.markdown index c330914f9a..6d097c5f13 100644 --- a/website/docs/d/is_instance.html.markdown +++ b/website/docs/d/is_instance.html.markdown @@ -48,6 +48,21 @@ resource "ibm_is_image" "example" { } +resource "ibm_is_reservation" "example" { + capacity { + total = 5 + } + committed_use { + term = "one_year" + } + profile { + name = "ba2-2x8" + resource_type = "instance_profile" + } + zone = "us-east-3" + name = "reservation-name" +} + resource "ibm_is_instance" "example" { name = "example-instance" image = ibm_is_image.example.id @@ -63,6 +78,13 @@ resource "ibm_is_instance" "example" { subnet = ibm_is_subnet.example.id } + reservation_affinity { + policy = "manual" + pool { + id = ibm_is_reservation.example.id + } + } + vpc = ibm_is_vpc.example.id zone = "us-south-1" keys = [ibm_is_ssh_key.example.id] @@ -155,6 +177,36 @@ In addition to all argument reference list, you can access the following attribu - `enabled` - (Boolean) Indicates whether the metadata service endpoint will be available to the virtual server instance. - `protocol` - (String) The communication protocol to use for the metadata service endpoint. - `response_hop_limit` - (Integer) The hop limit (IP time to live) for IP response packets from the metadata service. + +- `network_attachments` - (List) The network attachments for this virtual server instance, including the primary network attachment. + Nested schema for **network_attachments**: + - `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 network attachment. + - `id` - (String) The unique identifier for this network attachment. + - `name` - (String) + - `primary_ip` - (List) The primary IP address of the virtual network interface for the network attachment. + Nested schema for **primary_ip**: + - `address` - (String) The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `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 reserved IP. + - `id` - (String) The unique identifier for this reserved IP. + - `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. + - `resource_type` - (String) The resource type. + - `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. + Nested schema for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this subnet. + - `id` - (String) The unique identifier for this subnet. + - `name` - (String) The name for this subnet. The name is unique across all subnets in the VPC. + - `resource_type` - (String) The resource type. - `network_interfaces`- (List) A list of more network interfaces that the instance uses. @@ -184,6 +236,36 @@ In addition to all argument reference list, you can access the following attribu - `id` - (String) The unique identifier for this placement target resource. - `name` - (String) The unique user-defined name for this placement target resource. If unspecified, the name will be a hyphenated list of randomly-selected words. - `resource_type` - (String) The type of resource referenced. +- `primary_network_attachment` - (List) The primary network attachment for this virtual server instance. + Nested schema for **primary_network_attachment**: + - `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 network attachment. + - `id` - (String) The unique identifier for this network attachment. + - `name` - (String) + - `primary_ip` - (List) The primary IP address of the virtual network interface for the network attachment. + Nested schema for **primary_ip**: + - `address` - (String) The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `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 reserved IP. + - `id` - (String) The unique identifier for this reserved IP. + - `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. + - `resource_type` - (String) The resource type. + - `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. + Nested schema for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this subnet. + - `id` - (String) The unique identifier for this subnet. + - `name` - (String) The name for this subnet. The name is unique across all subnets in the VPC. + - `resource_type` - (String) The resource type. + - `primary_network_interface`- (List) A list of primary network interfaces that were created for the instance. Nested scheme for `primary_network_interface`: @@ -200,6 +282,34 @@ In addition to all argument reference list, you can access the following attribu - `primary_ipv4_address` - (String) The IPv4 address range that the subnet uses. Same as `primary_ip.0.address` - `subnet` - (String) The ID of the subnet that is used in the primary network interface. - `security_groups` (List)A list of security groups that were created for the interface. +- `reservation`- (List) The reservation used by this virtual server instance. + + 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 instance reservation affinity. + + Nested scheme for `reservation_affinity`: + - `policy` - (String) The reservation affinity policy to use for this virtual server instance. + - `pool` - (List) The pool of reservations available for use by this virtual server instance. + + 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_controller_url` - (String) The URL of the IBM Cloud dashboard that you can use to see details for your instance. - `resource_group` - (String) The resource group id, where the instance was created. - `status` - (String) The status of the instance. diff --git a/website/docs/d/is_instance_network_attachment.html.markdown b/website/docs/d/is_instance_network_attachment.html.markdown new file mode 100644 index 0000000000..43fd11e66c --- /dev/null +++ b/website/docs/d/is_instance_network_attachment.html.markdown @@ -0,0 +1,70 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_instance_network_attachment" +description: |- + Get information about InstanceNetworkAttachment +subcategory: "Virtual Private Cloud API" +--- + +# ibm_is_instance_network_attachment + +Provides a read-only data source to retrieve information about an Instance NetworkAttachment. You can then reference the fields of the data source in other resources within the same configuration by using interpolation syntax. + +## Example Usage + +```terraform +data "ibm_is_instance_network_attachment" "example" { + instance = ibm_is_instance.example.id + network_attachment = ibm_is_instance.example.primary_network_attachment.0.id +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +- `instance` - (Required, Forces new resource, String) The virtual server instance identifier. +- `network_attachment` - (Required, Forces new resource, String) The instance 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 Instance NetworkAttachment.`/` +- `created_at` - (String) The date and time that the instance network attachment was created. +- `href` - (String) The URL for this instance network attachment. +- `lifecycle_state` - (String) The lifecycle state of the instance network attachment. Allowable values are: `deleting`, `failed`, `pending`, `stable`, `suspended`, `updating`, `waiting`. +- `name` - (String) The name for this instance network attachment. The name is unique across all network attachments for the instance. +- `port_speed` - (Integer) The port speed for this instance network attachment in Mbps. +- `primary_ip` - (List) The primary IP address of the virtual network interface for the instance networkattachment. + Nested schema for **primary_ip**: + - `address` - (String) The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `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 reserved IP. + - `id` - (String) The unique identifier for this reserved IP. + - `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. + +- `resource_type` - (String) The resource type. +- `subnet` - (List) The subnet of the virtual network interface for the instance 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. + Nested schema for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this subnet. + - `id` - (String) The unique identifier for this subnet. + - `name` - (String) The name for this subnet. The name is unique across all subnets in the VPC. + - `resource_type` - (String) The resource type. + +- `type` - (String) The instance network attachment type. +- `virtual_network_interface` - (List) The virtual network interface for this instance network attachment. + Nested schema for **virtual_network_interface**: + - `crn` - (String) The CRN for this virtual network interface. + - `href` - (String) The URL for this virtual network interface. + - `id` - (String) The unique identifier for this virtual network interface. + - `name` - (String) The name for this virtual network interface. The name is unique across all virtual network interfaces in the VPC. + - `resource_type` - (String) The resource type. + diff --git a/website/docs/d/is_instance_network_attachments.html.markdown b/website/docs/d/is_instance_network_attachments.html.markdown new file mode 100644 index 0000000000..128bce999e --- /dev/null +++ b/website/docs/d/is_instance_network_attachments.html.markdown @@ -0,0 +1,69 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_instance_network_attachments" +description: |- + Get information about InstanceNetworkAttachment Collection +subcategory: "Virtual Private Cloud API" +--- + +# ibm_is_instance_network_attachments + +Provides a read-only data source to retrieve information about an InstanceNetworkAttachment Collection. You can then reference the fields of the data source in other resources within the same configuration by using interpolation syntax. + +## Example Usage + +```terraform +data "ibm_is_instance_network_attachments" "example" { + instance = ibm_is_instance.example.id +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +- `instance` - (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 InstanceNetworkAttachmentCollection. +- `network_attachments` - (List) Collection of instance network attachments. + Nested schema for **network_attachments**: + - `created_at` - (String) The date and time that the instance network attachment was created. + - `href` - (String) The URL for this instance network attachment. + - `id` - (String) The unique identifier for this instance network attachment. + - `lifecycle_state` - (String) The lifecycle state of the instance network attachment. + - `name` - (String) The name for this instance network attachment. The name is unique across all network attachments for the instance. + - `port_speed` - (Integer) The port speed for this instance network attachment in Mbps. + - `primary_ip` - (List) The primary IP address of the virtual network interface for the instance networkattachment. + Nested schema for **primary_ip**: + - `address` - (String) The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `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 reserved IP. + - `id` - (String) The unique identifier for this reserved IP. + - `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. + - `resource_type` - (String) The resource type. + - `subnet` - (List) The subnet of the virtual network interface for the instance 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. + Nested schema for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this subnet. + - `id` - (String) The unique identifier for this subnet. + - `name` - (String) The name for this subnet. The name is unique across all subnets in the VPC. + - `resource_type` - (String) The resource type. + - `type` - (String) The instance network attachment type. + - `virtual_network_interface` - (List) The virtual network interface for this instance network attachment. + Nested schema for **virtual_network_interface**: + - `crn` - (String) The CRN for this virtual network interface. + - `href` - (String) The URL for this virtual network interface. + - `id` - (String) The unique identifier for this virtual network interface. + - `name` - (String) The name for this virtual network interface. The name is unique across all virtual network interfaces in the VPC. + - `resource_type` - (String) The resource type. + diff --git a/website/docs/d/is_instance_profile.html.markdown b/website/docs/d/is_instance_profile.html.markdown index e34bb233cd..9bbebdb344 100644 --- a/website/docs/d/is_instance_profile.html.markdown +++ b/website/docs/d/is_instance_profile.html.markdown @@ -117,6 +117,10 @@ In addition to the argument reference list, you can access the following attribu Nested scheme for `gpu_model`: - `type` - (String) The type for this profile field. - `values` - (String) The permitted values for this profile field. +- `reservation_terms` - (List) Nested `reservation_terms` blocks have the following structure: + Nested scheme for `reservation_terms`: + - `type` - (String) The type for this profile field. + - `values` - (String) The supported committed use terms for a reservation using this profile. - `href` - (String) The URL for this virtual server instance profile. - `memory` - (List) Nested `memory` blocks have the following structure: @@ -128,6 +132,13 @@ In addition to the argument reference list, you can access the following attribu - `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. +- `network_attachment_count` - (List) The number of network attachments supported on an instance with this profile + + Nested scheme for `network_attachment_count`: + - `max` - (Integer) The maximum number of network attachments supported by an instance using this profile. + - `min` - (Integer) The minimum number of network attachments supported by an instance using this profile. + - `type` - (String) The type for this profile field, Ex: range or dependent. + - `network_interface_count` - (List) Nested scheme for `network_interface_count`: diff --git a/website/docs/d/is_instance_profiles.html.markdown b/website/docs/d/is_instance_profiles.html.markdown index e59d5a0a45..1501b80b64 100644 --- a/website/docs/d/is_instance_profiles.html.markdown +++ b/website/docs/d/is_instance_profiles.html.markdown @@ -108,6 +108,10 @@ You can access the following attribute references after your data source is crea Nested scheme for `gpu_model`: - `type` - (String) The type for this profile field. - `values` - (String) The permitted values for this profile field. + - `reservation_terms` - (List) Nested `reservation_terms` blocks have the following structure: + Nested scheme for `reservation_terms`: + - `type` - (String) The type for this profile field. + - `values` - (String) The supported committed use terms for a reservation using this profile. - `total_volume_bandwidth` Nested `total_volume_bandwidth` blocks have the following structure: Nested scheme for `total_volume_bandwidth`: - `type` - The type for this profile field. @@ -129,6 +133,14 @@ You can access the following attribute references after your data source is crea - `value` - (String) The value for this profile field. - `values` - (String) The permitted values for this profile field. + - `network_attachment_count` - (List) The number of network attachments supported on an instance with this profile + + Nested scheme for `network_attachment_count`: + - `max` - (Integer) The maximum number of network attachments supported by an instance using this profile. + - `min` - (Integer) The minimum number of network attachments supported by an instance using this profile. + - `type` - (String) The type for this profile field, Ex: range or dependent. + + - `network_interface_count` - (List) Nested scheme for `network_interface_count`: diff --git a/website/docs/d/is_instance_template.html.markdown b/website/docs/d/is_instance_template.html.markdown index dbe863c3b2..4736ad7b9c 100644 --- a/website/docs/d/is_instance_template.html.markdown +++ b/website/docs/d/is_instance_template.html.markdown @@ -82,6 +82,46 @@ You can access the following attribute references after your data source is crea - `response_hop_limit` - (Integer) The hop limit (IP time to live) for IP response packets from the metadata service. - `name` - (String) The name of the instance template. +- `network_attachments` - (List) The additional network attachments to create for the virtual server instance. + Nested schema for **network_attachments**: + - `name` - (String) The name for this network attachment. Names must be unique within the instance the network attachment resides in. If unspecified, the name will be a hyphenated list of randomly-selected words. + - `virtual_network_interface` - (List) A virtual network interface for the instance network attachment. This can be specifiedusing an existing virtual network interface, or a prototype object for a new virtualnetwork interface.If an existing virtual network interface is specified, `enable_infrastructure_nat` must be`false`. + Nested schema for **virtual_network_interface**: + - `allow_ip_spoofing` - (Boolean) Indicates whether source IP spoofing is allowed on this interface. If `false`, source IP spoofing is prevented on this interface. If `true`, source IP spoofing is allowed on this interface. + - `auto_delete` - (Boolean) Indicates whether this virtual network interface will be automatically deleted when`target` is deleted. + - `crn` - (String) The CRN for this virtual network interface. + - `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.- `allow_ip_spoofing` must be `false`.- If the virtual network interface is attached: - The target `resource_type` must be `bare_metal_server_network_attachment`. - The target `interface_type` must not be `hipersocket`. + - `href` - (String) The URL for this virtual network interface. + - `id` - (String) The unique identifier for this virtual network interface. + - `ips` - (List) Additional IP addresses to bind to the virtual network interface. Each item may be either a reserved IP identity, or as a reserved IP prototype object which will be used to create a new reserved IP. All IP addresses must be in the same subnet as the primary IP.If reserved IP identities are provided, the specified reserved IPs must be unbound.If reserved IP prototype objects with addresses are provided, the addresses must be available on the virtual network interface's subnet. For any prototype objects that do not specify an address, an available address on the subnet will be automatically selected and reserved. + Nested schema for **ips**: + - `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 reserved IP member will be automatically deleted when either`target` is deleted, or the reserved IP is unbound. + - `href` - (String) The URL for this reserved IP. + - `id` - (String) The unique identifier for this reserved IP. + - `name` - (String) The name for this reserved IP. The name must not be used by another reserved IP in the 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. + - `name` - (String) The name for this virtual network interface. The name must not be used by another virtual network interface in the VPC. If unspecified, the name will be a hyphenated list of randomly-selected words. Names beginning with `ibm-` are reserved for provider-owned resources, and are not allowed. + - `primary_ip` - (List) The primary IP address to bind to the virtual network interface. May be either areserved IP identity, or a reserved IP prototype object which will be used to create anew reserved IP.If a reserved IP identity is provided, the specified reserved IP must be unbound.If a reserved IP prototype object with an address is provided, the address must beavailable on the virtual network interface's subnet. If no address is specified,an available address on the subnet will 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 reserved IP member will be automatically deleted when either`target` is deleted, or the reserved IP is unbound. + - `href` - (String) The URL for this reserved IP. + - `id` - (String) The unique identifier for this reserved IP. + - `name` - (String) The name for this reserved IP. The name must not be used by another reserved IP in the 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. + - `resource_group` - (List) The resource group to use for this virtual network interface. If unspecified, thevirtual server instance's resource group will be used. + Nested schema for **resource_group**: + - `id` - (String) The unique identifier for this resource group. + - `security_groups` - (List) The security groups to use for this virtual network interface. If unspecified, the default security group of the VPC for the subnet is used. + Nested schema for **security_groups**: + - `crn` - (String) The security group's CRN. + - `href` - (String) The security group's canonical URL. + - `id` - (String) The unique identifier for this security group. + - `subnet` - (List) The associated subnet. Required if `primary_ip` does not specify a reserved IP. + Nested schema for **subnet**: + - `crn` - (String) The CRN for this subnet. + - `href` - (String) The URL for this subnet. + - `id` - (String) The unique identifier for this subnet. + - `network_interfaces` - (List) A nested block describes the network interfaces for the template. Nested scheme for `network_interfaces`: @@ -97,6 +137,46 @@ You can access the following attribute references after your data source is crea - `id` - (String) The URL for this placement target. - `profile` - (String) The number of instances created in the instance group. +- `primary_network_attachment` - (List) The primary network attachment to create for the virtual server instance. + Nested schema for **primary_network_attachment**: + - `name` - (String) The name for this network attachment. Names must be unique within the instance the network attachment resides in. If unspecified, the name will be a hyphenated list of randomly-selected words. + - `virtual_network_interface` - (List) A virtual network interface for the instance network attachment. This can be specifiedusing an existing virtual network interface, or a prototype object for a new virtualnetwork interface.If an existing virtual network interface is specified, `enable_infrastructure_nat` must be`false`. + Nested schema for **virtual_network_interface**: + - `allow_ip_spoofing` - (Boolean) Indicates whether source IP spoofing is allowed on this interface. If `false`, source IP spoofing is prevented on this interface. If `true`, source IP spoofing is allowed on this interface. + - `auto_delete` - (Boolean) Indicates whether this virtual network interface will be automatically deleted when`target` is deleted. + - `crn` - (String) The CRN for this virtual network interface. + - `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.- `allow_ip_spoofing` must be `false`.- If the virtual network interface is attached: - The target `resource_type` must be `bare_metal_server_network_attachment`. - The target `interface_type` must not be `hipersocket`. + - `href` - (String) The URL for this virtual network interface. + - `id` - (String) The unique identifier for this virtual network interface. + - `ips` - (List) Additional IP addresses to bind to the virtual network interface. Each item may be either a reserved IP identity, or as a reserved IP prototype object which will be used to create a new reserved IP. All IP addresses must be in the same subnet as the primary IP.If reserved IP identities are provided, the specified reserved IPs must be unbound.If reserved IP prototype objects with addresses are provided, the addresses must be available on the virtual network interface's subnet. For any prototype objects that do not specify an address, an available address on the subnet will be automatically selected and reserved. + Nested schema for **ips**: + - `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 reserved IP member will be automatically deleted when either`target` is deleted, or the reserved IP is unbound. + - `href` - (String) The URL for this reserved IP. + - `id` - (String) The unique identifier for this reserved IP. + - `name` - (String) The name for this reserved IP. The name must not be used by another reserved IP in the 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. + - `name` - (String) The name for this virtual network interface. The name must not be used by another virtual network interface in the VPC. If unspecified, the name will be a hyphenated list of randomly-selected words. Names beginning with `ibm-` are reserved for provider-owned resources, and are not allowed. + - `primary_ip` - (List) The primary IP address to bind to the virtual network interface. May be either areserved IP identity, or a reserved IP prototype object which will be used to create anew reserved IP.If a reserved IP identity is provided, the specified reserved IP must be unbound.If a reserved IP prototype object with an address is provided, the address must beavailable on the virtual network interface's subnet. If no address is specified,an available address on the subnet will 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 reserved IP member will be automatically deleted when either`target` is deleted, or the reserved IP is unbound. + - `href` - (String) The URL for this reserved IP. + - `id` - (String) The unique identifier for this reserved IP. + - `name` - (String) The name for this reserved IP. The name must not be used by another reserved IP in the 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. + - `resource_group` - (List) The resource group to use for this virtual network interface. If unspecified, thevirtual server instance's resource group will be used. + Nested schema for **resource_group**: + - `id` - (String) The unique identifier for this resource group. + - `security_groups` - (List) The security groups to use for this virtual network interface. If unspecified, the default security group of the VPC for the subnet is used. + Nested schema for **security_groups**: + - `crn` - (String) The security group's CRN. + - `href` - (String) The security group's canonical URL. + - `id` - (String) The unique identifier for this security group. + - `subnet` - (List) The associated subnet. Required if `primary_ip` does not specify a reserved IP. + Nested schema for **subnet**: + - `crn` - (String) The CRN for this subnet. + - `href` - (String) The URL for this subnet. + - `id` - (String) The unique identifier for this subnet. + - `primary_network_interfaces` - (List) A nested block describes the primary network interface for the template. Nested scheme for `primary_network_interfaces`: @@ -104,6 +184,14 @@ You can access the following attribute references after your data source is crea - `primary_ipv4_address` - (String) The IPv4 address assigned to the primary network interface. - `subnet` - (String) The VPC subnet to assign to the interface. - `security_groups` - (String) List of security groups of the subnet. +- `reservation_affinity` - (Optional, List) The reservation affinity for the instance + Nested scheme for `reservation_affinity`: + - `policy` - (Optional, String) The reservation affinity policy to use for this virtual server instance. + + ->**policy** + • disabled: Reservations will not be used +
• manual: Reservations in pool will be available for use + - `pool` - (string) The unique identifier for this reservation - `resource_group` - (String) The resource group ID. - `total_volume_bandwidth` - (Integer) The amount of bandwidth (in megabits per second) allocated exclusively to instance storage volumes - `user_data` - (String) The user data provided for the instance. diff --git a/website/docs/d/is_instance_templates.html.markdown b/website/docs/d/is_instance_templates.html.markdown index 84aaf636ab..643a05274b 100644 --- a/website/docs/d/is_instance_templates.html.markdown +++ b/website/docs/d/is_instance_templates.html.markdown @@ -71,6 +71,46 @@ You can access the following attribute references after your data source is crea - `response_hop_limit` - (Integer) The hop limit (IP time to live) for IP response packets from the metadata service. - `name` - (String) The name of the instance template. + - `network_attachments` - (List) The additional network attachments to create for the virtual server instance. + Nested schema for **network_attachments**: + - `name` - (String) The name for this network attachment. Names must be unique within the instance the network attachment resides in. If unspecified, the name will be a hyphenated list of randomly-selected words. + - `virtual_network_interface` - (List) A virtual network interface for the instance network attachment. This can be specifiedusing an existing virtual network interface, or a prototype object for a new virtualnetwork interface.If an existing virtual network interface is specified, `enable_infrastructure_nat` must be`false`. + Nested schema for **virtual_network_interface**: + - `allow_ip_spoofing` - (Boolean) Indicates whether source IP spoofing is allowed on this interface. If `false`, source IP spoofing is prevented on this interface. If `true`, source IP spoofing is allowed on this interface. + - `auto_delete` - (Boolean) Indicates whether this virtual network interface will be automatically deleted when`target` is deleted. + - `crn` - (String) The CRN for this virtual network interface. + - `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.- `allow_ip_spoofing` must be `false`.- If the virtual network interface is attached: - The target `resource_type` must be `bare_metal_server_network_attachment`. - The target `interface_type` must not be `hipersocket`. + - `href` - (String) The URL for this virtual network interface. + - `id` - (String) The unique identifier for this virtual network interface. + - `ips` - (List) Additional IP addresses to bind to the virtual network interface. Each item may be either a reserved IP identity, or as a reserved IP prototype object which will be used to create a new reserved IP. All IP addresses must be in the same subnet as the primary IP.If reserved IP identities are provided, the specified reserved IPs must be unbound.If reserved IP prototype objects with addresses are provided, the addresses must be available on the virtual network interface's subnet. For any prototype objects that do not specify an address, an available address on the subnet will be automatically selected and reserved. + Nested schema for **ips**: + - `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 reserved IP member will be automatically deleted when either`target` is deleted, or the reserved IP is unbound. + - `href` - (String) The URL for this reserved IP. + - `id` - (String) The unique identifier for this reserved IP. + - `name` - (String) The name for this reserved IP. The name must not be used by another reserved IP in the 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. + - `name` - (String) The name for this virtual network interface. The name must not be used by another virtual network interface in the VPC. If unspecified, the name will be a hyphenated list of randomly-selected words. Names beginning with `ibm-` are reserved for provider-owned resources, and are not allowed. + - `primary_ip` - (List) The primary IP address to bind to the virtual network interface. May be either areserved IP identity, or a reserved IP prototype object which will be used to create anew reserved IP.If a reserved IP identity is provided, the specified reserved IP must be unbound.If a reserved IP prototype object with an address is provided, the address must beavailable on the virtual network interface's subnet. If no address is specified,an available address on the subnet will 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 reserved IP member will be automatically deleted when either`target` is deleted, or the reserved IP is unbound. + - `href` - (String) The URL for this reserved IP. + - `id` - (String) The unique identifier for this reserved IP. + - `name` - (String) The name for this reserved IP. The name must not be used by another reserved IP in the 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. + - `resource_group` - (List) The resource group to use for this virtual network interface. If unspecified, thevirtual server instance's resource group will be used. + Nested schema for **resource_group**: + - `id` - (String) The unique identifier for this resource group. + - `security_groups` - (List) The security groups to use for this virtual network interface. If unspecified, the default security group of the VPC for the subnet is used. + Nested schema for **security_groups**: + - `crn` - (String) The security group's CRN. + - `href` - (String) The security group's canonical URL. + - `id` - (String) The unique identifier for this security group. + - `subnet` - (List) The associated subnet. Required if `primary_ip` does not specify a reserved IP. + Nested schema for **subnet**: + - `crn` - (String) The CRN for this subnet. + - `href` - (String) The URL for this subnet. + - `id` - (String) The unique identifier for this subnet. + - `network_interfaces` - (List) A nested block describes the network interfaces for the template. Nested scheme for `network_interfaces`: @@ -84,6 +124,46 @@ You can access the following attribute references after your data source is crea - `href` - (String) The CRN for this placement target. - `id` - (String) The URL for this placement target. - `profile` - (String) The number of instances created in the instance group. + - `primary_network_attachment` - (List) The primary network attachment to create for the virtual server instance. + Nested schema for **primary_network_attachment**: + - `name` - (String) The name for this network attachment. Names must be unique within the instance the network attachment resides in. If unspecified, the name will be a hyphenated list of randomly-selected words. + - `virtual_network_interface` - (List) A virtual network interface for the instance network attachment. This can be specifiedusing an existing virtual network interface, or a prototype object for a new virtualnetwork interface.If an existing virtual network interface is specified, `enable_infrastructure_nat` must be`false`. + Nested schema for **virtual_network_interface**: + - `allow_ip_spoofing` - (Boolean) Indicates whether source IP spoofing is allowed on this interface. If `false`, source IP spoofing is prevented on this interface. If `true`, source IP spoofing is allowed on this interface. + - `auto_delete` - (Boolean) Indicates whether this virtual network interface will be automatically deleted when`target` is deleted. + - `crn` - (String) The CRN for this virtual network interface. + - `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.- `allow_ip_spoofing` must be `false`.- If the virtual network interface is attached: - The target `resource_type` must be `bare_metal_server_network_attachment`. - The target `interface_type` must not be `hipersocket`. + - `href` - (String) The URL for this virtual network interface. + - `id` - (String) The unique identifier for this virtual network interface. + - `ips` - (List) Additional IP addresses to bind to the virtual network interface. Each item may be either a reserved IP identity, or as a reserved IP prototype object which will be used to create a new reserved IP. All IP addresses must be in the same subnet as the primary IP.If reserved IP identities are provided, the specified reserved IPs must be unbound.If reserved IP prototype objects with addresses are provided, the addresses must be available on the virtual network interface's subnet. For any prototype objects that do not specify an address, an available address on the subnet will be automatically selected and reserved. + Nested schema for **ips**: + - `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 reserved IP member will be automatically deleted when either`target` is deleted, or the reserved IP is unbound. + - `href` - (String) The URL for this reserved IP. + - `id` - (String) The unique identifier for this reserved IP. + - `name` - (String) The name for this reserved IP. The name must not be used by another reserved IP in the 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. + - `name` - (String) The name for this virtual network interface. The name must not be used by another virtual network interface in the VPC. If unspecified, the name will be a hyphenated list of randomly-selected words. Names beginning with `ibm-` are reserved for provider-owned resources, and are not allowed. + - `primary_ip` - (List) The primary IP address to bind to the virtual network interface. May be either areserved IP identity, or a reserved IP prototype object which will be used to create anew reserved IP.If a reserved IP identity is provided, the specified reserved IP must be unbound.If a reserved IP prototype object with an address is provided, the address must beavailable on the virtual network interface's subnet. If no address is specified,an available address on the subnet will 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 reserved IP member will be automatically deleted when either`target` is deleted, or the reserved IP is unbound. + - `href` - (String) The URL for this reserved IP. + - `id` - (String) The unique identifier for this reserved IP. + - `name` - (String) The name for this reserved IP. The name must not be used by another reserved IP in the 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. + - `resource_group` - (List) The resource group to use for this virtual network interface. If unspecified, thevirtual server instance's resource group will be used. + Nested schema for **resource_group**: + - `id` - (String) The unique identifier for this resource group. + - `security_groups` - (List) The security groups to use for this virtual network interface. If unspecified, the default security group of the VPC for the subnet is used. + Nested schema for **security_groups**: + - `crn` - (String) The security group's CRN. + - `href` - (String) The security group's canonical URL. + - `id` - (String) The unique identifier for this security group. + - `subnet` - (List) The associated subnet. Required if `primary_ip` does not specify a reserved IP. + Nested schema for **subnet**: + - `crn` - (String) The CRN for this subnet. + - `href` - (String) The URL for this subnet. + - `id` - (String) The unique identifier for this subnet. + - `primary_network_interfaces` - (List) A nested block describes the primary network interface for the template. Nested scheme for `primary_network_interfaces`: @@ -91,6 +171,14 @@ You can access the following attribute references after your data source is crea - `primary_ipv4_address` - (String) The IPv4 address assigned to the primary network interface. - `subnet` - (String) The VPC subnet to assign to the interface. - `security_groups` - (String) List of security groups of the subnet. + - `reservation_affinity` - (Optional, List) The reservation affinity for the instance + Nested scheme for `reservation_affinity`: + - `policy` - (Optional, String) The reservation affinity policy to use for this virtual server instance. + + ->**policy** + • disabled: Reservations will not be used +
• manual: Reservations in pool will be available for use + - `pool` - (string) The unique identifier for this reservation - `resource_group` - (String) The resource group ID. - `total_volume_bandwidth` - (Integer) The amount of bandwidth (in megabits per second) allocated exclusively to instance storage volumes - `user_data` - (String) The user data provided for the instance. diff --git a/website/docs/d/is_instances.html.markdown b/website/docs/d/is_instances.html.markdown index 42a5e07edb..c1de161b49 100644 --- a/website/docs/d/is_instances.html.markdown +++ b/website/docs/d/is_instances.html.markdown @@ -111,7 +111,37 @@ In addition to all argument reference list, you can access the following attribu - `enabled` - (Boolean) Indicates whether the metadata service endpoint will be available to the virtual server instance. - `protocol` - (String) The communication protocol to use for the metadata service endpoint. - `response_hop_limit` - (Integer) The hop limit (IP time to live) for IP response packets from the metadata service. - + + - `network_attachments` - (List) The network attachments for this virtual server instance, including the primary network attachment. + Nested schema for **network_attachments**: + - `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 network attachment. + - `id` - (String) The unique identifier for this network attachment. + - `name` - (String) + - `primary_ip` - (List) The primary IP address of the virtual network interface for the network attachment. + Nested schema for **primary_ip**: + - `address` - (String) The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `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 reserved IP. + - `id` - (String) The unique identifier for this reserved IP. + - `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. + - `resource_type` - (String) The resource type. + - `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. + Nested schema for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this subnet. + - `id` - (String) The unique identifier for this subnet. + - `name` - (String) The name for this subnet. The name is unique across all subnets in the VPC. + - `resource_type` - (String) The resource type. + - `network_interfaces`- (List) A list of more network interfaces that the instance uses. Nested scheme for `network_interfaces`: @@ -139,6 +169,36 @@ In addition to all argument reference list, you can access the following attribu - `id` - (String) The unique identifier for this placement target resource. - `name` - (String) The unique user-defined name for this placement target resource. If unspecified, the name will be a hyphenated list of randomly-selected words. - `resource_type` - (String) The type of resource referenced. + - `primary_network_attachment` - (List) The primary network attachment for this virtual server instance. + Nested schema for **primary_network_attachment**: + - `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 network attachment. + - `id` - (String) The unique identifier for this network attachment. + - `name` - (String) + - `primary_ip` - (List) The primary IP address of the virtual network interface for the network attachment. + Nested schema for **primary_ip**: + - `address` - (String) The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `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 reserved IP. + - `id` - (String) The unique identifier for this reserved IP. + - `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. + - `resource_type` - (String) The resource type. + - `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. + Nested schema for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this subnet. + - `id` - (String) The unique identifier for this subnet. + - `name` - (String) The name for this subnet. The name is unique across all subnets in the VPC. + - `resource_type` - (String) The resource type. + - `primary_network_interface`- (List) A list of primary network interfaces that were created for the instance. Nested scheme for `primary_network_interface`: @@ -156,6 +216,33 @@ In addition to all argument reference list, you can access the following attribu - `resource_type`- (String) The resource type. - `primary_ipv4_address` - (String) The IPv4 address range that the subnet uses. Same as `primary_ip.0.address` - `resource_group` - (String) The name of the resource group where the instance was created. + - `reservation`- (List) The reservation used by this virtual server instance. + 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 instance reservation affinity. + + Nested scheme for `reservation_affinity`: + - `policy` - (String) The reservation affinity policy to use for this virtual server instance. + - `pool` - (List) The pool of reservations available for use by this virtual server instance. + + 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. - `status` - (String) The status of the instance. - `status_reasons` - (List) Array of reasons for the current status. diff --git a/website/docs/d/is_reservation.html.markdown b/website/docs/d/is_reservation.html.markdown new file mode 100644 index 0000000000..07ba007714 --- /dev/null +++ b/website/docs/d/is_reservation.html.markdown @@ -0,0 +1,164 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : reservation" +description: |- + Manages IBM Cloud reservations. +--- + +# ibm_is_reservation +Retrieve information of an existing reservation as a read only data source. + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "us-south" +} +``` + +## Example usage +// Example to retrieve the reservation information by using reservation name. + +```terraform +resource "ibm_is_reservation" "res" { + capacity { + total = 5 + } + committed_use { + term = "one_year" + } + profile { + name = "ba2-2x8" + resource_type = "instance_profile" + } + zone = "us-east-3" + name = "reservation-name" +} +data "ibm_is_reservation" "ds_res" { + name = ibm_is_reservation.res.name +} + +``` +// Example to retrieve the reservation information by using reservation ID. + +```terraform +resource "ibm_is_reservation" "res" { + capacity { + total = 5 + } + committed_use { + term = "one_year" + } + profile { + name = "ba2-2x8" + resource_type = "instance_profile" + } + zone = "us-east-3" + name = "reservation-name" +} +data "ibm_is_reservation" "ds_res" { + identifier = ibm_is_reservation.res.id +} + +``` + +## Argument reference +Review the argument references that you can specify for your data source. + +- `identifier` - (Optional, String) The ID of the reservation,`name` and `identifier` are mutually exclusive. +- `name` - (Optional, String) The name of the reservation,`name` and `identifier` are mutually exclusive. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `affinity_policy` - (String) The affinity policy to use for this reservation. +- `capacity` - (List) The capacity configuration for this reservation. If absent, this reservation has no assigned capacity. + + Nested scheme for `capacity`: + - `allocated` - (Integer) The amount allocated to this capacity reservation. + - `available` - (Integer) The amount of this capacity reservation available for new attachments. + - `status` - (String) The status of the capacity reservation. + + ->**status** +
• allocating: The capacity reservation is being allocated for use +
• allocated: The total capacity of the reservation has been allocated for use +
• degraded: The capacity reservation has been allocated for use, but some of the capacity is not available +
• unallocated: The capacity reservation is not allocated for use + - `total` - (Integer) The total amount of this capacity reservation. + - `used` - (Integer) The amount of this capacity reservation used by existing attachments. +- `committed_use` - (List) The committed use configuration for this reservation. If absent, this reservation has no commitment for use. + + Nested scheme for `committed_use`: + - `expiration_at` - (Timestamp) The expiration date and time for this committed use reservation. + - `expiration_policy` - (String) The policy to apply when the committed use term expires. + + ->**expiration_policy** +
• release: Release any available capacity and let the reservation expire +
• renew: Renew for another term, provided the term remains listed in the reservation_terms for the profile. Otherwise, let the reservation expire + - `term` - (String) The term for this committed use reservation. + + ->**term** +
• one_year: 1 year +
• three_year: 3 years +- `created_at` - (Timestamp) The date and time that the reservation was created. +- `crn` - (String) The CRN for this reservation. +- `href` - (String) The URL for this reservation. +- `id` - (String) The unique identifier for this reservation. +- `lifecycle_state` - (String) The lifecycle state of this reservation. + + ->**lifecycle_state** +
• deleting +
• failed +
• pending +
• stable +
• suspended +
• updating +
• waiting +- `profile` - (List) The virtual server instance profile this reservation. + + Nested scheme for `profile`: + - `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 + + ->**resource_type** +
• instance_profile +- `resource_group` - (List) The resource group for this reservation. + + Nested scheme 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. + + ->**resource_type** +
• reservation +- `status` - (String) The status of the reservation. + + ->**status** +
• activating +
• active +
• deactivating +
• expired +
• failed +
• inactive +- `status_reasons` - (List) The reasons for the current status (if any). + + Nested scheme for `status_reasons`: + - `code` - (String) A snake case string succinctly identifying the status reason. + + ->**code** +
• cannot_activate_no_capacity_available +
• cannot_renew_unsupported_profile_term + - `message` - (String) An explanation of the status reason. + - `more_info` - (string) Link to documentation about this status reason +- `zone` - (String) The globally unique name for this zone. + +## References + +* [IBM Cloud Terraform Docs](https://cloud.ibm.com/docs/vpc?topic=vpc-provisioning-reserved-capacity-vpc&interface=ui +https://cloud.ibm.com/docs/vpc?topic=vpc-about-reserved-virtual-servers-vpc) \ No newline at end of file diff --git a/website/docs/d/is_reservations.html.markdown b/website/docs/d/is_reservations.html.markdown new file mode 100644 index 0000000000..9486d7b4f0 --- /dev/null +++ b/website/docs/d/is_reservations.html.markdown @@ -0,0 +1,156 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : Reservations" +description: |- + Manages IBM Cloud infrastructure reservations. +--- + +# ibm_is_reservations +Retrieve information of an existing reservations as a read only data source. + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "us-south" +} +``` + +## Example usage + +```terraform + +data "ibm_resource_group" "example" { + name = "Default" +} + +resource "ibm_is_reservation" "res" { + capacity { + total = 5 + } + committed_use { + term = "one_year" + } + profile { + name = "ba2-2x8" + resource_type = "instance_profile" + } + zone = "us-east-3" + name = "reservation-name" +} +data "ibm_is_reservations" "example1" { +} + +data "ibm_is_reservations" "example2" { + resource_group = data.ibm_resource_group.example.id +} + +data "ibm_is_reservations" "example3" { + zone_name = ibm_is_reservation.res.zone +} +``` + +## Argument reference + +Review the argument references that you can specify for your data source. + +* `resource_group` - (Optional, string) The id of the resource group. +* `zone_name` - (Optional, string) The name of the zone. + +## Attribute reference +You can access the following attribute references after your data source is created. + +- `reservations` - (List) Collection of reservations + +Nested scheme for `reservations`: + - `affinity_policy` - (String) The affinity policy to use for this reservation. + - `capacity` - (List) The capacity configuration for this reservation. If absent, this reservation has no assigned capacity. + + Nested scheme for `capacity`: + - `allocated` - (Integer) The amount allocated to this capacity reservation. + - `available` - (Integer) The amount of this capacity reservation available for new attachments. + - `status` - (String) The status of the capacity reservation. + + ->**status** +
• allocating: The capacity reservation is being allocated for use +
• allocated: The total capacity of the reservation has been allocated for use +
• degraded: The capacity reservation has been allocated for use, but some of the capacity is not available +
• unallocated: The capacity reservation is not allocated for use + - `total` - (Integer) The total amount of this capacity reservation. + - `used` - (Integer) The amount of this capacity reservation used by existing attachments. + - `committed_use` - (List) The committed use configuration for this reservation. If absent, this reservation has no commitment for use. + + Nested scheme for `committed_use`: + - `expiration_at` - (Timestamp) The expiration date and time for this committed use reservation. + - `expiration_policy` - (String) The policy to apply when the committed use term expires. + + ->**expiration_policy** +
• release: Release any available capacity and let the reservation expire +
• renew: Renew for another term, provided the term remains listed in the reservation_terms for the profile. Otherwise, let the reservation expire + - `term` - (String) The term for this committed use reservation. + + ->**term** +
• one_year: 1 year +
• three_year: 3 years + - `created_at` - (Timestamp) The date and time that the reservation was created. + - `crn` - (String) The CRN for this reservation. + - `href` - (String) The URL for this reservation. + - `id` - (String) The unique identifier for this reservation. + - `lifecycle_state` - (String) The lifecycle state of this reservation. + + ->**lifecycle_state** +
• deleting +
• failed +
• pending +
• stable +
• suspended +
• updating +
• waiting + - `profile` - (List) The virtual server instance profile this reservation. + + Nested scheme for `profile`: + - `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 + + ->**resource_type** +
• instance_profile + - `resource_group` - (List) The resource group for this reservation. + + Nested scheme 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. + + ->**resource_type** +
• reservation + - `status` - (String) The status of the reservation. + + ->**status** +
• activating +
• active +
• deactivating +
• expired +
• failed +
• inactive + - `status_reasons` - (List) The reasons for the current status (if any). + + Nested scheme for `status_reasons`: + - `code` - (String) A snake case string succinctly identifying the status reason. + + ->**code** +
• cannot_activate_no_capacity_available +
• cannot_renew_unsupported_profile_term + - `message` - (String) An explanation of the status reason. + - `more_info` - (string) Link to documentation about this status reason + - `zone` - (String) The globally unique name for this zone. + +## References + +* [IBM Cloud Terraform Docs](https://cloud.ibm.com/docs/vpc?topic=vpc-provisioning-reserved-capacity-vpc&interface=ui +https://cloud.ibm.com/docs/vpc?topic=vpc-about-reserved-virtual-servers-vpc) \ No newline at end of file diff --git a/website/docs/d/is_share_mount_target.html.markdown b/website/docs/d/is_share_mount_target.html.markdown index 2b67534486..00cb4fab2f 100644 --- a/website/docs/d/is_share_mount_target.html.markdown +++ b/website/docs/d/is_share_mount_target.html.markdown @@ -47,39 +47,41 @@ The following arguments are supported: The following attributes are exported: -- `access_control_mode` - (String) The access control mode for the share. -- `created_at` - (String) The date and time that the share target was created. -- `href` - (String) The URL for this share target. -- `lifecycle_state` - (String) The lifecycle state of the mount target. -- `mount_path` - (String) The mount path for the share. The server component of the mount path may be either an IP address or a fully qualified domain name. - - This property will be absent if the lifecycle_state of the mount target is 'pending', failed, or deleting. - - -> **If the share's access_control_mode is:** - • security_group: The IP address used in the mount path is the primary_ip address of the virtual network interface for this share mount target.
- • vpc: The fully-qualified domain name used in the mount path is an address that resolves to the share mount target.
+- `created_at` - The date and time that the share target was created. +- `href` - The URL for this share target. +- `lifecycle_state` - The lifecycle state of the mount target. +- `mount_path` - The mount path for the share.The IP addresses used in the mount path are currently within the IBM services IP range, but are expected to change to be within one of the VPC's subnets in the future. - `name` - The user-defined name for this share target. -- `resource_type` - (String) The type of resource referenced. +- `resource_type` - The type of resource referenced. - `transit_encryption` - (String) The transit encryption mode for this share target. -- `vpc` - (List) The VPC to which this share target is allowing to mount the file share. Nested `vpc` blocks have the following structure: - - `crn` - (String) The CRN for this VPC. - - `deleted` - (String) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. Nested `deleted` blocks have the following structure: - - `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 unique user-defined name for this VPC. - - `resource_type` - (String) The resource type. -- `subnet` - (List) The subnet of the virtual network interface for the share mount target. Nested `subnet` blocks have the following structure: - - `crn` - (String) The CRN for this subnet. - - `deleted` - (String) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. Nested `deleted` blocks have the following structure: - - `more_info` - (String) Link to documentation about deleted resources. - - `href` - (String) The URL for this subnet. - - `id` - (String) The unique identifier for this subnet. - - `name` - (String) The unique user-defined name for this subnet. - - `resource_type` - (String) The resource type. -- `virtual_network_interface` - (List) The virtual network interface for this file share mount target.. Nested `virtual_network_interface` blocks have the following structure: - - `crn` - (String) The CRN for this virtual network interface. - - `href` - (String) The URL for this virtual network interface. - - `id` - (String) The unique identifier for this virtual network interface. - - `name` - (String) The unique user-defined name for this virtual network interface. - - `resource_type` - (String) The resource type. +- `vpc` - The VPC to which this share target is allowing to mount the file share. Nested `vpc` blocks have the following structure: + - `crn` - The CRN for this VPC. + - `deleted` - If present, this property indicates the referenced resource has been deleted and providessome supplementary information. Nested `deleted` blocks have the following structure: + - `more_info` - Link to documentation about deleted resources. + - `href` - The URL for this VPC. + - `id` - The unique identifier for this VPC. + - `name` - The unique user-defined name for this VPC. + - `resource_type` - The resource type. +- `primary_ip` - The primary IP address of the virtual network interface for the share mount target. Nested `primary_ip` blocks have the following structure: + - `address` - The IP address. + - `deleted` - If present, this property indicates the referenced resource has been deleted and providessome supplementary information. Nested `deleted` blocks have the following structure: + - `more_info` - Link to documentation about deleted resources. + - `href` - The URL for this reserved IP. + - `id` - The unique identifier for this reserved IP. + - `name` - The name for this reserved IP. The name is unique across all reserved IPs in a subnet. + - `resource_type` - The resource type. +- `subnet` - The subnet of the virtual network interface for the share mount target. Nested `vpc` blocks have the following structure: + - `crn` - The CRN for this subnet. + - `deleted` - If present, this property indicates the referenced resource has been deleted and providessome supplementary information. Nested `deleted` blocks have the following structure: + - `more_info` - Link to documentation about deleted resources. + - `href` - The URL for this subnet. + - `id` - The unique identifier for this subnet. + - `name` - The unique user-defined name for this subnet. + - `resource_type` - The resource type. +- `virtual_network_interface` - The virtual network interface for this file share mount target.. Nested `subnet` blocks have the following structure: + - `crn` - The CRN for this virtual network interface. + - `href` - The URL for this virtual network interface. + - `id` - The unique identifier for this virtual network interface. + - `name` - The unique user-defined name for this virtual network interface. + - `resource_type` - The resource type. + diff --git a/website/docs/d/is_share_mount_targets.html.markdown b/website/docs/d/is_share_mount_targets.html.markdown index 17d59f25f4..2cb13d4b10 100644 --- a/website/docs/d/is_share_mount_targets.html.markdown +++ b/website/docs/d/is_share_mount_targets.html.markdown @@ -40,41 +40,42 @@ The following attributes are exported: - `id` - The unique identifier of the ShareTargetCollection. - `mount_targets` - Collection of share targets. Nested `targets` blocks have the following structure: - - `access_control_mode` - (String) The access control mode for the share. - - `created_at` - (String) The date and time that the share target was created. - - `href` - (String) The URL for this share target. - - `id` - (String) The unique identifier for this share target. - - `lifecycle_state` - (String) The lifecycle state of the mount target. - - `mount_path` - (String) The mount path for the share. The server component of the mount path may be either an IP address or a fully qualified domain name. - - This property will be absent if the lifecycle_state of the mount target is 'pending', failed, or deleting. - - -> **If the share's access_control_mode is:** - • security_group: The IP address used in the mount path is the primary_ip address of the virtual network interface for this share mount target.
- • vpc: The fully-qualified domain name used in the mount path is an address that resolves to the share mount target.
- - `name` - (String) The user-defined name for this share target. - - `resource_type` - (String) The type of resource referenced. + - `created_at` - The date and time that the share target was created. + - `href` - The URL for this share target. + - `id` - The unique identifier for this share target. + - `lifecycle_state` - The lifecycle state of the mount target. + - `mount_path` - The mount path for the share.The IP addresses used in the mount path are currently within the IBM services IP range, but are expected to change to be within one of the VPC's subnets in the future. + - `name` - The user-defined name for this share target. + - `resource_type` - The type of resource referenced. - `transit_encryption` - (String) The transit encryption mode for this share target. - `vpc` - The VPC to which this share target is allowing to mount the file share. Nested `vpc` blocks have the following structure: - - `crn` - (String) The CRN for this VPC. - - `deleted` - (String) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. Nested `deleted` blocks have the following structure: - - `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 unique user-defined name for this VPC. - - `resource_type` - (String) The resource type. - - `subnet` - (List) The subnet of the virtual network interface for the share mount target. Nested `subnet` blocks have the following structure: - - `crn` - (String) The CRN for this subnet. - - `deleted` - (String) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. Nested `deleted` blocks have the following structure: - - `more_info` - (String) Link to documentation about deleted resources. - - `href` - (String) The URL for this subnet. - - `id` - (String) The unique identifier for this subnet. - - `name` - (String) The unique user-defined name for this subnet. - - `resource_type` - (String) The resource type. - - `virtual_network_interface` - (List) The virtual network interface for this file share mount target.. Nested `virtual_network_interface` blocks have the following structure: - - `crn` - (String) The CRN for this virtual network interface. - - `href` - (String) The URL for this virtual network interface. - - `id` - (String) The unique identifier for this virtual network interface. - - `name` - (String) The unique user-defined name for this virtual network interface. - - `resource_type` - (String) The resource type. + - `crn` - The CRN for this VPC. + - `deleted` - If present, this property indicates the referenced resource has been deleted and providessome supplementary information. Nested `deleted` blocks have the following structure: + - `more_info` - Link to documentation about deleted resources. + - `href` - The URL for this VPC. + - `id` - The unique identifier for this VPC. + - `name` - The unique user-defined name for this VPC. + - `resource_type` - The resource type. + - `primary_ip` - The primary IP address of the virtual network interface for the share mount target. Nested `primary_ip` blocks have the following structure: + - `address` - The IP address. + - `deleted` - If present, this property indicates the referenced resource has been deleted and providessome supplementary information. Nested `deleted` blocks have the following structure: + - `more_info` - Link to documentation about deleted resources. + - `href` - The URL for this reserved IP. + - `id` - The unique identifier for this reserved IP. + - `name` - The name for this reserved IP. The name is unique across all reserved IPs in a subnet. + - `resource_type` - The resource type. + - `subnet` - The subnet of the virtual network interface for the share mount target. Nested `vpc` blocks have the following structure: + - `crn` - The CRN for this subnet. + - `deleted` - If present, this property indicates the referenced resource has been deleted and providessome supplementary information. Nested `deleted` blocks have the following structure: + - `more_info` - Link to documentation about deleted resources. + - `href` - The URL for this subnet. + - `id` - The unique identifier for this subnet. + - `name` - The unique user-defined name for this subnet. + - `resource_type` - The resource type. + - `virtual_network_interface` - The virtual network interface for this file share mount target.. Nested `subnet` blocks have the following structure: + - `crn` - The CRN for this virtual network interface. + - `href` - The URL for this virtual network interface. + - `id` - The unique identifier for this virtual network interface. + - `name` - The unique user-defined name for this virtual network interface. + - `resource_type` - The resource type. diff --git a/website/docs/d/is_source_share.html.markdown b/website/docs/d/is_source_share.html.markdown index 93bb3ea9f7..6802d073b0 100644 --- a/website/docs/d/is_source_share.html.markdown +++ b/website/docs/d/is_source_share.html.markdown @@ -1,14 +1,14 @@ --- layout: "ibm" -page_title: "IBM : is_share" +page_title: "IBM : is_source_share" description: |- Get information about Share subcategory: "VPC infrastructure" --- -# ibm\_is_share +# ibm_is_source_share -Provides a read-only data source for Share. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. +Provides a read-only data source for the source share. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. ## Example Usage diff --git a/website/docs/d/is_subnet_reserved_ip.html.markdown b/website/docs/d/is_subnet_reserved_ip.html.markdown index 1287448158..8d3d27dbd6 100644 --- a/website/docs/d/is_subnet_reserved_ip.html.markdown +++ b/website/docs/d/is_subnet_reserved_ip.html.markdown @@ -50,3 +50,15 @@ In addition to all argument reference list, you can access the following attribu - `subnet` - (String) The ID of the subnet for the reserved IP. - `target` - (String) The ID of the target for the reserved IP. - `target_crn` - (String) The crn of the target for the reserved IP. +- `target_reference` - (List) The target this reserved IP is bound to. If absent, this reserved IP is provider-owned or unbound. + + Nested schema for **target_reference**: + - `crn` - (String) The CRN for this endpoint gateway. + - `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 endpoint gateway. + - `id` - (String) The unique identifier for this endpoint gateway. + - `name` - (String) The name for this endpoint gateway. The name is unique across all endpoint gateways in the VPC. + - `resource_type` - (String) The resource type. diff --git a/website/docs/d/is_subnet_reserved_ips.html.markdown b/website/docs/d/is_subnet_reserved_ips.html.markdown index 5df436b48d..4f60192d89 100644 --- a/website/docs/d/is_subnet_reserved_ips.html.markdown +++ b/website/docs/d/is_subnet_reserved_ips.html.markdown @@ -50,5 +50,16 @@ In addition to the argument reference list, you can access the following attribu - `resource_type` - (String) The resource type. - `target` - (String) The ID of the target for the reserved IP. - `target_crn` - (String) The crn of the target for the reserved IP. -- `total_count` - (String) The total number of resources across all pages. + - `target_reference` - (List) The target this reserved IP is bound to. If absent, this reserved IP is provider-owned or unbound. + + Nested schema for **target_reference**: + - `crn` - (String) The CRN for this endpoint gateway. + - `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 endpoint gateway. + - `id` - (String) The unique identifier for this endpoint gateway. + - `name` - (String) The name for this endpoint gateway. The name is unique across all endpoint gateways in the VPC. + - `resource_type` - (String) The resource type. +- `total_count` - (String) The total number of resources across all pages. \ No newline at end of file diff --git a/website/docs/d/is_virtual_network_interface.html.markdown b/website/docs/d/is_virtual_network_interface.html.markdown index 9f67e78b13..7dd5cd5ace 100644 --- a/website/docs/d/is_virtual_network_interface.html.markdown +++ b/website/docs/d/is_virtual_network_interface.html.markdown @@ -57,12 +57,27 @@ Review the argument reference that you can specify for your data source. In addition to all argument references listed, you can access the following attribute references after your data source is created. +- `access_tags` - (Array of Strings) Access management tags associated for the virtual network interface. +- `allow_ip_spoofing` - (Boolean) Indicates whether source IP spoofing is allowed on this interface. If `false`, source IP spoofing is prevented on this interface. If `true`, source IP spoofing is allowed on this interface. - `auto_delete` - (Boolean) Indicates whether this virtual network interface will be automatically deleted when`target` is deleted. - `created_at` - (String) The date and time that the virtual network interface was created. - `crn` - (String) The CRN for this virtual network interface. +- `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.- `allow_ip_spoofing` must be `false`.- If the virtual network interface is attached: - The target `resource_type` must be `bare_metal_server_network_attachment`. - The target `interface_type` must not be `hipersocket`. - `href` - (String) The URL for this virtual network interface. - `id` - The unique identifier of the VirtualNetworkInterface. +- `ips` - (List) The reserved IPs bound to this virtual network interface.May be empty when `lifecycle_state` is `pending`. + Nested schema for **ips**: + - `address` - (String) The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `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 reserved IP. + - `id` - (String) The unique identifier for this reserved IP. + - `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. + - `lifecycle_state` - (String) The lifecycle state of the virtual network interface. +- `mac_address` - (String) The MAC address of the virtual network interface. May be absent if `lifecycle_state` is `pending`. - `name` - (String) The name for this virtual network interface. The name is unique across all virtual network interfaces in the VPC. - `primary_ip` - (List) The reserved IP for this virtual network interface.May be absent when `lifecycle_state` is `pending`. Nested scheme for **primary_ip**: @@ -99,6 +114,7 @@ In addition to all argument references listed, you can access the following attr - `id` - (String) The unique identifier for this subnet. - `name` - (String) The name for this subnet. The name is unique across all subnets in the VPC. - `resource_type` - (String) The resource type. +- `tags` - (Array of Strings) The tags associated with the virtual netork interface. - `target` - (List) The target of this virtual network interface.If absent, this virtual network interface is not attached to a target. Nested scheme for **target**: - `deleted` - (List) If present, this property indicates the referenced resource has been deleted, and providessome supplementary information. diff --git a/website/docs/d/is_virtual_network_interface_floating_ip.html.markdown b/website/docs/d/is_virtual_network_interface_floating_ip.html.markdown new file mode 100644 index 0000000000..ed4a5111c8 --- /dev/null +++ b/website/docs/d/is_virtual_network_interface_floating_ip.html.markdown @@ -0,0 +1,41 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_virtual_network_interface_floating_ip" +description: |- + Get information about Virtual Network Interface Floating IP. +subcategory: "Virtual Private Cloud API" +--- + +# ibm_is_virtual_network_interface_floating_ip + +Provides a read-only data source to retrieve information about a Virtual Network Interface Floating IP. You can then reference the fields of the data source in other resources within the same configuration by using interpolation syntax. + +## Example Usage + +```terraform +data "ibm_is_virtual_network_interface_floating_ip" "vni_fip" { + virtual_network_interface = + floating_ip = +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +- `virtual_network_interface` - (Required, String) The virtual network interface identifier +- `floating_ip` - (Required, String) The floating IP identifier + +## Attribute Reference + +After your data source is created, you can read values from the following attributes. + + +- `id` - The unique identifier of the FloatingIP. +- `address` - (String) The globally unique IP address. +- `crn` - (String) The CRN for this floating IP. +- `href` - (String) The URL for this floating IP. +- `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + Nested scheme for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. +- `name` - (String) The name for this floating IP. The name is unique across all floating IPs in the region. diff --git a/website/docs/d/is_virtual_network_interface_floating_ips.html.markdown b/website/docs/d/is_virtual_network_interface_floating_ips.html.markdown new file mode 100644 index 0000000000..9186b403cb --- /dev/null +++ b/website/docs/d/is_virtual_network_interface_floating_ips.html.markdown @@ -0,0 +1,42 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_virtual_network_interface_floating_ips" +description: |- + List information about Virtual Network Interface Floating IPs. +subcategory: "Virtual Private Cloud API" +--- + +# ibm_is_virtual_network_interface_floating_ips + +Provides a read-only data source to retrieve information about a list of Virtual Network Interface Floating IPs. You can then reference the fields of the data source in other resources within the same configuration by using interpolation syntax. + +## Example Usage + +```terraform +data "ibm_is_virtual_network_interface_floating_ips" "vni_fips" { + virtual_network_interface = +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +- `virtual_network_interface` - (Required, String) The virtual network interface identifier + +## Attribute Reference + +After your data source is created, you can read values from the following attributes. +- `floating_ips` - (List) Lists all floatings ips in the virtual network interface. + + Nested scheme for `floating_ips`: + - `id` - The unique identifier of the FloatingIP + - `address` - (String) The globally unique IP address. + - `crn` - (String) The CRN for this floating IP. + - `href` - (String) The URL for this floating IP. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + Nested scheme for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - `name` - (String) The name for this floating IP. The name is unique across all floating IPs in the region. + + diff --git a/website/docs/d/is_virtual_network_interface_ip.html.markdown b/website/docs/d/is_virtual_network_interface_ip.html.markdown new file mode 100644 index 0000000000..c9eb2b1a07 --- /dev/null +++ b/website/docs/d/is_virtual_network_interface_ip.html.markdown @@ -0,0 +1,40 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_virtual_network_interface_ip" +description: |- + Get information about Virtual Network Interface Reserved Ip +subcategory: "Virtual Private Cloud API" +--- + +# ibm_is_virtual_network_interface_ip + +Provides a read-only data source to retrieve information about a Virtual Network Interface Reserved Ip. 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_virtual_network_interface_ip" "is_reserved_ip" { + reserved_ip = "id" + virtual_network_interface = ibm_is_virtual_network_interface_ip.is_reserved_ip.subnet_id +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +- `reserved_ip` - (Required, Forces new resource, String) The reserved IP identifier. +- `virtual_network_interface` - (Required, Forces new resource, String) The virtual network interface identifier. + +## Attribute Reference + +After your data source is created, you can read values from the following attributes. + +- `address` - (String) The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. +- `href` - (String) The URL for this reserved IP. +- `id` - (String) The unique identifier for this reserved IP. +- `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + Nested scheme for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. +- `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. diff --git a/website/docs/d/is_virtual_network_interface_ips.html.markdown b/website/docs/d/is_virtual_network_interface_ips.html.markdown new file mode 100644 index 0000000000..913ba86a63 --- /dev/null +++ b/website/docs/d/is_virtual_network_interface_ips.html.markdown @@ -0,0 +1,43 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_virtual_network_interface_ips" +description: |- + Get information about ReservedIP Collection of a Virtual Network Interface +subcategory: "Virtual Private Cloud API" +--- + +# ibm_is_virtual_network_interface_ips + +Provides a read-only data source to retrieve information about a ReservedIP Collection bound to a virtual network interface. You can then reference the fields of the data source in other resources within the same configuration by using interpolation syntax. + +## Example Usage + +```terraform +data "ibm_is_virtual_network_interface_ips" "is_reserved_ips" { + virtual_network_interface = ibm_is_virtual_network_interface.testacc_vni.id +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +- `virtual_network_interface` - (Required, Forces new resource, String) The virtual 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 virtual network interface reserved IP Collection. + +- `reserved_ips` - (List) Collection of reserved IPs in this subnet. + Nested schema for **reserved_ips**: + - `address` - (String) The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `href` - (String) The URL for this reserved IP. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + Nested scheme for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - `id` - (String) The unique identifier for this reserved IP. + - `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. + diff --git a/website/docs/d/is_virtual_network_interfaces.html.markdown b/website/docs/d/is_virtual_network_interfaces.html.markdown index 93fb780ef6..21a80e52ca 100644 --- a/website/docs/d/is_virtual_network_interfaces.html.markdown +++ b/website/docs/d/is_virtual_network_interfaces.html.markdown @@ -20,16 +20,32 @@ data "ibm_is_virtual_network_interfaces" "example" { ## Attribute Reference +- `resource_group` - (Optional, String) The ID of the Resource group these virtual network interfaces belong to. + In addition to all argument references listed, you can access the following attribute references after your data source is created. - `virtual_network_interfaces` - (List) Collection of virtual network interfaces. Nested scheme for **virtual_network_interfaces**: + - `access_tags` - (Array of Strings) Access management tags associated for the virtual network interface. + - `allow_ip_spoofing` - (Boolean) Indicates whether source IP spoofing is allowed on this interface. If `false`, source IP spoofing is prevented on this interface. If `true`, source IP spoofing is allowed on this interface. - `auto_delete` - (Boolean) Indicates whether this virtual network interface will be automatically deleted when`target` is deleted. - `created_at` - (String) The date and time that the virtual network interface was created. - `crn` - (String) The CRN for this virtual network interface. + - `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.- `allow_ip_spoofing` must be `false`.- If the virtual network interface is attached: - The target `resource_type` must be `bare_metal_server_network_attachment`. - The target `interface_type` must not be `hipersocket`. - `href` - (String) The URL for this virtual network interface. - `id` - (String) The unique identifier for this virtual network interface. + - `ips` - (List) The reserved IPs bound to this virtual network interface.May be empty when `lifecycle_state` is `pending`. + Nested schema for **ips**: + - `address` - (String) The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `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 reserved IP. + - `id` - (String) The unique identifier for this reserved IP. + - `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. - `lifecycle_state` - (String) The lifecycle state of the virtual network interface. + - `mac_address` - (String) The MAC address of the virtual network interface. May be absent if `lifecycle_state` is `pending`. - `name` - (String) The name for this virtual network interface. The name is unique across all virtual network interfaces in the VPC. - `primary_ip` - (List) The reserved IP for this virtual network interface.May be absent when `lifecycle_state` is `pending`. Nested scheme for **primary_ip**: @@ -66,6 +82,7 @@ In addition to all argument references listed, you can access the following attr - `id` - (String) The unique identifier for this subnet. - `name` - (String) The name for this subnet. The name is unique across all subnets in the VPC. - `resource_type` - (String) The resource type. + - `tags` - (Array of Strings) The tags associated with the virtual netork interface. - `target` - (List) The target of this virtual network interface.If absent, this virtual network interface is not attached to a target. Nested scheme for **target**: - `deleted` - (List) If present, this property indicates the referenced resource has been deleted, and providessome supplementary information. diff --git a/website/docs/d/is_vpn_gateway.html.markdown b/website/docs/d/is_vpn_gateway.html.markdown index da67f40b90..12ee7f6fcf 100644 --- a/website/docs/d/is_vpn_gateway.html.markdown +++ b/website/docs/d/is_vpn_gateway.html.markdown @@ -65,7 +65,6 @@ In addition to all argument references listed, you can access the following attr - `private_ip_address` - (String) The private IP address assigned to the VPN gateway member. This property will be present only when the VPN gateway status is `available`. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. Same as `primary_ip.0.address` - `public_ip_address` - (String) The public IP address assigned to the VPN gateway member. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. - `role` - (String) The high availability role assigned to the VPN gateway member. - - `status` - (String) The status of the VPN gateway member. - `mode` - (String) Route mode VPN gateway. @@ -79,7 +78,6 @@ In addition to all argument references listed, you can access the following attr - `resource_type` - (String) The resource type. -- `status` - (String) The status of the VPN gateway. - `health_reasons` - (List) The reasons for the current health_state (if any). Nested scheme for `health_reasons`: diff --git a/website/docs/d/is_vpn_gateways.html.markdown b/website/docs/d/is_vpn_gateways.html.markdown index 8c7a66df30..457edbcfc7 100644 --- a/website/docs/d/is_vpn_gateways.html.markdown +++ b/website/docs/d/is_vpn_gateways.html.markdown @@ -56,11 +56,9 @@ In addition to all argument reference list, you can access the following attribu Nested scheme for `private_ip`: - `address` - (String) The IP address. If the address has not yet been selected, the value will be 0.0.0.0. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. - `private_address` - (String) The private IP address assigned to the VPN gateway member. Same as `private_ip.0.address`.
- - `status` - (String) The status of the VPN gateway member. - `resource_type` - (String) The resource type, supported value is `vpn_gateway`. - - `status` - (String) The status of the VPN gateway, supported values are **available**, **deleting**, **failed**, **pending**. - `health_reasons` - (List) The reasons for the current health_state (if any). Nested scheme for `health_reasons`: diff --git a/website/docs/d/pi_catalog_images.html.markdown b/website/docs/d/pi_catalog_images.html.markdown index 8693c9e211..a40655476a 100644 --- a/website/docs/d/pi_catalog_images.html.markdown +++ b/website/docs/d/pi_catalog_images.html.markdown @@ -10,7 +10,7 @@ description: |- Retrieve the details of an image that you can use in your Power Systems Virtual Server instance for copying into IBM Cloud instances. For more information, about catalog images, see [provisioning a virtual server instance from a third-party image](https://cloud.ibm.com/docs/virtual-servers?topic=virtual-servers-ordering-3P). ## Example usage -The following example shows how to retrieve information by using `ibm_pi_catalog_images`. +The following example shows how to retrieve information using `ibm_pi_catalog_images`. ```terraform data "ibm_pi_catalog_images" "ds_images" { @@ -19,13 +19,12 @@ data "ibm_pi_catalog_images" "ds_images" { ``` **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: +- 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" @@ -46,18 +45,19 @@ In addition to the argument reference list, you can access the following attribu - `images`- (List) Lists all the images in the IBM Power Virtual Server Cloud. Nested scheme for `images`: - - `architecture` - (String) Architecture. - - `creation_date` - (String) The creation date of an image. + - `architecture` - (String) The CPU architecture that the image is designed for. + - `container_format` - (String) The container format. + - `creation_date` - (String) Date of image creation. - `description` - (String) The description of an image. - `disk_format` - (String) The disk format. - `endianness` - (String) The `Endianness` order. - - `hypervisor_type` - (String) Hypervisor type. - `href` - (String) The `href` of an image. + - `hypervisor_type` - (String) Hypervisor type. - `image_id` - (String) The unique identifier of an image. - - `image_type` - (String) The type of the format. + - `image_type` - (String) The identifier of this image type. - `last_update_date` - (String) The last updated date of an image. - `name` - (String) The name of the image. - `operating_system` - (String) Operating System. + - `state` - (String) The state of an Operating System. - `storage_pool` - (String) Storage pool where image resides. - `storage_type` - (String) The storage type of an image. - - `state` - (String) The state of an Operating System. diff --git a/website/docs/d/pi_cloud_connection.html.markdown b/website/docs/d/pi_cloud_connection.html.markdown index ca42eb4117..2e6de4d4bd 100644 --- a/website/docs/d/pi_cloud_connection.html.markdown +++ b/website/docs/d/pi_cloud_connection.html.markdown @@ -7,11 +7,9 @@ description: |- --- # ibm_pi_cloud_connection - Retrieve information about an existing IBM Cloud Power Virtual Server Cloud cloud connection. 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 - ```terraform data "ibm_pi_cloud_connection" "example" { pi_cloud_connection_name = "test_cloud_connection" @@ -20,15 +18,12 @@ data "ibm_pi_cloud_connection" "example" { ``` **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: - +Example usage: ```terraform provider "ibm" { region = "lon" @@ -37,28 +32,26 @@ data "ibm_pi_cloud_connection" "example" { ``` ## 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. - `pi_cloud_connection_name` - (Required, String) The cloud connection name to be used. ## 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 cloud connection. -- `classic_enabled` - (Bool) Is classic endpoint destination enabled? +- `classic_enabled` - (Boolean) Enable classic endpoint destination. - `connection_mode` - (String) Type of service the gateway is attached to. -- `global_routing` - (String) Is global routing enabled for this cloud connection. -- `gre_destination_address` - (String) The GRE destination IP address. -- `gre_source_address` - (String) The GRE auto-assigned source IP address. +- `global_routing` - (String) Enable global routing for this cloud connection. +- `gre_destination_address` - (String) GRE destination IP address. +- `gre_source_address` - (String) GRE auto-assigned source IP address. +- `id` - (String) The unique identifier of the cloud connection. - `ibm_ip_address` - (String) The IBM IP address. -- `metered` - (String) Is metered enabled for this cloud connection. -- `networks` - (Set of String) Set of Networks attached to this cloud connection. +- `metered` - (String) Enable metering for this cloud connection. +- `networks` - (Set) Set of Networks attached to this cloud connection. - `port` - (String) Port. - `speed` - (Integer) Speed of the cloud connection (speed in megabits per second). - `status` - (String) Link status. - `user_ip_address` - (String) User IP address. -- `vpc_crns` - (Set of String) Set of VPCs attached to this cloud connection. -- `vpc_enabled` - (Bool) Is VPC enabled for this cloud connection? +- `vpc_crns` - (Set) Set of VPCs attached to this cloud connection. +- `vpc_enabled` - (Boolean) Enable VPC for this cloud connection. diff --git a/website/docs/d/pi_cloud_connections.html.markdown b/website/docs/d/pi_cloud_connections.html.markdown index 8925fd81e6..0ab04e36da 100644 --- a/website/docs/d/pi_cloud_connections.html.markdown +++ b/website/docs/d/pi_cloud_connections.html.markdown @@ -7,11 +7,9 @@ description: |- --- # ibm_pi_cloud_connections - Retrieve information about all cloud connections as a read-only data source. 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 - ```terraform data "ibm_pi_cloud_connections" "example" { pi_cloud_instance_id = "" @@ -19,15 +17,13 @@ data "ibm_pi_cloud_connections" "example" { ``` **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: - +Example usage: ```terraform provider "ibm" { region = "lon" @@ -36,32 +32,29 @@ data "ibm_pi_cloud_connections" "example" { ``` ## 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. - `connections` - (List) List of all the Cloud Connections. Nested scheme for `connections`: - - - `classic_enabled` - (Bool) Is Classic endpoint destination enabled. + - `classic_enabled` - (Boolean) Enable classic endpoint destination. - `cloud_connection_id` - (String) The unique identifier of the cloud connection. - - `global_routing` - (String) Is global routing enabled for this cloud connection. + - `connection_mode` - (String) Type of service the gateway is attached to. + - `global_routing` - (String) Enable global routing for this cloud connection. - `gre_destination_address` - (String) GRE destination IP address. - `gre_source_address` - (String) GRE auto-assigned source IP address. - `ibm_ip_address` - (String) IBM IP address. - - `metered` - (String) Is metered enabled for this cloud connection. + - `metered` - (String) Enable metering for this cloud connection. - `name` - (String) Name of the cloud connection. - - `networks` - (Set of String) Set of Networks attached to this cloud connection. + - `networks` - (Set) Set of Networks attached to this cloud connection. - `port` - (String) Port. - `speed` - (Integer) Speed of the cloud connection (speed in megabits per second). - `status` - (String) Link status. - `user_ip_address` - (String) User IP address. - - `vpc_crns` - (Set of String) Set of VPCs attached to this cloud connection. - - `vpc_enabled` - (Bool) Is VPC enabled for this cloud connection. - - `connection_mode` - (String) Type of service the gateway is attached to. + - `vpc_crns` - (Set) Set of VPCs attached to this cloud connection. + - `vpc_enabled` - (Boolean) Enable VPC for this cloud connection. diff --git a/website/docs/d/pi_cloud_instance.html.markdown b/website/docs/d/pi_cloud_instance.html.markdown index 5e65926b84..32dcbb43ba 100644 --- a/website/docs/d/pi_cloud_instance.html.markdown +++ b/website/docs/d/pi_cloud_instance.html.markdown @@ -10,21 +10,19 @@ description: |- Retrieve information about an existing IBM Power Virtual Server Cloud Instance as a read-only data source. 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 - ```terraform data "ibm_pi_cloud_instance" "ds_cloud_instance" { 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` +**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" @@ -46,7 +44,7 @@ In addition to the argument reference list, you can access the following attribu - `pvm_instances` - (List) PVM instances owned by the Cloud Instance. Nested scheme for `pvm_instances`: - - `creation_date` - (String) Date/Time of PVM creation. + - `creation_date` - (String) Date of PVM instance creation. - `href` - (String) Link to Cloud Instance resource. - `id` - (String) PVM Instance ID. - `name` - (String) Name of the server. @@ -59,4 +57,3 @@ In addition to the argument reference list, you can access the following attribu - `total_processors_consumed` - (String) The total processors consumed by this service instance. - `total_ssd_storage_consumed` - (String) The total SSD Storage consumed by this service instance. - `total_standard_storage_consumed` - (String) The total Standard Storage consumed by this service instance. - diff --git a/website/docs/d/pi_console_languages.html.markdown b/website/docs/d/pi_console_languages.html.markdown index d5f7f36afd..e679fedd62 100644 --- a/website/docs/d/pi_console_languages.html.markdown +++ b/website/docs/d/pi_console_languages.html.markdown @@ -1,5 +1,4 @@ --- - subcategory: "Power Systems" layout: "ibm" page_title: "IBM: pi_console_languages" @@ -8,11 +7,9 @@ description: |- --- # ibm_pi_console_languages - Retrieve information about all the available Console Languages for an Instance. For more information, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). ## Example usage - ```terraform data "ibm_pi_console_languages" "example" { pi_cloud_instance_id = "" @@ -21,14 +18,12 @@ data "ibm_pi_console_languages" "example" { ``` **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` +- 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" @@ -37,14 +32,12 @@ Example usage: ``` ## 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. - `pi_instance_name` - (Required, String) The unique identifier or name of the instance. ## Attribute reference - In addition to all argument reference list, you can access the following attribute references after your data source is created. - `console_languages` - (List) List of all the Console Languages. diff --git a/website/docs/d/pi_datacenter.html.markdown b/website/docs/d/pi_datacenter.html.markdown index 8076d2188f..9ce0e5a12a 100644 --- a/website/docs/d/pi_datacenter.html.markdown +++ b/website/docs/d/pi_datacenter.html.markdown @@ -1,5 +1,4 @@ --- - subcategory: "Power Systems" layout: "ibm" page_title: "IBM: pi_datacenter" @@ -8,26 +7,22 @@ description: |- --- # ibm_pi_datacenter - Retrieve information about a Power Systems Datacenter. ## Example usage - ```terraform data "ibm_pi_datacenter" "datacenter" { pi_datacenter_zone= "dal12" } ``` -## 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" @@ -36,13 +31,11 @@ Example usage: ``` ## Argument reference - Review the argument references that you can specify for your data source. - `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 - In addition to all argument reference list, you can access the following attribute references after your data source is created. - `pi_datacenter_capabilities` - (Map) Datacenter Capabilities. Capabilities are `true` or `false`. @@ -50,11 +43,12 @@ In addition to all argument reference list, you can access the following attribu Some of `pi_datacenter_capabilities` are: - `cloud-connections`, `disaster-recovery-site`, `metrics`, `power-edge-router`, `power-vpn-connections` +- `pi_datacenter_href` - (String) Datacenter href. - `pi_datacenter_location` - (Map) Datacenter location. Nested schema for `pi_datacenter_location`: - - `region` - (String) The Datacenter location region zone. - - `type` - (String) The Datacenter location region type. - - `url`- (String) The Datacenter location region url. -- `pi_datacenter_status` - (String) The Datacenter status, `active`,`maintenance` or `down`. -- `pi_datacenter_type` - (String) The Datacenter type, `off-premises` or `on-premises`. + - `region` - (String) Datacenter location region zone. + - `type` - (String) Datacenter location region type. + - `url`- (String) Datacenter location region url. +- `pi_datacenter_status` - (String) Datacenter status, `active`,`maintenance` or `down`. +- `pi_datacenter_type` - (String) Datacenter type, `off-premises` or `on-premises`. diff --git a/website/docs/d/pi_datacenters.html.markdown b/website/docs/d/pi_datacenters.html.markdown index 812b0a75f3..6efbda05e9 100644 --- a/website/docs/d/pi_datacenters.html.markdown +++ b/website/docs/d/pi_datacenters.html.markdown @@ -1,5 +1,4 @@ --- - subcategory: "Power Systems" layout: "ibm" page_title: "IBM: pi_datacenters" @@ -8,26 +7,22 @@ description: |- --- # ibm_pi_datacenters - Retrieve information about Power Systems Datacenters. ## Example usage - The following example retrieves information about Power Systems Datacenters. ```terraform data "ibm_pi_datacenters" "datacenters" {} ``` -## 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" @@ -36,22 +31,22 @@ Example usage: ``` ## Attribute reference - In addition to all argument reference list, you can access the following attribute references after your data source is created. -- `datacenters` - List of Datacenters +- `datacenters` - (List) List of Datacenters Nested schema for `datacenters` - `pi_datacenter_capabilities` - (Map) Datacenter Capabilities. Capabilities are `true` or `false`. Some of `pi_datacenter_capabilities` are: - `cloud-connections`, `disaster-recovery-site`, `metrics`, `power-edge-router`, `power-vpn-connections` - + + - `pi_datacenter_href` - (String) Datacenter href. - `pi_datacenter_location` - (Map) Datacenter location. Nested schema for `pi_datacenter_location`: - - `region` - (String) The Datacenter location region zone. - - `type` - (String) The Datacenter location region type. - - `url`- (String) The Datacenter location region url. - - `pi_datacenter_status` - (String) The Datacenter status, `active`,`maintenance` or `down`. - - `pi_datacenter_type` - (String) The Datacenter type, `off-premises` or `on-premises`. + - `region` - (String) Datacenter location region zone. + - `type` - (String) Datacenter location region type. + - `url`- (String) Datacenter location region url. + - `pi_datacenter_status` - (String) Datacenter status, `active`,`maintenance` or `down`. + - `pi_datacenter_type` - (String) Datacenter type, `off-premises` or `on-premises`. diff --git a/website/docs/d/pi_dhcp.html.markdown b/website/docs/d/pi_dhcp.html.markdown index cf6f1221d5..74a73de098 100644 --- a/website/docs/d/pi_dhcp.html.markdown +++ b/website/docs/d/pi_dhcp.html.markdown @@ -34,7 +34,6 @@ In addition to all argument reference list, you can access the following attribu Nested scheme for `leases`: - `instance_ip` - (String) The IP of the PVM Instance. - `instance_mac` - (String) The MAC Address of the PVM Instance. -- `network` - (String) The ID of the DHCP Server private network (deprecated - replaced by `network_id`). - `network_id`- (String) The ID of the DHCP Server private network. - `network_name` - The name of the DHCP Server private network. - `status` - (String) The status of the DHCP Server. diff --git a/website/docs/d/pi_dhcps.html.markdown b/website/docs/d/pi_dhcps.html.markdown index edc89f2dd5..1f0095f1d7 100644 --- a/website/docs/d/pi_dhcps.html.markdown +++ b/website/docs/d/pi_dhcps.html.markdown @@ -33,7 +33,6 @@ In addition to all argument reference list, you can access the following attribu Nested scheme for `servers`: - `dhcp_id` - (String) The ID of the DHCP Server. - - `network` - (String) The ID of the DHCP Server private network (deprecated - replaced by `network_id`). - `network_id`- (String) The ID of the DHCP Server private network. - `network_name` - The name of the DHCP Server private network. - `status` - (String) The status of the DHCP Server. diff --git a/website/docs/d/pi_disaster_recovery_location.html.markdown b/website/docs/d/pi_disaster_recovery_location.html.markdown index 171b827268..60e7415568 100644 --- a/website/docs/d/pi_disaster_recovery_location.html.markdown +++ b/website/docs/d/pi_disaster_recovery_location.html.markdown @@ -1,5 +1,4 @@ --- - subcategory: "Power Systems" layout: "ibm" page_title: "IBM: pi_disaster_recovery_location" @@ -18,20 +17,21 @@ data "ibm_pi_disaster_recovery_location" "ds_disaster_recovery_location" { 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` +- 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" { region = "lon" zone = "lon04" } ``` - + ## Argument reference Review the argument references that you can specify for your data source. @@ -41,8 +41,8 @@ Review the argument references that you can specify for your data source. In addition to all argument reference list, you can access the following attribute references after your data source is created. - `location` - (String) The region zone of a site. -- `replication_sites` - List of replication sites. +- `replication_sites` - (List) List of replication sites. Nested scheme for `replication_sites`: - `is_active` - (Boolean) Indicates the location is active or not, `true` if location is active , otherwise it is `false`. - - `location` - (String) The region zone of the location. \ No newline at end of file + - `location` - (String) The region zone of the location. diff --git a/website/docs/d/pi_disaster_recovery_locations.html.markdown b/website/docs/d/pi_disaster_recovery_locations.html.markdown index 412e73a193..6ed0e43817 100644 --- a/website/docs/d/pi_disaster_recovery_locations.html.markdown +++ b/website/docs/d/pi_disaster_recovery_locations.html.markdown @@ -1,5 +1,4 @@ --- - subcategory: "Power Systems" layout: "ibm" page_title: "IBM: pi_disaster_recovery_locations" @@ -16,13 +15,14 @@ The following example retrieves information about the disaster recovery location ```terraform data "ibm_pi_disaster_recovery_locations" "ds_disaster_recovery_locations" {} ``` + **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` +- 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" { region = "lon" @@ -39,6 +39,6 @@ In addition to all argument reference list, you can access the following attribu - `location` - (String) The region zone of a site. - `replication_sites` - List of Replication Sites. - Nested scheme for `replication_sites`: - - `is_active` - (Boolean) Indicates the location is active or not, `true` if location is active, otherwise it is `false`. - - `location` - (String) The region zone of the location. \ No newline at end of file + Nested scheme for `replication_sites`: + - `is_active` - (Boolean) Indicates the location is active or not, `true` if location is active, otherwise it is `false`. + - `location` - (String) The region zone of the location. diff --git a/website/docs/d/pi_image.html.markdown b/website/docs/d/pi_image.html.markdown index fad9111aa0..2fcb988d4c 100644 --- a/website/docs/d/pi_image.html.markdown +++ b/website/docs/d/pi_image.html.markdown @@ -11,7 +11,6 @@ description: |- Import the details of an existing IBM Power Virtual Server Cloud image as a read-only data source. 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 - ```terraform data "ibm_pi_image" "ds_image" { pi_image_name = "7200-03-03" @@ -19,14 +18,13 @@ data "ibm_pi_image" "ds_image" { } ``` - **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: +**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" @@ -44,10 +42,11 @@ Review the argument references that you can specify for your data source. In addition to all argument reference list, you can access the following attribute references after your data source is created. - `architecture` - (String) The CPU architecture that the image is designed for. +- `hypervisor` - (String) Hypervisor type. - `id` - (String) The unique identifier of the image. -- `operatingsystem` - (String) The operating system that is installed with the image. +- `image_type` - (String) The identifier of this image type. +- `operating_system` - (String) The operating system that is installed with the image. - `size` - (String) The size of the image in megabytes. - `state` - (String) The state for this image. - `storage_type` - (String) The storage type for this image. - `storage_pool` - (String) Storage pool where image resides. -- `image_type` - (String) The identifier of this image type. diff --git a/website/docs/d/pi_images.html.markdown b/website/docs/d/pi_images.html.markdown index 791e2df2bf..617207e159 100644 --- a/website/docs/d/pi_images.html.markdown +++ b/website/docs/d/pi_images.html.markdown @@ -18,14 +18,13 @@ data "ibm_pi_images" "ds_images" { } ``` - **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: +**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" @@ -41,13 +40,13 @@ Review the argument references that you can specify for your data source. ## Attribute reference In addition to all argument reference list, you can access the following attribute references after your data source is created. -- `image_info` - List of images - A list of all supported images. +- `image_info` - (List) List of all supported images. Nested scheme for `image_info`: - `href` - (String) The hyper link of an image. - `id` - (String) The unique identifier of an image. + - `image_type` - (String) The identifier of this image type. - `name`- (String) The name of an image. - `state` - (String) The state of an image. - `storage_pool` - (String) Storage pool where image resides. - `storage_type` - (String) The storage type of an image. - - `image_type` - (String) The identifier of this image type. diff --git a/website/docs/d/pi_instance.html.markdown b/website/docs/d/pi_instance.html.markdown index 75fecd8d53..590cc12fbd 100644 --- a/website/docs/d/pi_instance.html.markdown +++ b/website/docs/d/pi_instance.html.markdown @@ -44,17 +44,14 @@ Review the argument references that you can specify for your data source. ## Attribute reference In addition to all argument reference list, you can access the following attribute references after your data source is created. -- `addresses` - (Deprecated, List of objects) - The address associated with this instance. - - Nested scheme for `addresses`: - - `ip` - (String) The IP address of the instance. - - `external_ip` - (String) The external IP address of the instance. - - `macaddress` - (String) The MAC address of the instance. - - `network_id` - (String) The network ID of the instance. - - `network_name` - (String) The network name of the instance. - - `type` - (String) The type of the network. - `deployment_type` - (String) The custom deployment type. - `health_status` - (String) The health of the instance. + +**Notes** IBMi software licenses for IBMi virtual server instances -- only for IBMi instances +- `ibmi_css` - (Boolean) IBMi Cloud Storage Solution. +- `ibmi_pha` - (Boolean) IBMi Power High Availability. +- `ibmi_rds` - (Boolean) IBMi Rational Dev Studio. +- `ibmi_rds_users` - (Integer) IBMi Rational Dev Studio Number of User Licenses. - `id` - (String) The unique identifier of the instance. - `license_repository_capacity` - The VTL license repository capacity TB value. Only available with VTL instances. - `memory` - (Float) The amount of memory that is allocated to the instance. @@ -73,6 +70,7 @@ In addition to all argument reference list, you can access the following attribu - `network_id` - (String) The network ID of the instance. - `network_name` - (String) The network name of the instance. - `type` - (String) The type of the network. + - `placement_group_id`- (String) The ID of the placement group that the instance is a member. - `processors` - (Float) The number of processors that are allocated to the instance. - `proctype` - (String) The procurement type of the instance. Supported values are `shared` and `dedicated`. diff --git a/website/docs/d/pi_instance_ip.html.markdown b/website/docs/d/pi_instance_ip.html.markdown index 541891d09c..8f1942cc83 100644 --- a/website/docs/d/pi_instance_ip.html.markdown +++ b/website/docs/d/pi_instance_ip.html.markdown @@ -1,5 +1,4 @@ --- - subcategory: "Power Systems" layout: "ibm" page_title: "IBM: pi_instance_ip" @@ -11,7 +10,6 @@ description: |- Retrieve information about a Power Systems Virtual Server instance IP address. For more information, about Power Systems Virtual Server instance IP address, see [configuring and adding a private network subnet](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-configuring-subnet). ## Example usage - ```terraform data "ibm_pi_instance_ip" "ds_instance_ip" { pi_instance_name = "terraform-test-instance" @@ -19,12 +17,14 @@ data "ibm_pi_instance_ip" "ds_instance_ip" { 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: +- 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" @@ -36,7 +36,7 @@ data "ibm_pi_instance_ip" "ds_instance_ip" { 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_instance_name` - (Required, String) The name of the instance. +- `pi_instance_name` - (Required, String) The unique identifier or name of the instance. - `pi_network_name` - (Required, String) The subnet that the instance belongs to. diff --git a/website/docs/d/pi_instance_snapshot.html.markdown b/website/docs/d/pi_instance_snapshot.html.markdown new file mode 100644 index 0000000000..ff1f7469d0 --- /dev/null +++ b/website/docs/d/pi_instance_snapshot.html.markdown @@ -0,0 +1,50 @@ +--- +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_instance_snapshot" +description: |- + Manages an instance snapshot in the Power Virtual Server cloud. +--- + +# ibm_pi_instance_snapshot +Retrieve information about a Power Systems Virtual Server instance snapshot. For more information, about Power Virtual Server instance snapshot, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + +## Example usage +```terraform +data "ibm_pi_instance_snapshot" "ds_instance_snapshot" { + pi_cloud_instance_id = "49fba6c9-23f8-40bc-9899-aca322ee7d5b" + pi_snapshot_id = "2ce22124-4c32-6456-bfce-803e0658ab12" +} +``` + +**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. +- `pi_snapshot_id` - (Required, String) The unique identifier of the Power Systems Virtual Machine instance snapshot. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `action` - (String) Action performed on the instance snapshot. +- `creation_date` - (String) Date of snapshot creation. +- `description` - (String) The description of the snapshot. +- `last_updated_date` - (String) Date of last update. +- `name` - (String) The name of the Power Systems Virtual Machine instance snapshot. +- `percent_complete` - (Integer) The snapshot completion percentage. +- `status` - (String) The status of the Power Virtual Machine instance snapshot. +- `volume_snapshots` - (Map) A map of volume snapshots included in the Power Virtual Machine instance snapshot. diff --git a/website/docs/d/pi_instance_snapshots.html.markdown b/website/docs/d/pi_instance_snapshots.html.markdown index cbe97e86f3..7d39c0d0d5 100644 --- a/website/docs/d/pi_instance_snapshots.html.markdown +++ b/website/docs/d/pi_instance_snapshots.html.markdown @@ -1,5 +1,4 @@ --- - subcategory: "Power Systems" layout: "ibm" page_title: "IBM: pi_instance_snapshots" @@ -11,21 +10,19 @@ description: |- Retrieve information about a Power Systems Virtual Server instance snapshots. For more information, about Power Virtual Server instance snapshots, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). ## Example usage - ```terraform data "ibm_pi_instance_snapshots" "ds_instance_snapshots" { pi_cloud_instance_id = "49fba6c9-23f8-40bc-9899-aca322ee7d5b" } ``` -**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: - +Example usage: ```terraform provider "ibm" { region = "lon" @@ -41,15 +38,15 @@ Review the argument references that you can specify for your data source. ## Attribute reference In addition to all argument reference list, you can access the following attribute references after your data source is created. -- `instance_snapshots` - The list of Power Virtual Machine instance snapshots within the given cloud instance. +- `instance_snapshots` - (List) List of Power Virtual Machine instance snapshots within the given cloud instance. Nested scheme for `instance_snapshots`: - `action` - (String) Action performed on the instance snapshot. - - `creation_date` - (String) The creation date. + - `creation_date` - (String) Date of snapshot creation. - `description` - (String) The description of the snapshot. - `id` - (String) The unique identifier of the Power Systems Virtual Machine instance snapshot. - - `last_updated_date` - (String) The last Update Date. + - `last_updated_date` - (String) Date of last update. - `name` - (String) The name of the Power Systems Virtual Machine instance snapshot. - `percent_complete` - (Integer) The snapshot completion percentage. - `status` - (String) The status of the Power Virtual Machine instance snapshot. - - `volume_snapshots` - (Map) A map of volume snapshots included in the Power Virtual Machine instance snapshot. \ No newline at end of file + - `volume_snapshots` - (Map) A map of volume snapshots included in the Power Virtual Machine instance snapshot. diff --git a/website/docs/d/pi_instance_volumes.html.markdown b/website/docs/d/pi_instance_volumes.html.markdown index 1fc2583b2b..6c17530538 100644 --- a/website/docs/d/pi_instance_volumes.html.markdown +++ b/website/docs/d/pi_instance_volumes.html.markdown @@ -1,5 +1,4 @@ --- - subcategory: "Power Systems" layout: "ibm" page_title: "IBM: pi_instance_volumes" @@ -8,26 +7,25 @@ description: |- --- # ibm_pi_instance_volumes -Retrieves information about a persistent storage volume that is mounted to a Power Systems Virtual Server instance. For more information, about power instance volume, see [snapshotting, cloning, and restoring](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-volume-snapshot-clone). +Retrieves information about the persistent storage volumes that are mounted to a Power Systems Virtual Server instance. For more information, about power instance volume, see [snapshotting, cloning, and restoring](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-volume-snapshot-clone). ## Example usage -The following example retrieves information about the `volume_1` volume that is mounted to the Power Systems Virtual Server instance with the ID. +The following example retrieves information about the volumes attached to the `terraform-test-instance` instance. ```terraform data "ibm_pi_instance_volumes" "ds_volumes" { - pi_instance_name = "volume_1" + pi_instance_name = "terraform-test-instance" 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: +- 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" @@ -39,21 +37,21 @@ data "ibm_pi_instance_volumes" "ds_volumes" { 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_volume_name` - (Required, String) The name of the volume for which you want to retrieve detailed information. +- `pi_instance_name` - (Required, String) The unique identifier or name of the instance. ## Attribute reference In addition to all argument reference list, you can access the following attribute references after your data source is created. - `boot_volume_id` - (String) The unique identifier of the boot volume. -- `instance_volumes` - List of volumes - List of volumes attached to instance. +- `instance_volumes` - (List) List of volumes attached to instance. Nested scheme for `instance_volumes`: - - `bootable`- (Bool) Indicates if the volume is boot capable. + - `bootable`- (Boolean) Indicates if the volume is boot capable. - `href` - (String) The hyper link of the volume. - `id` - (String) The unique identifier of the volume. - `name` - (String) The name of the volume. - `pool` - (String) Volume pool, name of storage pool where the volume is located. - - `shareable` - (Bool) Indicates if the volume is shareable between VMs. + - `shareable` - (Boolean) Indicates if the volume is shareable between VMs. - `size` - (Integer) The size of this volume in gigabytes. - `state` - (String) The state of the volume. - `type` - (String) The disk type that is used for this volume. diff --git a/website/docs/d/pi_key.html.markdown b/website/docs/d/pi_key.html.markdown index 19b824e44c..69eda7ca5b 100644 --- a/website/docs/d/pi_key.html.markdown +++ b/website/docs/d/pi_key.html.markdown @@ -1,28 +1,40 @@ --- - subcategory: "Power Systems" layout: "ibm" page_title: "IBM: pi_key" description: |- - Manages an key in the Power Virtual Server cloud. + Manages an SSH key in the Power Virtual Server cloud. --- # ibm_pi_key -Retrieve information about the SSH key that is used for your Power Systems Virtual Server instance. The SSH key is used to access the instance after it is created. For more information, about [configuring your IBM virtual machine (VM)](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-creating-ssh-key). +Retrieve information about the SSH key that is used for your Power Systems Virtual Server instance. The SSH key is used to access the instance after it is created. For more information, about [generating and using SSH Keys](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-creating-ssh-key). ## Example usage - ```terraform data "ibm_pi_key" "ds_instance" { pi_key_name = "terraform-test-key" 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) Cloud Instance ID of a PCloud Instance. +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. - `pi_key_name` - (Required, String) User defined name for the SSH key. ## Attribute reference @@ -31,19 +43,3 @@ In addition to all argument reference list, you can access the following attribu - `id` - (String) User defined name for the SSH key - `creation_date` - (String) Date of SSH Key creation. - `ssh_key` - (String) SSH RSA key. - -**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" - } - ``` \ No newline at end of file diff --git a/website/docs/d/pi_keys.html.markdown b/website/docs/d/pi_keys.html.markdown index 305c0f4a9d..dd5dac4d13 100644 --- a/website/docs/d/pi_keys.html.markdown +++ b/website/docs/d/pi_keys.html.markdown @@ -1,5 +1,4 @@ --- - subcategory: "Power Systems" layout: "ibm" page_title: "IBM: pi_keys" @@ -8,20 +7,33 @@ description: |- --- # ibm_pi_keys -Retrieve information about all SSH keys. For more information, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). +Retrieve information about all SSH keys. For more information, about [generating and using SSH Keys](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-creating-ssh-key). ## Example usage - ```terraform data "ibm_pi_keys" "example" { pi_cloud_instance_id = "" } ``` - + +**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) Cloud Instance ID of a PCloud Instance. +- `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. @@ -32,19 +44,3 @@ In addition to all argument reference list, you can access the following attribu - `name` - (String) User defined name for the SSH key - `creation_date` - (String) Date of SSH Key creation. - `ssh_key` - (String) SSH RSA key. - -**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" - } - ``` \ No newline at end of file diff --git a/website/docs/d/pi_network.html.markdown b/website/docs/d/pi_network.html.markdown index c4f03cb824..30635fd315 100644 --- a/website/docs/d/pi_network.html.markdown +++ b/website/docs/d/pi_network.html.markdown @@ -1,5 +1,4 @@ --- - subcategory: "Power Systems" layout: "ibm" page_title: "IBM: pi_network" @@ -11,7 +10,6 @@ description: |- 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" @@ -19,15 +17,13 @@ data "ibm_pi_network" "ds_network" { } ``` -**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: - +Example usage: ```terraform provider "ibm" { region = "lon" @@ -44,15 +40,15 @@ Review the argument references that you can specify for your data source. ## 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). - `available_ip_count` - (Float) The total number of IP addresses that you have in your network. - `cidr` - (String) The CIDR of the network. -- `dns`- (Set of String) The DNS Servers for the network. +- `dns`- (Set) The DNS Servers for the network. - `gateway` - (String) The network gateway that is attached to your network. - `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. - `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. - `vlan_id` - (String) The VLAN ID that the network is connected to. -- `jumbo` - (Bool) MTU Jumbo option of the network (for multi-zone locations only). `deprecated` -- `mtu` - (Bool) Maximum Transmission Unit option of the network. -- `access_config` - (String) The network communication configuration option of the network (for satellite locations only). \ No newline at end of file diff --git a/website/docs/d/pi_network_port.html.markdown b/website/docs/d/pi_network_port.html.markdown new file mode 100644 index 0000000000..9d46bee2d0 --- /dev/null +++ b/website/docs/d/pi_network_port.html.markdown @@ -0,0 +1,52 @@ +--- +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_network_port" +description: |- + Manages an Network Port in the Power Virtual Server Cloud. +--- + +# ibm_pi_network_port +Retrieve information about a network port in the Power Virtual Server Cloud. For more information, about networks in IBM power virtual server, see [adding or removing a public network](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-modifying-server#adding-removing-network). + +## Example usage +```terraform +data "ibm_pi_network_port" "test-network-port" { + pi_network_name = "Zone1-CFN" + pi_cloud_instance_id = "51e1879c-bcbe-4ee1-a008-49cdba0eaf60" +} +``` + +**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. +- `pi_network_name` - (Required, String) The unique identifier or name of a network. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute reference after your data source is created. + +- `network_ports` - (List) List of all in use network ports for a network. + + Nested scheme for `network_ports`: + - `description` - (String) The description for the network port. + - `href` - (String) Network port href. + - `ipaddress` - (String) The IP address of the port. + - `macaddress` - (String) The MAC address of the port. + - `portid` - (String) The ID of the port. + - `public_ip`- (String) The public IP associated with the port. + - `status` - (String) The status of the port. diff --git a/website/docs/d/pi_placement_group.html.markdown b/website/docs/d/pi_placement_group.html.markdown index d90d4b83f9..0c6aebd4d4 100644 --- a/website/docs/d/pi_placement_group.html.markdown +++ b/website/docs/d/pi_placement_group.html.markdown @@ -1,5 +1,4 @@ --- - subcategory: "Power Systems" layout: "ibm" page_title: "IBM: pi_placement_group" @@ -11,7 +10,6 @@ description: |- Retrieve information about a placement group. For more information, about placement groups, see [Managing server placement groups](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-placement-groups). ## Example Usage - ```terraform data "ibm_pi_placement_group" "ds_placement_group" { pi_placement_group_name = "my-pg" @@ -20,20 +18,18 @@ data "ibm_pi_placement_group" "ds_placement_group" { ``` **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: +- 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. @@ -45,5 +41,5 @@ Review the argument references that you can specify for your data source. In addition to all argument reference list, you can access the following attribute references after your data source is created. - `id` - (String) The ID of the placement group. -- `members` - (List of strings) The list of server instances IDs that are members of the placement group. +- `members` - (List) List of server instances IDs that are members of the placement group. - `policy` - (String) The value of the group's affinity policy. Valid values are affinity and anti-affinity. diff --git a/website/docs/d/pi_placement_groups.html.markdown b/website/docs/d/pi_placement_groups.html.markdown index c4ef5d7946..a1e11659bf 100644 --- a/website/docs/d/pi_placement_groups.html.markdown +++ b/website/docs/d/pi_placement_groups.html.markdown @@ -1,5 +1,4 @@ --- - subcategory: "Power Systems" layout: "ibm" page_title: "IBM: pi_placement_groups" @@ -11,7 +10,6 @@ description: |- Retrieve information about all placement groups. For more information, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). ## Example usage - ```terraform data "ibm_pi_placement_groups" "example" { pi_cloud_instance_id = "" @@ -19,14 +17,12 @@ data "ibm_pi_placement_groups" "example" { ``` **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` +- 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" @@ -46,6 +42,6 @@ In addition to all argument reference list, you can access the following attribu Nested scheme for `placement_groups`: - `id` - (String) The ID of the placement group. + - `members` - (List) List of server instances IDs that are members of the placement group. - `name` - (String) User defined name for the placement group. - - `members` - (List of strings) The list of server instances IDs that are members of the placement group. - `policy` - (String) The value of the group's affinity policy. Valid values are affinity and anti-affinity. diff --git a/website/docs/d/pi_public_network.html.markdown b/website/docs/d/pi_public_network.html.markdown index 9c00c9d0a3..097d94ce6a 100644 --- a/website/docs/d/pi_public_network.html.markdown +++ b/website/docs/d/pi_public_network.html.markdown @@ -1,5 +1,4 @@ --- - subcategory: "Power Systems" layout: "ibm" page_title: "IBM: pi_public_network" @@ -8,32 +7,29 @@ description: |- --- # ibm_pi_public_network -Retrieve the details about a public network that is used for your Power Systems Virtual Server instance. For more information, about public network in IBM power virutal server, see [adding or removing a public network +Retrieve the details about a public network that is used for your Power Systems Virtual Server instance. For more information, about public network in IBM Power Systems Virtual Server, see [adding or removing a public network ](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-modifying-server#adding-removing-network). ## Example usage - ```terraform data "ibm_pi_public_network" "ds_public_network" { pi_cloud_instance_id = "49fba6c9-23f8-40bc-9899-aca322ee7d5b" } ``` -**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` - - Example usage: +**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. diff --git a/website/docs/d/pi_pvm_snapshots.html.markdown b/website/docs/d/pi_pvm_snapshots.html.markdown index 7a2eeaf5e5..3a5fa6571a 100644 --- a/website/docs/d/pi_pvm_snapshots.html.markdown +++ b/website/docs/d/pi_pvm_snapshots.html.markdown @@ -1,5 +1,4 @@ --- - subcategory: "Power Systems" layout: "ibm" page_title: "IBM: pi_pvm_snapshots" @@ -11,7 +10,6 @@ description: |- Retrieve information about a Power Systems Virtual Server instance snapshots. For more information, about Power Virtual Server PVM instance snapshots, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). ## Example usage - ```terraform data "ibm_pi_pvm_snapshots" "ds_pvm_snapshots" { pi_instance_name = "terraform-test-instance" @@ -19,14 +17,13 @@ data "ibm_pi_pvm_snapshots" "ds_pvm_snapshots" { } ``` -**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: - +Example usage: ```terraform provider "ibm" { region = "lon" @@ -37,8 +34,8 @@ data "ibm_pi_pvm_snapshots" "ds_pvm_snapshots" { ## Argument reference Review the argument references that you can specify for your data source. -- `pi_instance_name` - (Required, String) The name of the instance. - `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_instance_name` - (Required, String) The unique identifier or name of the instance. ## Attribute reference In addition to all argument reference list, you can access the following attribute references after your data source is created. @@ -47,11 +44,11 @@ In addition to all argument reference list, you can access the following attribu Nested scheme for `pvm_snapshots`: - `action` - (String) Action performed on the instance snapshot. - - `creation_date` - (String) The creation date. + - `creation_date` - (String) Date of snapshot creation. - `description` - (String) The description of the snapshot. - `id` - (String) The unique identifier of the Power Virtual Machine instance snapshot. - - `last_updated_date` - (String) The last update date. + - `last_updated_date` - (String) Date of last update. - `name` - (String) The name of the Power Virtual Machine instance snapshot. - `percent_complete` - (Integer) The snapshot completion percentage. - `status` - (String) The status of the Power Virtual Machine instance snapshot. - - `volume_snapshots` - (Map) A map of volume snapshots included in the Power Virtual Machine instance snapshot. \ No newline at end of file + - `volume_snapshots` - (Map) A map of volume snapshots included in the Power Virtual Machine instance snapshot. diff --git a/website/docs/d/pi_sap_profile.html.markdown b/website/docs/d/pi_sap_profile.html.markdown index 2be43b8874..32717c17f7 100644 --- a/website/docs/d/pi_sap_profile.html.markdown +++ b/website/docs/d/pi_sap_profile.html.markdown @@ -1,5 +1,4 @@ --- - subcategory: "Power Systems" layout: "ibm" page_title: "IBM: pi_sap_profile" @@ -11,7 +10,6 @@ description: |- Retrieve information about a SAP profile. For more information, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). ## Example usage - ```terraform data "ibm_pi_sap_profile" "example" { pi_cloud_instance_id = "" @@ -20,14 +18,12 @@ data "ibm_pi_sap_profile" "example" { ``` **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` +- 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" diff --git a/website/docs/d/pi_sap_profiles.html.markdown b/website/docs/d/pi_sap_profiles.html.markdown index 4106f1fa84..630242ee68 100644 --- a/website/docs/d/pi_sap_profiles.html.markdown +++ b/website/docs/d/pi_sap_profiles.html.markdown @@ -1,5 +1,4 @@ --- - subcategory: "Power Systems" layout: "ibm" page_title: "IBM: pi_sap_profiles" @@ -11,7 +10,6 @@ description: |- Retrieve information about all SAP profiles. For more information, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). ## Example usage - ```terraform data "ibm_pi_sap_profiles" "example" { pi_cloud_instance_id = "" @@ -19,14 +17,12 @@ data "ibm_pi_sap_profiles" "example" { ``` **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` +- 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" diff --git a/website/docs/d/pi_shared_processor_pool.html.markdown b/website/docs/d/pi_shared_processor_pool.html.markdown index b47e607be6..7918b46199 100644 --- a/website/docs/d/pi_shared_processor_pool.html.markdown +++ b/website/docs/d/pi_shared_processor_pool.html.markdown @@ -1,5 +1,4 @@ --- - subcategory: "Power Systems" layout: "ibm" page_title: "IBM: pi_shared_processor_pool" @@ -11,7 +10,6 @@ description: |- Retrieve information about a shared processor pool. For more information, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). ## Example Usage - ```terraform data "ibm_pi_shared_processor_pool" "ds_pool" { pi_shared_processor_pool_id = "my-spp" @@ -20,20 +18,18 @@ data "ibm_pi_shared_processor_pool" "ds_pool" { ``` **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: +- 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. @@ -48,7 +44,8 @@ In addition to all argument reference list, you can access the following attribu - `available_cores` - (Integer) The available cores in the shared processor pool. - `host_id` - (Integer) The host ID where the shared processor pool resides. - `id` - (String) The shared processor pool's unique ID. -- `instances` - (List of Map) The list of server instances that are deployed in the shared processor pool. +- `instances` - (List) List of server instances deployed in the shared processor pool. + Nested scheme for `instances`: - `availability_zone` - (String) Availability zone for the server instances. - `cpus` - (Integer) The amount of cpus for the server instance. diff --git a/website/docs/d/pi_shared_processor_pools.html.markdown b/website/docs/d/pi_shared_processor_pools.html.markdown index dd9ad6d97e..3586e0437c 100644 --- a/website/docs/d/pi_shared_processor_pools.html.markdown +++ b/website/docs/d/pi_shared_processor_pools.html.markdown @@ -1,5 +1,4 @@ --- - subcategory: "Power Systems" layout: "ibm" page_title: "IBM: pi_shared_processor_pools" @@ -11,7 +10,6 @@ description: |- Retrieve information about all shared processor pools. For more information, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). ## Example usage - ```terraform data "ibm_pi_shared_processor_pools" "example" { pi_cloud_instance_id = "" @@ -19,14 +17,12 @@ data "ibm_pi_shared_processor_pools" "example" { ``` **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` +- 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" @@ -52,4 +48,4 @@ In addition to all argument reference list, you can access the following attribu - `reserved_cores` - (Integer) The amount of reserved cores for the shared processor pool. - `shared_processor_pool_id` - (String) The shared processor pool's unique ID. - `status` - (String) The status of the shared processor pool. - - `status_detail` - (String) The status details of the shared processor pool. \ No newline at end of file + - `status_detail` - (String) The status details of the shared processor pool. diff --git a/website/docs/d/pi_spp_placement_group.html.markdown b/website/docs/d/pi_spp_placement_group.html.markdown index 79af4c068e..b725105481 100644 --- a/website/docs/d/pi_spp_placement_group.html.markdown +++ b/website/docs/d/pi_spp_placement_group.html.markdown @@ -1,5 +1,4 @@ --- - subcategory: "Power Systems" layout: "ibm" page_title: "IBM: pi_spp_placement_group" @@ -11,7 +10,6 @@ description: |- Retrieve information about a shared processor pool placement group. For more information, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). ## Example Usage - ```terraform data "ibm_pi_spp_placement_group" "ds_placement_group" { pi_spp_placement_group_id = "my-spppg" @@ -20,20 +18,18 @@ data "ibm_pi_spp_placement_group" "ds_placement_group" { ``` **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: +- 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. @@ -44,6 +40,6 @@ Review the argument references that you can specify for your data source. ## Attribute reference In addition to all argument reference list, you can access the following attribute references after your data source is created. -- `members` - (List of strings) The list of shared processor pool IDs that are members of the placement group. +- `members` - (List) List of shared processor pool IDs that are members of the placement group. - `name` - (String) The name of the shared processor pool placement group. - `policy` - (String) The value of the group's affinity policy. Valid values are affinity and anti-affinity. diff --git a/website/docs/d/pi_spp_placement_groups.html.markdown b/website/docs/d/pi_spp_placement_groups.html.markdown index 61267fefb5..cc1503dd9f 100644 --- a/website/docs/d/pi_spp_placement_groups.html.markdown +++ b/website/docs/d/pi_spp_placement_groups.html.markdown @@ -1,5 +1,4 @@ --- - subcategory: "Power Systems" layout: "ibm" page_title: "IBM: pi_spp_placement_groups" @@ -11,7 +10,6 @@ description: |- Retrieve information about all shared processor pool placement groups. For more information, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). ## Example usage - ```terraform data "ibm_pi_spp_placement_groups" "example" { pi_cloud_instance_id = "" @@ -19,14 +17,12 @@ data "ibm_pi_spp_placement_groups" "example" { ``` **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` +- 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" @@ -45,7 +41,7 @@ In addition to all argument reference list, you can access the following attribu - `spp_placement_groups` - (List) List of all the shared processor pool placement groups. Nested scheme for `spp_placement_groups`: + - `members` - (List) The list of shared processor pool IDs that are members of the shared processor pool placement group. - `name` - (String) User defined name for the shared processor pool placement group. - - `members` - (List of strings) The list of shared processor pool IDs that are members of the shared processor pool placement group. - `policy` - (String) The value of the group's affinity policy. Valid values are affinity and anti-affinity. - `spp_placement_group_id` - (String) The ID of the shared processor pool placement group. diff --git a/website/docs/d/pi_storage_pool_capacity.markdown b/website/docs/d/pi_storage_pool_capacity.markdown index a38e01eb79..caa5550c16 100644 --- a/website/docs/d/pi_storage_pool_capacity.markdown +++ b/website/docs/d/pi_storage_pool_capacity.markdown @@ -1,5 +1,4 @@ --- - subcategory: "Power Systems" layout: "ibm" page_title: "IBM: pi_storage_pool_capacity" @@ -11,7 +10,6 @@ description: |- Retrieve information about storages capacity for a storage pool in a region. For more information, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). ## Example usage - ```terraform data "ibm_pi_storage_pool_capacity" "pool" { pi_cloud_instance_id = "" @@ -20,14 +18,12 @@ data "ibm_pi_storage_pool_capacity" "pool" { ``` **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` +- 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" @@ -45,6 +41,7 @@ Review the argument references that you can specify for your data source. In addition to all argument reference list, you can access the following attribute references after your data source is created. - `max_allocation_size` - (Integer) Maximum allocation storage size (GB). +- `replication_enabled` - (Boolean) Replication status of the storage pool. - `storage_type` - (String) Storage type of the storage pool. - `total_capacity` - (Integer) Total pool capacity (GB). -- `replication_enabled` - (Boolean) Replication status of the storage pool. + diff --git a/website/docs/d/pi_storage_pools_capacity.markdown b/website/docs/d/pi_storage_pools_capacity.markdown index f85cecb0d3..0a20832207 100644 --- a/website/docs/d/pi_storage_pools_capacity.markdown +++ b/website/docs/d/pi_storage_pools_capacity.markdown @@ -1,5 +1,4 @@ --- - subcategory: "Power Systems" layout: "ibm" page_title: "IBM: pi_storage_pools_capacity" @@ -11,7 +10,6 @@ description: |- Retrieve information about storages capacity for all available storage pools in a region. For more information, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). ## Example usage - ```terraform data "ibm_pi_storage_pools_capacity" "pools" { pi_cloud_instance_id = "" @@ -19,14 +17,12 @@ data "ibm_pi_storage_pools_capacity" "pools" { ``` **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` +- 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" diff --git a/website/docs/d/pi_system_pools.markdown b/website/docs/d/pi_system_pools.markdown index 28ce84b76d..09cb154c97 100644 --- a/website/docs/d/pi_system_pools.markdown +++ b/website/docs/d/pi_system_pools.markdown @@ -1,5 +1,4 @@ --- - subcategory: "Power Systems" layout: "ibm" page_title: "IBM: pi_system_pools" @@ -11,7 +10,6 @@ description: |- Retrieve information about list of system pools within a particular data center. For more information, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). ## Example usage - ```terraform data "ibm_pi_system_pools" "pools" { pi_cloud_instance_id = "" @@ -19,14 +17,12 @@ data "ibm_pi_system_pools" "pools" { ``` **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` +- 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" @@ -42,47 +38,46 @@ Review the argument references that you can specify for your data source. ## Attribute reference In addition to all argument reference list, you can access the following attribute references after your data source is created. -- `system_pools` - (List) The available system pools within a particular DataCenter. +- `system_pools` - (List) List of available system pools within a particular Datacenter. Nested scheme for `system_pools`: - - `system_pool_name` - (String) The system pool name. - `capacity` - (Map) Advertised capacity cores and memory (GB). - Nested scheme for `capacity`: - - `cores` - (String) The host available Processor units. - - `memory`- (String) The host available RAM memory in GiB. + Nested scheme for `capacity`: + - `cores` - (String) The host available Processor units. + - `memory`- (String) The host available RAM memory in GiB. - `core_memory_ratio` - (Float) Processor to Memory (GB) Ratio. - `max_available` - (Map) Maximum configurable cores and memory (GB) (aggregated from all hosts). - Nested scheme for `max_available`: - - `cores` - (String) The host available Processor units. - - `memory`- (String) The host available RAM memory in GiB. + Nested scheme for `max_available`: + - `cores` - (String) The host available Processor units. + - `memory`- (String) The host available RAM memory in GiB. - `max_cores_available` - (Map) Maximum configurable cores available combined with available memory of that host. - Nested scheme for `max_cores_available`: - - `cores` - (String) The host available Processor units. - - `memory`- (String) The host available RAM memory in GiB. + Nested scheme for `max_cores_available`: + - `cores` - (String) The host available Processor units. + - `memory`- (String) The host available RAM memory in GiB. - `max_memory_available` - (Map) Maximum configurable memory available combined with available cores of that host. - Nested scheme for `max_memory_available`: - - `cores` - (String) The host available Processor units. - - `memory`- (String) The host available RAM memory in GiB. + Nested scheme for `max_memory_available`: + - `cores` - (String) The host available Processor units. + - `memory`- (String) The host available RAM memory in GiB. - `shared_core_ratio` - (Map) The min-max-default allocation percentage of shared core per vCPU. - Nested scheme for `shared_core_ratio`: - - `default` - (String) The default value. - - `max` - (String) The max value. - - `min`- (String) The min value. - - - `systems` - (List) The DataCenter list of servers and their available resources. + Nested scheme for `shared_core_ratio`: + - `default` - (String) The default value. + - `max` - (String) The max value. + - `min`- (String) The min value. + - `system_pool_name` - (String) The system pool name. + - `systems` - (List) The Datacenter list of servers and their available resources. - Nested scheme for `systems`: - - `cores` - (String) The host available Processor units. - - `id` - (String) The host identifier. - - `memory`- (String) The host available RAM memory in GiB. + Nested scheme for `systems`: + - `cores` - (String) The host available Processor units. + - `id` - (String) The host identifier. + - `memory`- (String) The host available RAM memory in GiB. - `type` - (String) Type of system hardware. diff --git a/website/docs/d/pi_workspace.html.markdown b/website/docs/d/pi_workspace.html.markdown index 1b3195f016..6134e2a18c 100644 --- a/website/docs/d/pi_workspace.html.markdown +++ b/website/docs/d/pi_workspace.html.markdown @@ -1,5 +1,4 @@ --- - subcategory: "Power Systems" layout: "ibm" page_title: "IBM: pi_workspace" @@ -8,26 +7,22 @@ description: |- --- # ibm_pi_workspace - Retrieve information about your Power Systems account workspace. ## Example usage - ```terraform data "ibm_pi_workspace" "workspace" { pi_cloud_instance_id = "99fba9c9-66f9-99bc-9999-aca999ee9d9b" } ``` -## 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" @@ -36,13 +31,11 @@ Example usage: ``` ## Argument reference - Review the argument references that you can specify for your data source. - `pi_cloud_instance_id` - (Required, String) Cloud Instance ID of a PCloud Instance under your account. ## Attribute reference - In addition to all argument reference listed, you can access the following attribute references after your data source is created. - `id` - (String) Workspace ID. @@ -54,14 +47,14 @@ In addition to all argument reference listed, you can access the following attri - `pi_workspace_details` - (Map) Workspace information. Nested schema for `pi_workspace_details`: - - `creation_date` - (String) Workspace creation date. + - `creation_date` - (String) Date of workspace creation. - `crn` - (String) Workspace crn. - `pi_workspace_location` - (Map) Workspace location. Nested schema for `Workspace location`: - - `region` - (String) The Workspace location region zone. - - `type` - (String) The Workspace location region type. - - `url`- (String) The Workspace location region url. -- `pi_workspace_name` - (String) The Workspace name. -- `pi_workspace_status` - (String) The Workspace status, `active`, `critical`, `failed`, `provisioning`. -- `pi_workspace_type` - (String) The Workspace type, `off-premises` or `on-premises`. + - `region` - (String) Workspace location region zone. + - `type` - (String) Workspace location region type. + - `url`- (String) Workspace location region url. +- `pi_workspace_name` - (String) Workspace name. +- `pi_workspace_status` - (String) Workspace status, `active`, `critical`, `failed`, `provisioning`. +- `pi_workspace_type` - (String) Workspace type, `off-premises` or `on-premises`. diff --git a/website/docs/d/pi_workspaces.html.markdown b/website/docs/d/pi_workspaces.html.markdown index 12ca699246..0c5f6e5af2 100644 --- a/website/docs/d/pi_workspaces.html.markdown +++ b/website/docs/d/pi_workspaces.html.markdown @@ -1,5 +1,4 @@ --- - subcategory: "Power Systems" layout: "ibm" page_title: "IBM: pi_workspaces" @@ -8,26 +7,22 @@ description: |- --- # ibm_pi_workspaces - Retrieve information about Power Systems workspaces. ## Example usage - ```terraform data "ibm_pi_workspaces" "workspaces" { pi_cloud_instance_id = "99fba9c9-66f9-99bc-9999-aca999ee9d9b" } ``` -## 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" @@ -36,34 +31,32 @@ Example usage: ``` ## Argument reference - Review the argument references that you can specify for your data source. -- `pi_cloud_instance_id` - (Required, String) Cloud Instance ID of a PCloud Instance. +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. ## Attribute reference - In addition to all argument reference listed, you can access the following attribute references after your data source is created. -- `workspaces` - List of all Workspaces. +- `workspaces` - (List) List of all Workspaces. Nested schema for `workspaces` - `pi_workspace_capabilities` - (Map) Workspace Capabilities. Capabilities are `true` or `false`. - Some of `pi_workspace_capabilities` are: - - `cloud-connections` ,`power-edge-router`, `power-vpn-connections`, `transit-gateway-connection` + Some of `pi_workspace_capabilities` are: + - `cloud-connections`, `power-edge-router`, `power-vpn-connections`, `transit-gateway-connection` - `pi_workspace_details` - (Map) Workspace information. - Nested schema for `pi_workspace_details`: - - `creation_date` - (String) Workspace creation date. - - `crn` - (String) Workspace crn. + Nested schema for `pi_workspace_details`: + - `creation_date` - (String) Date of workspace creation. + - `crn` - (String) Workspace crn. - `pi_workspace_id` - (String) Workspace ID. - `pi_workspace_location` - (Map) Workspace location. - Nested schema for `Workspace location`: - - `region` - (String) The Workspace location region zone. - - `type` - (String) The Workspace location region type. - - `url`- (String) The Workspace location region url. - - `pi_workspace_name` - (String) The Workspace name. - - `pi_workspace_status` - (String) The Workspace status, `active`, `critical`, `failed`, `provisioning`. - - `pi_workspace_type` - (String) The Workspace type, `off-premises` or `on-premises`. + Nested schema for `Workspace location`: + - `region` - (String) Workspace location region zone. + - `type` - (String) Workspace location region type. + - `url`- (String) Workspace location region url. + - `pi_workspace_name` - (String) Workspace name. + - `pi_workspace_status` - (String) Workspace status, `active`, `critical`, `failed`, `provisioning`. + - `pi_workspace_type` - (String) Workspace type, `off-premises` or `on-premises`. diff --git a/website/docs/d/project.html.markdown b/website/docs/d/project.html.markdown index 7960495c97..9c68c304a4 100644 --- a/website/docs/d/project.html.markdown +++ b/website/docs/d/project.html.markdown @@ -37,7 +37,7 @@ Nested schema for **configs**: * `definition` - (List) The name and description of a project configuration. Nested schema for **definition**: * `description` - (String) A project configuration description. - * Constraints: The maximum length is `1024` characters. The minimum length is `0` characters. The value must match regular expression `/^$|^(?!\\s)(?!.*\\s$)[^\\x00-\\x1F]*$/`. + * Constraints: The default value is ``. The maximum length is `1024` characters. The minimum length is `0` characters. The value must match regular expression `/^$|^(?!\\s)(?!.*\\s$)[^\\x00-\\x1F]*$/`. * `name` - (String) The configuration name. It is unique within the account across projects and regions. * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9][a-zA-Z0-9-_ ]*$/`. * `deployment_model` - (String) The configuration type. @@ -85,8 +85,10 @@ Nested schema for **cumulative_needs_attention_view**: * `definition` - (List) The definition of the project. Nested schema for **definition**: * `description` - (String) A brief explanation of the project's use in the configuration of a deployable architecture. It is possible to create a project without providing a description. - * Constraints: The maximum length is `1024` characters. The minimum length is `0` characters. The value must match regular expression `/^$|^(?!\\s)(?!.*\\s$)[^\\x00-\\x1F]*$/`. + * Constraints: The default value is ``. The maximum length is `1024` characters. The minimum length is `0` characters. The value must match regular expression `/^$|^(?!\\s)(?!.*\\s$)[^\\x00-\\x1F]*$/`. * `destroy_on_delete` - (Boolean) The policy that indicates whether the resources are destroyed or not when a project is deleted. + * `monitoring_enabled` - (Boolean) A boolean flag to enable project monitoring. + * Constraints: The default value is `false`. * `name` - (String) The name of the project. It is unique within the account across regions. * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^(?!\\s)(?!.*\\s$)[^'"`<>{}\\x00-\\x1F]+$/`. @@ -97,7 +99,7 @@ Nested schema for **environments**: * `definition` - (List) The environment definition used in the project collection. Nested schema for **definition**: * `description` - (String) The description of the environment. - * Constraints: The maximum length is `1024` characters. The minimum length is `0` characters. The value must match regular expression `/^$|^(?!\\s)(?!.*\\s$)[^\\x00-\\x1F]*$/`. + * Constraints: The default value is ``. The maximum length is `1024` characters. The minimum length is `0` characters. The value must match regular expression `/^$|^(?!\\s)(?!.*\\s$)[^\\x00-\\x1F]*$/`. * `name` - (String) The name of the environment. It is unique within the account across projects and regions. * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^(?!\\s)(?!.*\\s$)[^'"`<>{}\\x00-\\x1F]+$/`. * `href` - (String) A URL. diff --git a/website/docs/d/project_config.html.markdown b/website/docs/d/project_config.html.markdown index 21021df943..233f91b9d7 100644 --- a/website/docs/d/project_config.html.markdown +++ b/website/docs/d/project_config.html.markdown @@ -58,7 +58,7 @@ Nested schema for **definition**: * `profile_name` - (String) The name of the compliance profile. * Constraints: The maximum length is `1024` characters. The minimum length is `0` characters. The value must match regular expression `/^(?!\\s)(?!.*\\s$)[^`<>\\x00-\\x1F]*$/`. * `description` - (String) A project configuration description. - * Constraints: The maximum length is `1024` characters. The minimum length is `0` characters. The value must match regular expression `/^$|^(?!\\s)(?!.*\\s$)[^\\x00-\\x1F]*$/`. + * Constraints: The default value is ``. The maximum length is `1024` characters. The minimum length is `0` characters. The value must match regular expression `/^$|^(?!\\s)(?!.*\\s$)[^\\x00-\\x1F]*$/`. * `environment_id` - (String) The ID of the project environment. * Constraints: The maximum length is `128` characters. The value must match regular expression `/^[\\.\\-0-9a-zA-Z]+$/`. * `inputs` - (Map) The input variables for configuration definition and environment. diff --git a/website/docs/d/project_environment.html.markdown b/website/docs/d/project_environment.html.markdown index a975ff2fb4..d06f95d38e 100644 --- a/website/docs/d/project_environment.html.markdown +++ b/website/docs/d/project_environment.html.markdown @@ -58,7 +58,7 @@ Nested schema for **definition**: * `profile_name` - (String) The name of the compliance profile. * Constraints: The maximum length is `1024` characters. The minimum length is `0` characters. The value must match regular expression `/^(?!\\s)(?!.*\\s$)[^`<>\\x00-\\x1F]*$/`. * `description` - (String) The description of the environment. - * Constraints: The maximum length is `1024` characters. The minimum length is `0` characters. The value must match regular expression `/^$|^(?!\\s)(?!.*\\s$)[^\\x00-\\x1F]*$/`. + * Constraints: The default value is ``. The maximum length is `1024` characters. The minimum length is `0` characters. The value must match regular expression `/^$|^(?!\\s)(?!.*\\s$)[^\\x00-\\x1F]*$/`. * `inputs` - (Map) The input variables for configuration definition and environment. * `name` - (String) The name of the environment. It is unique within the account across projects and regions. * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^(?!\\s)(?!.*\\s$)[^'"`<>{}\\x00-\\x1F]+$/`. diff --git a/website/docs/d/secrets_manager_secret.html.markdown b/website/docs/d/secrets_manager_secret.html.markdown deleted file mode 100644 index 26cda83ab2..0000000000 --- a/website/docs/d/secrets_manager_secret.html.markdown +++ /dev/null @@ -1,9 +0,0 @@ ---- -subcategory: "Secrets Manager" -layout: "ibm" -page_title: "IBM : ibm_secrets_manager_secret" -description: |- - Get information about secrets manager secret ---- - -# ibm_secrets_manager_secret (Removed) \ No newline at end of file diff --git a/website/docs/d/secrets_manager_secrets.html.markdown b/website/docs/d/secrets_manager_secrets.html.markdown deleted file mode 100644 index 27899b85fe..0000000000 --- a/website/docs/d/secrets_manager_secrets.html.markdown +++ /dev/null @@ -1,10 +0,0 @@ ---- -subcategory: "Secrets Manager" -layout: "ibm" -page_title: "IBM : ibm_secrets_manager_secrets" -description: |- - Get information about secrets manager secrets. ---- - -# ibm_secrets_manager_secrets (Removed) - diff --git a/website/docs/d/sm_username_password_secret.html.markdown b/website/docs/d/sm_username_password_secret.html.markdown index 64768e067f..a376c69cb5 100644 --- a/website/docs/d/sm_username_password_secret.html.markdown +++ b/website/docs/d/sm_username_password_secret.html.markdown @@ -83,13 +83,20 @@ In addition to all argument references listed, you can access the following attr * `password` - (String) The password that is assigned to the secret. * Constraints: The maximum length is `64` characters. The minimum length is `6` characters. The value must match regular expression `/[A-Za-z0-9+-=.]*/`. +* `password_generation_policy` - (List) Policy for auto-generated passwords. + Nested scheme for **password_generation_policy**: + * `length` - (Integer) The length of auto-generated passwords. + * `include_digits` - (Boolean) Include digits in auto-generated passwords. + * `include_symbols` - (Boolean) Include symbols in auto-generated passwords. + * `include_uppercase` - (Boolean) Include uppercase letters in auto-generated passwords. + * `rotation` - (List) Determines whether Secrets Manager rotates your secrets automatically. Nested scheme for **rotation**: - * `auto_rotate` - (Boolean) Determines whether Secrets Manager rotates your secret automatically.Default is `false`. If `auto_rotate` is set to `true` the service rotates your secret based on the defined interval. - * `interval` - (Integer) The length of the secret rotation time interval. - * Constraints: The minimum value is `1`. - * `unit` - (String) The units for the secret rotation time interval. - * Constraints: Allowable values are: `day`, `month`. + * `auto_rotate` - (Boolean) Determines whether Secrets Manager rotates your secret automatically.Default is `false`. If `auto_rotate` is set to `true` the service rotates your secret based on the defined interval. + * `interval` - (Integer) The length of the secret rotation time interval. + * Constraints: The minimum value is `1`. + * `unit` - (String) The units for the secret rotation time interval. + * Constraints: Allowable values are: `day`, `month`. * `secret_group_id` - (String) A v4 UUID identifier, or `default` secret group. * Constraints: The maximum length is `36` characters. The minimum length is `7` characters. The value must match regular expression `/^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|default)$/`. diff --git a/website/docs/d/sm_username_password_secret_metadata.html.markdown b/website/docs/d/sm_username_password_secret_metadata.html.markdown index 781f524f1a..9e26afd431 100644 --- a/website/docs/d/sm_username_password_secret_metadata.html.markdown +++ b/website/docs/d/sm_username_password_secret_metadata.html.markdown @@ -64,6 +64,13 @@ In addition to all argument references listed, you can access the following attr * `next_rotation_date` - (String) The date that the secret is scheduled for automatic rotation.The service automatically creates a new version of the secret on its next rotation date. This field exists only for secrets that have an existing rotation policy. +* `password_generation_policy` - (List) Policy for auto-generated passwords. + Nested scheme for **password_generation_policy**: + * `length` - (Integer) The length of auto-generated passwords. + * `include_digits` - (Boolean) Include digits in auto-generated passwords. + * `include_symbols` - (Boolean) Include symbols in auto-generated passwords. + * `include_uppercase` - (Boolean) Include uppercase letters in auto-generated passwords. + * `rotation` - (List) Determines whether Secrets Manager rotates your secrets automatically. Nested scheme for **rotation**: * `auto_rotate` - (Boolean) Determines whether Secrets Manager rotates your secret automatically.Default is `false`. If `auto_rotate` is set to `true` the service rotates your secret based on the defined interval. diff --git a/website/docs/r/cbr_rule.html.markdown b/website/docs/r/cbr_rule.html.markdown index 82399a036b..e08049b341 100644 --- a/website/docs/r/cbr_rule.html.markdown +++ b/website/docs/r/cbr_rule.html.markdown @@ -101,7 +101,7 @@ resource "ibm_cbr_rule" "cbr_rule" { Review the argument reference that you can specify for your resource. * `contexts` - (Optional, List) The contexts this rule applies to. - * Constraints: The maximum length is `1000` items. The minimum length is `1` item. + * Constraints: The maximum length is `1000` items. The minimum length is `0` items. Nested scheme for **contexts**: * `attributes` - (Required, List) The attributes. * Constraints: The minimum length is `1` item. diff --git a/website/docs/r/cbr_zone.html.markdown b/website/docs/r/cbr_zone.html.markdown index 71a9db498c..1fa3dc850f 100644 --- a/website/docs/r/cbr_zone.html.markdown +++ b/website/docs/r/cbr_zone.html.markdown @@ -47,7 +47,7 @@ Review the argument reference that you can specify for your resource. * `account_id` - (Optional, String) The id of the account owning this zone. * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9\-]+$/`. * `addresses` - (Optional, List) The list of addresses in the zone. - * Constraints: The maximum length is `1000` items. The minimum length is `1` item. + * Constraints: The maximum length is `1000` items. The minimum length is `0` items. Nested scheme for **addresses**: * `ref` - (Optional, List) A service reference value. Nested scheme for **ref**: diff --git a/website/docs/r/container_cluster.html.markdown b/website/docs/r/container_cluster.html.markdown index 99a4629b65..d830e4fe38 100644 --- a/website/docs/r/container_cluster.html.markdown +++ b/website/docs/r/container_cluster.html.markdown @@ -27,7 +27,7 @@ The following example creates a single zone IBM Cloud Kubernetes Service cluster resource "ibm_container_cluster" "testacc_cluster" { name = "test" datacenter = "dal10" - machine_type = "free" + machine_type = "u2c.2x4" hardware = "shared" public_vlan_id = "vlan" private_vlan_id = "vlan" @@ -53,7 +53,7 @@ resource "ibm_container_cluster" "testacc_cluster" { resource "ibm_container_cluster" "testacc_cluster" { name = "test" datacenter = "dal10" - machine_type = "free" + machine_type = "u2c.2x4" hardware = "shared" public_vlan_id = "vlan" private_vlan_id = "vlan" @@ -219,9 +219,9 @@ Review the argument references that you can specify for your resource. - `operating_system` - (Optional, String) The operating system of the workers in the default worker pool. For supported options, see [Red Hat OpenShift on IBM Cloud version information](https://cloud.ibm.com/docs/openshift?topic=openshift-openshift_versions) or [IBM Cloud Kubernetes Service version information](https://cloud.ibm.com/docs/containers?topic=containers-cs_versions). This field only affects cluster creation, to manage the default worker pool, create a dedicated worker pool resource. - `patch_version` - (Optional, String) Updates the worker nodes with the required patch version. The patch_version should be in the format: `patch_version_fixpack_version`. For more information, about Kubernetes version information and update, see [Kubernetes version update](https://cloud.ibm.com/docs/containers?topic=containers-cs_versions). **NOTE:** To update the patch or fix pack versions of the worker nodes, run the command `ibmcloud ks workers -c output json`. Fetch the required patch & fix pack versions from `kubeVersion.target` and set the `patch_version` parameter. - `public_service_endpoint` - (Optional, Forces new resource, Bool) If set to **true**, your cluster is set up with a public service endpoint. You can use the public service endpoint to access the Kubernetes master from the public network. To use service endpoints, your account must be enabled for [Virtual Routing and Forwarding (VRF)](https://cloud.ibm.com/docs/account?topic=account-vrf-service-endpoint#vrf). For more information, see [Worker-to-master and user-to-master communication: Service endpoints](https://cloud.ibm.com/docs/containers?topic=containers-plan_clusters#workeruser-master). If set to **false**, the public service endpoint is disabled for your cluster. -- `public_vlan_id` - (Optional, String) The ID of the public VLAN that you want to use for the worker nodes in the default worker pool. You can retrieve the VLAN ID with the `ibmcloud ks vlans --zone ` command.

* **Free clusters**: If you want to provision a free cluster, you do not need to enter a public VLAN ID. Your cluster is automatically connected to a public VLAN that is owned by IBM.
* **Standard clusters**: If you create a standard cluster and you have an existing public VLAN ID for the zone where you plan to set up worker nodes, you must enter the VLAN ID. To retrieve the ID, run `ibmcloud ks vlans --zone `. If you do not have an existing public VLAN ID, or you want to connect your cluster to a private VLAN only, do not specify this option. **Note**: The prerequisite for using service endpoints, account must be enabled for [Virtual Routing and Forwarding (VRF)](https://cloud.ibm.com/docs/infrastructure/direct-link/vrf-on-ibm-cloud.html#overview-of-virtual-routing-and-forwarding-vrf-on-ibm-cloud). Account must be enabled for connectivity to service endpoints. Use the resource `ibm_container_cluster_feature` to update the `public_service_endpoint` and `private_service_endpoint`. This field only affects cluster creation, to manage the default worker pool, create a dedicated worker pool resource. +- `public_vlan_id` - (Optional, String) The ID of the public VLAN that you want to use for the worker nodes in the default worker pool. You can retrieve the VLAN ID with the `ibmcloud ks vlans --zone ` command.

* **Free clusters**: If you create a standard cluster and you have an existing public VLAN ID for the zone where you plan to set up worker nodes, you must enter the VLAN ID. To retrieve the ID, run `ibmcloud ks vlans --zone `. If you do not have an existing public VLAN ID, or you want to connect your cluster to a private VLAN only, do not specify this option. **Note**: The prerequisite for using service endpoints, account must be enabled for [Virtual Routing and Forwarding (VRF)](https://cloud.ibm.com/docs/infrastructure/direct-link/vrf-on-ibm-cloud.html#overview-of-virtual-routing-and-forwarding-vrf-on-ibm-cloud). Account must be enabled for connectivity to service endpoints. Use the resource `ibm_container_cluster_feature` to update the `public_service_endpoint` and `private_service_endpoint`. This field only affects cluster creation, to manage the default worker pool, create a dedicated worker pool resource. - `private_service_endpoint` - (Optional, Forces new resource, Bool) If set to **true**, your cluster is set up with a private service endpoint. When the private service endpoint is enabled, communication between the Kubernetes and the worker nodes is established over the private network. If you enable the private service endpoint, you cannot disable it later. To use service endpoints, your account must be enabled for [Virtual Routing and Forwarding (VRF)](https://cloud.ibm.com/docs/account?topic=account-vrf-service-endpoint#vrf). For more information, see [Worker-to-master and user-to-master communication: Service endpoints](https://cloud.ibm.com/docs/containers?topic=containers-plan_clusters#workeruser-master). If set to **false**, the private service endpoint is disabled and all communication to the Kubernetes master must go through the public network. -- `private_vlan_id` - (Optional, String) The ID of the private VLAN that you want to use for the worker nodes in your default worker pool. You can retrieve the VLAN ID with the `ibmcloud ks vlans --zone ` command.

* **Free clusters**: If you want to provision a free cluster, you do not need to enter a private VLAN ID. Your cluster is automatically connected to a private VLAN that is owned by IBM.
* **Standard clusters**: If you create a standard cluster and you have an existing private VLAN ID for the zone where you plan to set up worker nodes, you must enter the VLAN ID. To retrieve the ID, run `ibmcloud ks vlans --zone `. If you do not have an existing private VLAN ID, do not specify this option. A private VLAN is created automatically for you. This field only affects cluster creation, to manage the default worker pool, create a dedicated worker pool resource. +- `private_vlan_id` - (Optional, String) The ID of the private VLAN that you want to use for the worker nodes in your default worker pool. You can retrieve the VLAN ID with the `ibmcloud ks vlans --zone ` command.

* * **Standard clusters**: If you create a standard cluster and you have an existing private VLAN ID for the zone where you plan to set up worker nodes, you must enter the VLAN ID. To retrieve the ID, run `ibmcloud ks vlans --zone `. If you do not have an existing private VLAN ID, do not specify this option. A private VLAN is created automatically for you. This field only affects cluster creation, to manage the default worker pool, create a dedicated worker pool resource. - `pod_subnet`- (Optional, String) Specify a custom subnet CIDR to provide private IP addresses for pods. The subnet must be at least `/23` or more. For more information, refer to [Pod subnet](https://cloud.ibm.com/docs/containers?topic=containers-cli-plugin-kubernetes-service-cli#pod-subnet).Yes- - `resource_group_id` - (Optional, String) The ID of the resource group where you want to provision your cluster. To retrieve the ID, use the `ibm_resource_group` data source. If no value is provided, the cluster is automatically provisioned into the `default` resource group. - `retry_patch_version` - (Optional, Integer) This argument retries the update of `patch_version` if the previous update fails. Increment the value to retry the update of `patch_version` on worker nodes. diff --git a/website/docs/r/container_vpc_cluster.html.markdown b/website/docs/r/container_vpc_cluster.html.markdown index 921964b348..ec7c814b9c 100644 --- a/website/docs/r/container_vpc_cluster.html.markdown +++ b/website/docs/r/container_vpc_cluster.html.markdown @@ -9,7 +9,6 @@ description: |- # ibm_container_vpc_cluster Create, update, or delete a VPC cluster. To create a VPC cluster, make sure to include the VPC infrastructure generation in the `provider` block of your Terraform configuration file. If you do not set this value, the generation is automatically set to 2. For more information, about how to configure the `provider` block, see [Overview of required input parameters for each resource category](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-provider-reference#required-parameters). -You cannot create a free cluster in IBM Cloud Schematics. If you want to delete a VPC cluster and their associated load balancer. The following order is followed by the resource. 1. Invokes the cluster deletion. @@ -246,6 +245,7 @@ In addition to all argument reference list, you can access the following attribu - `master_status` - (String) The status of the Kubernetes master. - `master_url` - (String) The URL of the Kubernetes master. - `private_service_endpoint_url` - (String) The private service endpoint URL. +- `vpe_service_endpoint_url` - (String) The virtual private endpoint URL. - `public_service_endpoint_url` - (String) The public service endpoint URL. - `state` - (String) The state of the VPC cluster. diff --git a/website/docs/r/en_destination_android.html.markdown b/website/docs/r/en_destination_android.html.markdown index 4c9867ef5a..bc0647261f 100644 --- a/website/docs/r/en_destination_android.html.markdown +++ b/website/docs/r/en_destination_android.html.markdown @@ -14,10 +14,11 @@ Create, update, or delete a FCM destination by using IBM Cloudâ„¢ Event Notific ```terraform resource "ibm_en_destination_android" "android_en_destination" { - instance_guid = ibm_resource_instance.en_terraform_test_resource.guid - name = "Android Destination" - type = "push_android" - description = "The Android Destination" + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "Android Destination" + type = "push_android" + collect_failed_events = false + description = "The Android Destination" config { params { project_id = "5237288990" @@ -41,6 +42,7 @@ Review the argument reference that you can specify for your resource. - `type` - (Required, String) push_android. +- `collect_failed_events` - (boolean) Toggle switch to enable collect failed event in Cloud Object Storage bucket. - `config` - (Optional, List) Payload describing a destination configuration. diff --git a/website/docs/r/en_destination_ce.html.markdown b/website/docs/r/en_destination_ce.html.markdown index 331d376662..ebe44ae85e 100644 --- a/website/docs/r/en_destination_ce.html.markdown +++ b/website/docs/r/en_destination_ce.html.markdown @@ -14,10 +14,11 @@ Create, update, or delete a Code Engine destination by using IBM Cloudâ„¢ Event ```terraform resource "ibm_en_destination_ce" "codeengine_en_destination" { - instance_guid = ibm_resource_instance.en_terraform_test_resource.guid - name = "Code engine Destination" - type = "ibmce" - description = "Code Engine destination for event notification" + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "Code engine Destination" + type = "ibmce" + collect_failed_events = false + description = "Code Engine destination for event notification" config { params { verb = "POST" @@ -43,6 +44,8 @@ Review the argument reference that you can specify for your resource. - `type` - (Required, String) ibmce. +- `collect_failed_events` - (boolean) Toggle switch to enable collect failed event in Cloud Object Storage bucket. + - `config` - (Optional, List) Payload describing a destination configuration. Nested scheme for **config**: diff --git a/website/docs/r/en_destination_cf.html.markdown b/website/docs/r/en_destination_cf.html.markdown index 0e01b26f48..0c498b31c2 100644 --- a/website/docs/r/en_destination_cf.html.markdown +++ b/website/docs/r/en_destination_cf.html.markdown @@ -14,10 +14,11 @@ Create, update, or delete a IBM Cloud Functions destination by using IBM Cloud ```terraform resource "ibm_en_destination_cf" "cf_en_destination" { - instance_guid = ibm_resource_instance.en_terraform_test_resource.guid - name = "Cloud Function Test Destination" - type = "ibmcf" - description = "Destination Chrome for event notification" + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "Cloud Function Test Destination" + type = "ibmcf" + collect_failed_events = true + description = "Destination Chrome for event notification" config { params { api_key = "XYZ" @@ -39,6 +40,8 @@ Review the argument reference that you can specify for your resource. - `type` - (Required, String) ibmcf. +- `collect_failed_events` - (boolean) Toggle switch to enable collect failed event in Cloud Object Storage bucket. + - `config` - (Optional, List) Payload describing a destination configuration. Nested scheme for **config**: diff --git a/website/docs/r/en_destination_chrome.html.markdown b/website/docs/r/en_destination_chrome.html.markdown index 6a678834e5..9141e62ae2 100644 --- a/website/docs/r/en_destination_chrome.html.markdown +++ b/website/docs/r/en_destination_chrome.html.markdown @@ -14,10 +14,11 @@ Create, update, or delete a Chrome destination by using IBM Cloudâ„¢ Event Notif ```terraform resource "ibm_en_destination_chrome" "chrome_en_destination" { - instance_guid = ibm_resource_instance.en_terraform_test_resource.guid - name = "My Chrome Destination" - type = "push_chrome" - description = "Destination Chrome for event notification" + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "My Chrome Destination" + type = "push_chrome" + collect_failed_events = false + description = "Destination Chrome for event notification" config { params { api_key = "The FCM api key for project" @@ -40,6 +41,8 @@ Review the argument reference that you can specify for your resource. - `type` - (Required, String) push_chrome. +- `collect_failed_events` - (boolean) Toggle switch to enable collect failed event in Cloud Object Storage bucket. + - `config` - (Optional, List) Payload describing a destination configuration. Nested scheme for **config**: diff --git a/website/docs/r/en_destination_cos.html.markdown b/website/docs/r/en_destination_cos.html.markdown index 357474d94f..a9c5530dcd 100644 --- a/website/docs/r/en_destination_cos.html.markdown +++ b/website/docs/r/en_destination_cos.html.markdown @@ -14,10 +14,11 @@ Create, update, or delete a IBM Cloud Object Storage destination by using IBM Cl ```terraform resource "ibm_en_destination_cos" "cos_en_destination" { - instance_guid = ibm_resource_instance.en_terraform_test_resource.guid - name = "COS Test Destination" - type = "ibmcos" - description = "IBM Cloud Object Storage Destination for event notification" + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "COS Test Destination" + type = "ibmcos" + collect_failed_events = true + description = "IBM Cloud Object Storage Destination for event notification" config { params { bucket_name = "cos-test-bucket" @@ -40,6 +41,8 @@ Review the argument reference that you can specify for your resource. - `type` - (Required, String) ibmcos. +- `collect_failed_events` - (boolean) Toggle switch to enable collect failed event in Cloud Object Storage bucket. + - `config` - (Optional, List) Payload describing a destination configuration. Nested scheme for **config**: diff --git a/website/docs/r/en_destination_custom_email.html.markdown b/website/docs/r/en_destination_custom_email.html.markdown index 5f5b9cc1b6..931dd5e6df 100644 --- a/website/docs/r/en_destination_custom_email.html.markdown +++ b/website/docs/r/en_destination_custom_email.html.markdown @@ -14,10 +14,11 @@ Create, update, or delete a Custom Email destination by using IBM Cloudâ„¢ Event ```terraform resource "ibm_en_destination_custom_email" "custom_domain_en_destination" { - instance_guid = ibm_resource_instance.en_terraform_test_resource.guid - name = "Custom Email EN Destination" - type = "smtp_custom" - description = "Destination Custom Email for event notification" + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "Custom Email EN Destination" + type = "smtp_custom" + collect_failed_events = true + description = "Destination Custom Email for event notification" config { params { domain = "mailx.com" @@ -54,6 +55,8 @@ Review the argument reference that you can specify for your resource. - `type` - (Required, String) smtp_custom. +- `collect_failed_events` - (boolean) Toggle switch to enable collect failed event in Cloud Object Storage bucket. + - `config` - (Optional, List) Payload describing a destination configuration. Nested scheme for **config**: diff --git a/website/docs/r/en_destination_custom_sms.html.markdown b/website/docs/r/en_destination_custom_sms.html.markdown new file mode 100644 index 0000000000..3eea1172a5 --- /dev/null +++ b/website/docs/r/en_destination_custom_sms.html.markdown @@ -0,0 +1,68 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_destination_custom_sms' +description: |- + Manages Event Notification Custom SMS destination. +--- + +# ibm_en_destination_custom_sms + +Create, update, or delete a Custom SMS destination by using IBM Cloudâ„¢ Event Notifications. + +## Example usage + +```terraform +resource "ibm_en_destination_custom_sms" "custom_sms_en_destination" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "Custom SMS EN Destination" + type = "sms_custom" + collect_failed_events = true + description = "Destination Custom SMS for event notification" +} +``` + +## Argument reference + +Review the argument reference that you can specify for your resource. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `name` - (Required, String) The Destintion name. + +- `description` - (Optional, String) The Destination description. + +- `type` - (Required, String) sms_custom. + +- `collect_failed_events` - (boolean) Toggle switch to enable collect failed event in Cloud Object Storage bucket. + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +- `id` - (String) The unique identifier of the `custom_sms_en_destination`. +- `destination_id` - (String) The unique identifier of the created destination. +- `subscription_count` - (Integer) Number of subscriptions. + - Constraints: The minimum value is `0`. +- `subscription_names` - (List) List of subscriptions. +- `updated_at` - (String) Last updated time. + +## Import + +You can import the `ibm_en_destination_custom_sms` resource by using `id`. + +The `id` property can be formed from `instance_guid`, and `destination_id` in the following format: + +``` +/ +``` + +- `instance_guid`: A string. Unique identifier for IBM Cloud Event Notifications instance. + +- `destination_id`: A string. Unique identifier for Destination. + +**Example** + +``` +$ terraform import ibm_en_destination_custom_sms.custom_domain_sms_en_destination / +``` diff --git a/website/docs/r/en_destination_firefox.html.markdown b/website/docs/r/en_destination_firefox.html.markdown index 892944d7d3..24a4acdf6e 100644 --- a/website/docs/r/en_destination_firefox.html.markdown +++ b/website/docs/r/en_destination_firefox.html.markdown @@ -14,10 +14,11 @@ Create, update, or delete a firefox destination by using IBM Cloudâ„¢ Event Noti ```terraform resource "ibm_en_destination_firefox" "firefox_en_destination" { - instance_guid = ibm_resource_instance.en_terraform_test_resource.guid - name = "My Firefox Destination" - type = "push_firefox" - description = "Destination firefox for event notification" + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "My Firefox Destination" + type = "push_firefox" + collect_failed_events = false + description = "Destination firefox for event notification" config { params { website_url = "https://testwebsite.com" @@ -39,6 +40,8 @@ Review the argument reference that you can specify for your resource. - `type` - (Required, String) push_firefox. +- `collect_failed_events` - (boolean) Toggle switch to enable collect failed event in Cloud Object Storage bucket. + - `config` - (Optional, List) Payload describing a destination configuration. Nested scheme for **config**: diff --git a/website/docs/r/en_destination_huawei.html.markdown b/website/docs/r/en_destination_huawei.html.markdown index e1772d4068..4e5b5d87f2 100644 --- a/website/docs/r/en_destination_huawei.html.markdown +++ b/website/docs/r/en_destination_huawei.html.markdown @@ -14,10 +14,11 @@ Create, update, or delete a Huawei destination by using IBM Cloudâ„¢ Event Noti ```terraform resource "ibm_en_destination_huawei" "huawei_en_destination" { - instance_guid = ibm_resource_instance.en_terraform_test_resource.guid - name = "Huawei Destination" - type = "push_huawei" - description = "The Huawei Destination" + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "Huawei Destination" + type = "push_huawei" + collect_failed_events = false + description = "The Huawei Destination" config { params { client_id = "5237288990" @@ -40,6 +41,7 @@ Review the argument reference that you can specify for your resource. - `type` - (Required, String) push_huawei. +- `collect_failed_events` - (boolean) Toggle switch to enable collect failed event in Cloud Object Storage bucket. - `config` - (Optional, List) Payload describing a destination configuration. diff --git a/website/docs/r/en_destination_ios.html.markdown b/website/docs/r/en_destination_ios.html.markdown index 431487abbd..c026ab373b 100644 --- a/website/docs/r/en_destination_ios.html.markdown +++ b/website/docs/r/en_destination_ios.html.markdown @@ -15,19 +15,20 @@ Create, update, or delete IOS destination by using IBM Cloudâ„¢ Event Notificati ```terraform resource "ibm_en_destination_ios" "ios_en_destination" { instance_guid = ibm_resource_instance.en_terraform_test_resource.guid - name = "IOS Destination Auth" - type = "push_ios" + name = "IOS Destination Auth" + type = "push_ios" + collect_failed_events = false certificate_content_type = "p8" - certificate = "${path.module}/Certificates/Auth.p8" - description = "IOS destination with P8" + certificate = "${path.module}/Certificates/Auth.p8" + description = "IOS destination with P8" config { params { - cert_type = "p8" + cert_type = "p8" is_sandbox = true - key_id = production - team_id = "2347" - bundle_id = "testp8" - pre_prod = false + key_id = production + team_id = "2347" + bundle_id = "testp8" + pre_prod = false } } } @@ -64,6 +65,8 @@ Review the argument reference that you can specify for your resource. - `type` - (Required, String) push_ios. +- `collect_failed_events` - (boolean) Toggle switch to enable collect failed event in Cloud Object Storage bucket. + - `certificate_content_type` - (Required, String) The type of certificate, Values are p8/p12. - `certificate` - (Required, binary) Certificate file. The file type allowed is .p8 and .p12 diff --git a/website/docs/r/en_destination_msteams.html.markdown b/website/docs/r/en_destination_msteams.html.markdown index fdae33219e..4a87be785c 100644 --- a/website/docs/r/en_destination_msteams.html.markdown +++ b/website/docs/r/en_destination_msteams.html.markdown @@ -14,15 +14,17 @@ Create, update, or delete a MSTeams destination by using IBM Cloudâ„¢ Event Noti ```terraform resource "ibm_en_destination_msteams" "msteams_en_destination" { - instance_guid = ibm_resource_instance.en_terraform_test_resource.guid - name = "MSteams EN Destination" - type = "msteams" - description = "Destination MSTeams for event notification" + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "MSteams EN Destination" + type = "msteams" + collect_failed_events = false + description = "Destination MSTeams for event notification" config { params { url = "https://xyz.webhook.office.com" } } +} ``` ## Argument reference @@ -37,6 +39,8 @@ Review the argument reference that you can specify for your resource. - `type` - (Required, String) msteams. +- `collect_failed_events` - (boolean) Toggle switch to enable collect failed event in Cloud Object Storage bucket. + - `config` - (Optional, List) Payload describing a destination configuration. Nested scheme for **config**: diff --git a/website/docs/r/en_destination_pagerduty.html.markdown b/website/docs/r/en_destination_pagerduty.html.markdown index a44425eec8..a4af3fa51e 100644 --- a/website/docs/r/en_destination_pagerduty.html.markdown +++ b/website/docs/r/en_destination_pagerduty.html.markdown @@ -14,10 +14,11 @@ Create, update, or delete a pagerduty destination by using IBM Cloudâ„¢ Event No ```terraform resource "ibm_en_destination_pagerduty" "pagerduty_en_destination" { - instance_guid = ibm_resource_instance.en_terraform_test_resource.guid - name = "Pagerduty Destination" - type = "pagerduty" - description = "Destination pagerduty for event notification" + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "Pagerduty Destination" + type = "pagerduty" + collect_failed_events = false + description = "Destination pagerduty for event notification" config { params { api_key = "user token for assigned group" @@ -40,6 +41,8 @@ Review the argument reference that you can specify for your resource. - `type` - (Required, String) pagerduty. +- `collect_failed_events` - (boolean) Toggle switch to enable collect failed event in Cloud Object Storage bucket. + - `config` - (Optional, List) Payload describing a destination configuration. Nested scheme for **config**: diff --git a/website/docs/r/en_destination_safari.html.markdown b/website/docs/r/en_destination_safari.html.markdown index a4ff644243..518a41da17 100644 --- a/website/docs/r/en_destination_safari.html.markdown +++ b/website/docs/r/en_destination_safari.html.markdown @@ -17,6 +17,7 @@ resource "ibm_en_destination_safari" "safari_en_destination" { instance_guid = ibm_resource_instance.en_terraform_test_resource.guid name = "EN Safari Destination" type = "push_safari" + collect_failed_events = false certificate = "${path.module}/Certificates/safaricert.p12" icon_16x16 = "${path.module}/Certificates/safariicon.png" icon_16x16_2x = "${path.module}/Certificates/safariicon.png" @@ -56,6 +57,8 @@ Review the argument reference that you can specify for your resource. - `type` - (Required, String) push_safari. +- `collect_failed_events` - (boolean) Toggle switch to enable collect failed event in Cloud Object Storage bucket. + - `certificate` - (Required, binary) Certificate file. The file type allowed is .p8 and .p12 - `icon_16x16` - (Optional, binary) icon file of dimension 16x16 diff --git a/website/docs/r/en_destination_slack.html.markdown b/website/docs/r/en_destination_slack.html.markdown index 2e509778a5..c7b3cd8ce5 100644 --- a/website/docs/r/en_destination_slack.html.markdown +++ b/website/docs/r/en_destination_slack.html.markdown @@ -14,15 +14,17 @@ Create, update, or delete a Slack destination by using IBM Cloudâ„¢ Event Notifi ```terraform resource "ibm_en_destination_slack" "slack_en_destination" { - instance_guid = ibm_resource_instance.en_terraform_test_resource.guid - name = "My Slack Destination" - type = "slack" - description = "Destination slack for event notification" + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "My Slack Destination" + type = "slack" + collect_failed_events = false + description = "Destination slack for event notification" config { params { url = "https://hooks.slack.com/services/G0gyhsush/TYodsjhs/GHTbfidsimkk" } } +} ``` ## Argument reference @@ -37,6 +39,8 @@ Review the argument reference that you can specify for your resource. - `type` - (Required, String) slack. +- `collect_failed_events` - (boolean) Toggle switch to enable collect failed event in Cloud Object Storage bucket. + - `config` - (Optional, List) Payload describing a destination configuration. Nested scheme for **config**: diff --git a/website/docs/r/en_destination_sn.html.markdown b/website/docs/r/en_destination_sn.html.markdown index 18a9668241..6c68ba846f 100644 --- a/website/docs/r/en_destination_sn.html.markdown +++ b/website/docs/r/en_destination_sn.html.markdown @@ -14,10 +14,11 @@ Create, update, or delete a servicenow destination by using IBM Cloudâ„¢ Event N ```terraform resource "ibm_en_destination_sn" "servicenow_en_destination" { - instance_guid = ibm_resource_instance.en_terraform_test_resource.guid - name = "Service Now Destination" - type = "servicenow" - description = "Destination servicenow for event notification" + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "Service Now Destination" + type = "servicenow" + collect_failed_events = false + description = "Destination servicenow for event notification" config { params { client_id = "321efc4f9c974b03d0fd959a81d8d8e8fyeyee" @@ -43,6 +44,8 @@ Review the argument reference that you can specify for your resource. - `type` - (Required, String) pagerduty. +- `collect_failed_events` - (boolean) Toggle switch to enable collect failed event in Cloud Object Storage bucket. + - `config` - (Optional, List) Payload describing a destination configuration. Nested scheme for **config**: diff --git a/website/docs/r/en_destination_webhook.html.markdown b/website/docs/r/en_destination_webhook.html.markdown index 74caa29ac7..b7336be1bd 100644 --- a/website/docs/r/en_destination_webhook.html.markdown +++ b/website/docs/r/en_destination_webhook.html.markdown @@ -14,10 +14,11 @@ Create, update, or delete a Webhook destination by using IBM Cloudâ„¢ Event Noti ```terraform resource "ibm_en_destination_webhook" "webhook_en_destination" { - instance_guid = ibm_resource_instance.en_terraform_test_resource.guid - name = "My Webhook Destination" - type = "webhook" - description = "Destination webhook for event notification" + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "My Webhook Destination" + type = "webhook" + collect_failed_events = false + description = "Destination webhook for event notification" config { params { verb = "POST" @@ -43,6 +44,8 @@ Review the argument reference that you can specify for your resource. - `type` - (Required, String) Webhook. +- `collect_failed_events` - (boolean) Toggle switch to enable collect failed event in Cloud Object Storage bucket. + - `config` - (Optional, List) Payload describing a destination configuration. Nested scheme for **config**: diff --git a/website/docs/r/en_email_template.html.markdown b/website/docs/r/en_email_template.html.markdown new file mode 100644 index 0000000000..3110bc8e26 --- /dev/null +++ b/website/docs/r/en_email_template.html.markdown @@ -0,0 +1,76 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_email_template' +description: |- + Manages Event Notification Email Templates. +--- + +# ibm_en_email_template + +Create, update, or delete Email Template by using IBM Cloudâ„¢ Event Notifications. + +## Example usage + +```terraform +resource "ibm_en_email_template" "email_template" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "Notification Template" + type = "smtp_custom.notification" + description = "Destination Custom Email for event notification" + params { + body = "Go To-Do list

To-Do list for user: {{ Data.issuer.p }}

{{#each Email}}{{/each}}
TaskDone
{{ this }}
" + subject = "HI This is the template subject for the invitation" + } +} +``` + +## Argument reference + +Review the argument reference that you can specify for your resource. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `name` - (Required, String) The Message Template. + +- `description` - (Optional, String) The Template description. + +- `type` - (Required, String) smtp_custom.notification/smtp_custom.invitation. + +- `params` - (Required, List) Payload describing a template configuration + + Nested scheme for **params**: + + - `body` - (Required, String) The Body for Email Template. + + - `subject` - (Required, String) The Subject of Email Template +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +- `id` - (String) The unique identifier of the `email_template`. +- `template_id` - (String) The unique identifier of the created Template. +- `subscription_count` - (Integer) Number of subscriptions. + - Constraints: The minimum value is `0`. +- `subscription_names` - (List) List of subscriptions. +- `updated_at` - (String) Last updated time. + +## Import + +You can import the `ibm_en_email_template` resource by using `id`. + +The `id` property can be formed from `instance_guid`, and `template_id` in the following format: + +``` +/ +``` + +- `instance_guid`: A string. Unique identifier for IBM Cloud Event Notifications instance. + +- `template_id`: A string. Unique identifier for Template. + +**Example** + +``` +$ terraform import ibm_en_email_template.email_template / +``` diff --git a/website/docs/r/en_integration_cos.html.markdown b/website/docs/r/en_integration_cos.html.markdown new file mode 100644 index 0000000000..39943a2276 --- /dev/null +++ b/website/docs/r/en_integration_cos.html.markdown @@ -0,0 +1,69 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_integration_cos' +description: |- + Manages Event Notifications COS Integration. +--- + +# ibm_en_integration + +Manage COS integration using IBM Cloudâ„¢ Event Notifications. + +## Example usage + +```terraform +resource "ibm_en_integration" "en_cos_integration" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + type = "collect_failed_events" + metadata { + endpoint = "https://s3.us-west.cloud-object-storage.test.appdomain.cloud", + crn = "crn:v1:bluemix:public:cloud-object-storage:global:xxxx6db359a81a1dde8f44bxxxxxx:xxxx-1d48-xxxx-xxxx-xxxxxxxxxxxx::" + bucket_name = "cloud-object-storage" + } +} +``` + +## Argument reference + +Review the argument reference that you can specify for your resource. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `type` - (Required, String) The integration type collect_failed_events. + +- `metadata` - (Required, List) + + Nested scheme for **params**: + + - `endpoint` - (Required, String) endpoint url for COS bucket region. + - `crn` - (Required, String) CRN of the COS instance. + - `bucket_name` - (Required, String) cloud object storage bucket name. + + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +- `id` - (String) The unique identifier of the `en_cos_integration`. +- `updated_at` - (String) Last updated time. + +## Import + +You can import the `ibm_en_integration_cos` resource by using `id`. + +The `id` property can be formed from `instance_guid`, and `integration_id` in the following format: + +``` +/ +``` + +- `instance_guid`: A string. Unique identifier for IBM Cloud Event Notifications instance. + +- `integration_id`: A string. Unique identifier for Integration. + +**Example** + +``` +$ terraform import ibm_en_integration_cos.en_cos_integration / +``` diff --git a/website/docs/r/en_subscription_custom_sms.html.markdown b/website/docs/r/en_subscription_custom_sms.html.markdown new file mode 100644 index 0000000000..79455e33aa --- /dev/null +++ b/website/docs/r/en_subscription_custom_sms.html.markdown @@ -0,0 +1,93 @@ +--- +subcategory: 'Event Notifications' +layout: 'ibm' +page_title: 'IBM : ibm_en_subscription_custom_sms' +description: |- + Manages Event Notifications Custom SMS subscription. +--- + +# ibm_en_subscription_custom_sms + +Create, update, or delete a Custom SMS Destination subscription by using IBM Cloudâ„¢ Event Notifications. + +## Example usage for SMS Subscription Creation + +```terraform +resource "ibm_en_subscription_sms" "sms_subscription" { + instance_guid = ibm_resource_instance.en_terraform_test_resource.guid + name = "Non IBM SMS Destination Subscription" + description = "Custom SMS Destination subscription" + destination_id = ibm_en_destination_custom_sms.custom_sms_en_destination.destination_id + topic_id = ibm_en_topic.topic1.topic_id + attributes { + invited = ["+15678923404", "+19643567389"] + } +} +``` + +## Example usage for SMS Subscription Updation + +```terraform +resource "ibm_en_subscription_custom_sms" "custom_sms_subscription" { + instance_guid = "my_instance_guid" + name = "Non IBM SMS Destination Subscription" + description = "Subscription for Certificate expiration alert" + destination_id = ibm_en_destination_custom_sms.custom_sms_en_destination.destination_id + topic_id = ibm_en_topic.topic1.topic_id + attributes { + add = ["+19643744902"] + remove = ["+19807485102"] + } +} +``` + +## Argument reference + +Review the argument reference that you can specify for your resource. + +- `instance_guid` - (Required, Forces new resource, String) Unique identifier for IBM Cloud Event Notifications instance. + +- `name` - (Requires, String) Subscription name. + +- `description` - (Optional, String) Subscription description. + +- `destination_id` - (Requires, String) Destination ID. + +- `topic_id` - (Required, String) Topic ID. + +- `attributes` - (Optional, List) Subscription attributes. + Nested scheme for **attributes**: + + - `invited` - (Optional, List) The phone number to send the SMS to. + + - `add`- (List) The phone number to add in case of updating the list of contact + + - `reomve`- (List) The phone number list to be provided in case of removing the contact number from subscription + +## Attribute reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +- `id` - (String) The unique identifier of the `custon_sms_subscription`. + +- `subscription_id` - (String) The unique identifier of the created subscription. + +- `updated_at` - (String) Last updated time. + +## Import + +You can import the `ibm_en_subscription_custom_sms` resource by using `id`. +The `id` property can be formed from `instance_guid`, and `subscription_id` in the following format: + +``` +/ +``` + +- `instance_guid`: A string. Unique identifier for IBM Cloud Event Notifications instance. +- `subscription_id`: A string. Unique identifier for Subscription. + +**Example** + +``` +$ terraform import ibm_en_subscription_custom_sms.custom_sms_subscription / +``` diff --git a/website/docs/r/en_subscription_sms.html.markdown b/website/docs/r/en_subscription_sms.html.markdown index 798efb54e8..879e7f6ea4 100644 --- a/website/docs/r/en_subscription_sms.html.markdown +++ b/website/docs/r/en_subscription_sms.html.markdown @@ -28,12 +28,12 @@ resource "ibm_en_subscription_sms" "sms_subscription" { ## Example usage for SMS Subscription Updation ```terraform -resource "ibm_en_subscription_email" "email_subscription" { +resource "ibm_en_subscription_sms" "sms_subscription" { instance_guid = "my_instance_guid" - name = "Email Certificate Subscription" + name = "IBM SMS Certificate Subscription" description = "Subscription for Certificate expiration alert" - destination_id = "email_destination_id" - topic_id = "topicId" + destination_id = [for s in toset(data.ibm_en_destinations.destinations.destinations): s.id if s.type == "sms_ibm"].0 + topic_id = ibm_en_topic.topic1.topic_id attributes { add = ["+19643744902"] remove = ["+19807485102"] @@ -60,9 +60,9 @@ Review the argument reference that you can specify for your resource. - `invited` - (Optional, List) The phone number to send the SMS to. - - `add`- (List) The phone number to add in case of updating the list of email addressses + - `add`- (List) The phone number to add in case of updating the list of contact - - `reomve`- (List) The phone number list to be provided in case of removing the email addresses from subscription + - `reomve`- (List) The phone number list to be provided in case of removing the contact number from subscription ## Attribute reference diff --git a/website/docs/r/iam_authorization_policy.html.markdown b/website/docs/r/iam_authorization_policy.html.markdown index 2758bb8b9d..bac30292cc 100644 --- a/website/docs/r/iam_authorization_policy.html.markdown +++ b/website/docs/r/iam_authorization_policy.html.markdown @@ -66,9 +66,9 @@ resource "ibm_resource_instance" "instance2" { resource "ibm_iam_authorization_policy" "policy" { source_service_name = "cloud-object-storage" - source_resource_instance_id = ibm_resource_instance.instance1.id + source_resource_instance_id = ibm_resource_instance.instance1.guid target_service_name = "kms" - target_resource_instance_id = ibm_resource_instance.instance2.id + target_resource_instance_id = ibm_resource_instance.instance2.guid roles = ["Reader"] } @@ -156,6 +156,40 @@ resource "ibm_iam_authorization_policy" "policy" { } ``` +### Authorization policy between all resource groups in an account and a target service using resource attributes + +```terraform + +resource "ibm_resource_group" "source_resource_group" { + name = "123123" +} + +resource "ibm_iam_authorization_policy" "policy" { + roles = [ + "Reader", + ] + + resource_attributes { + name = "accountId" + operator = "stringEquals" + value = "12345" + } + resource_attributes { + name = "serviceName" + operator = "stringEquals" + value = "cloud-object-storage" + } + + subject_attributes { + name = "accountId" + value = "12345" + } + subject_attributes { + name = "resourceGroupId" + value = "*" + } +} +``` ### Authorization policy between source service and target resource type "resource-group" using resource attributes diff --git a/website/docs/r/is_bare_metal_server.markdown b/website/docs/r/is_bare_metal_server.markdown index 8af43463d7..1225f6b240 100644 --- a/website/docs/r/is_bare_metal_server.markdown +++ b/website/docs/r/is_bare_metal_server.markdown @@ -77,6 +77,25 @@ resource "ibm_is_bare_metal_server" "bms" { vpc = ibm_is_vpc.example.id } +``` +### VNI example +```terraform +resource "ibm_is_bare_metal_server" "bms" { + 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_attachment { + name = "test-vni-100-102" + virtual_network_interface { + id = ibm_is_virtual_network_interface.testacc_vni.id + } + allowed_vlans = [100, 102] + } + vpc = ibm_is_vpc.example.id +} + ``` ## Timeouts @@ -111,6 +130,41 @@ Review the argument references that you can specify for your resource. -> **NOTE:** a bare metal server can take up to 30 mins to clean up on delete, replacement/re-creation using the same name may return error +- `network_attachments` - (Optional, List) The network attachments for this bare metal server, including the primary network attachment. + Nested schema for **network_attachments**: + - `allowed_vlans` - (Optional, Array) Comma separated VLANs, Indicates what VLAN IDs (for VLAN type only) can use this physical (`PCI`, `VLAN` type) interface. A given VLAN can only be in the allowed_vlans array for one PCI type adapter per bare metal server. + - `interface_type` - (Optional, String) The type of the network interface.[**pci**, **vlan**]. + - `name` - (Required, String) Name for this network attachment. + - `virtual_network_interface` - (Optional, List) The virtual network interface details for this target. + Nested schema for **virtual_network_interface**: + - `allow_ip_spoofing` - (Optional, Boolean) Indicates whether source IP spoofing is allowed on this interface. If `false`, source IP spoofing is prevented on this interface. If `true`, source IP spoofing is allowed on this interface. + - `auto_delete` - (Optional, Boolean) Indicates whether this virtual network interface will be automatically deleted when`target` is deleted. + - `enable_infrastructure_nat` - (Optional, 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 network interface, allowing the workload to perform any needed NAT operations.- `allow_ip_spoofing` must be `false`.- If the virtual network interface is attached: - The target `resource_type` must be `bare_metal_server_network_attachment`. - The target `interface_type` must not be `hipersocket`. + - `ips` - (Optional, List) The reserved IPs bound to this virtual network interface.May be empty when `lifecycle_state` is `pending`. + Nested schema for **ips**: + - `address` - (Required, String) The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `deleted` - (Optional, 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 reserved IP. + - `reserved_ip` - (Required, String) The unique identifier for this reserved IP. + - `name` - (Required, String) The name for this reserved IP. The name is unique across all reserved IPs in a subnet. + - `resource_type` - (Computed, String) The resource type. + - `name` - (Optional, String) The name for this virtual network interface. The name is unique across all virtual network interfaces in the VPC. + - `primary_ip` - (Optional, List) The reserved IP for this virtual network interface. + Nested schema for **primary_ip**: + - `address` - (Required, String) The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `deleted` - (Optional, List) If present, this property indicates the referenced resource has been deleted, and providessome supplementary information. + Nested schema for **deleted**: + - `more_info` - (Required, String) Link to documentation about deleted resources. + - `href` - (Required, String) The URL for this reserved IP. + - `reserved_ip` - (Required, String) The unique identifier for this reserved IP. + - `name` - (Required, String) The name for this reserved IP. The name is unique across all reserved IPs in a subnet. + - `resource_type` - (Computed, String) The resource type. + - `resource_group` - (Optional, List) The resource group id for this virtual network interface. + - `security_groups` - (Optional, Array of string) The security group ids list for this virtual network interface. + - `subnet` - (Optional, List) The associated subnet id. + - `vlan` - (Optional, Integer) Indicates the 802.1Q VLAN ID tag that must be used for all traffic on this interface. [ conflicts with `allowed_vlans`] - `network_interfaces` - (Optional, List) The additional network interfaces to create for the bare metal server to this bare metal server. Use `ibm_is_bare_metal_server_network_interface` & `ibm_is_bare_metal_server_network_interface_allow_float` resource for network interfaces. ~> **NOTE:** @@ -132,6 +186,40 @@ Review the argument references that you can specify for your resource. - `subnet` - (Required, String) ID of the subnet to associate with. - `vlan` - (Optional, Integer) Indicates the 802.1Q VLAN ID tag that must be used for all traffic on this interface. [ conflicts with `allowed_vlans`] +- `primary_network_attachment` - (Optional, List) The primary network attachment. + Nested schema for **primary_network_attachment**: + - `allowed_vlans` - (Optional, Array) Comma separated VLANs, Indicates what VLAN IDs (for VLAN type only) can use this physical (`PCI` type) interface. A given VLAN can only be in the allowed_vlans array for one PCI type adapter per bare metal server. + - `interface_type` - (String) The type of the network interface.[**pci**]. + - `name` - (Required, String) Name for this primary network attachment. + - `virtual_network_interface` - (Optional, List) The virtual network interface details for this target. + Nested schema for **virtual_network_interface**: + - `allow_ip_spoofing` - (Optional, Boolean) Indicates whether source IP spoofing is allowed on this interface. If `false`, source IP spoofing is prevented on this interface. If `true`, source IP spoofing is allowed on this interface. + - `auto_delete` - (Optional, Boolean) Indicates whether this virtual network interface will be automatically deleted when`target` is deleted. + - `enable_infrastructure_nat` - (Optional, 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 network interface, allowing the workload to perform any needed NAT operations.- `allow_ip_spoofing` must be `false`.- If the virtual network interface is attached: - The target `resource_type` must be `bare_metal_server_network_attachment`. - The target `interface_type` must not be `hipersocket`. + - `ips` - (Optional, List) The reserved IPs bound to this virtual network interface.May be empty when `lifecycle_state` is `pending`. + Nested schema for **ips**: + - `address` - (Required, String) The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `deleted` - (Optional, 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 reserved IP. + - `reserved_ip` - (Required, String) The unique identifier for this reserved IP. + - `name` - (Required, String) The name for this reserved IP. The name is unique across all reserved IPs in a subnet. + - `resource_type` - (Computed, String) The resource type. + - `name` - (Optional, String) The name for this virtual network interface. The name is unique across all virtual network interfaces in the VPC. + - `primary_ip` - (Optional, List) The reserved IP for this virtual network interface. + Nested schema for **primary_ip**: + - `address` - (Required, String) The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `deleted` - (Optional, List) If present, this property indicates the referenced resource has been deleted, and providessome supplementary information. + Nested schema for **deleted**: + - `more_info` - (Required, String) Link to documentation about deleted resources. + - `href` - (Required, String) The URL for this reserved IP. + - `reserved_ip` - (Required, String) The unique identifier for this reserved IP. + - `name` - (Required, String) The name for this reserved IP. The name is unique across all reserved IPs in a subnet. + - `resource_type` - (Computed, String) The resource type. + - `resource_group` - (Optional, List) The resource group id for this virtual network interface. + - `security_groups` - (Optional, Array of string) The security group ids list for this virtual network interface. + - `subnet` - (Optional, List) The associated subnet id. - `primary_network_interface` - (Required, List) A nested block describing the primary network interface of this bare metal server. We can have only one primary network interface. Nested scheme for `primary_network_interface`: diff --git a/website/docs/r/is_bare_metal_server_network_attachment.html.markdown b/website/docs/r/is_bare_metal_server_network_attachment.html.markdown new file mode 100644 index 0000000000..fb466b1aa8 --- /dev/null +++ b/website/docs/r/is_bare_metal_server_network_attachment.html.markdown @@ -0,0 +1,129 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_bare_metal_server_network_attachment" +description: |- + Manages is_bare_metal_server_network_attachment. +subcategory: "Virtual Private Cloud API" +--- + +# ibm_is_bare_metal_server_network_attachment + +Create, update, and delete is_bare_metal_server_network_attachments with this resource. + +## Example Usage + +```terraform +resource "ibm_is_bare_metal_server" "testacc_bms" { + profile = "cx2-metal-96x192" + name = "${var.name}-bms" + image = "r134-f47cc24c-e020-4db5-ad96-1e5be8b5853b" + zone = "${var.region}-2" + keys = ["r134-349aac10-ed14-4dc6-a95d-2ce66c3b447c"] + primary_network_attachment { + name = "vni-2" + virtual_network_interface { + id = "0726-b1755e04-1430-48d7-971d-661ba2836b54" + } + allowed_vlans = [100, 102] + } + vpc = "r134-6d509c8a-470e-4cdd-a82c-103f2353f5fc" +} +resource "ibm_is_bare_metal_server_network_attachment" "na" { + bare_metal_server = "0726-e17dbe53-25d2-42da-8532-bcb3b5a19f37" + allowed_vlans = [200, 202, 203] + virtual_network_interface { + id = "0726-b1755e04-1430-48d7-971d-661ba2836b54" + } +} + +``` + +## Argument Reference + +You can specify the following arguments for this resource. + +- `allow_to_float` - (Optional, Boolean) Indicates if the bare metal server network attachment can automatically float to any other server within the same `resource_group`. The bare metal server network attachment will float automatically if the network detects a GARP or RARP on another bare metal server in the resource group. Applies only to bare metal server network attachments with `vlan` interface type. +- `allowed_vlans` - (Optional, List) Indicates what VLAN IDs (for VLAN type only) can use this physical (PCI type) attachment. +- `bare_metal_server` - (Required, Forces new resource, String) The bare metal server identifier. +- `interface_type` - (Required, String) The network attachment's interface type:- `hipersocket`: a virtual network device that provides high-speed TCP/IP connectivity within a `s390x` based system- `pci`: a physical PCI device which can only be created or deleted when the bare metal server is stopped - Has an `allowed_vlans` property which controls the VLANs that will be permitted to use the PCI attachment - Cannot directly use an IEEE 802.1q VLAN tag.- `vlan`: a virtual device, used through a `pci` device that has the `vlan` in its array of `allowed_vlans`. - Must use an IEEE 802.1q tag.The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered. +- `name` - (Optional, String) The name for this bare metal server network attachment. The name is unique across all network attachments for the bare metal server. +- `virtual_network_interface` - (Optional, List) The virtual network interface for this bare metal server network attachment. + Nested schema for **virtual_network_interface**: + - `allow_ip_spoofing` - (Optional, Boolean) Indicates whether source IP spoofing is allowed on this interface. If `false`, source IP spoofing is prevented on this interface. If `true`, source IP spoofing is allowed on this interface. + - `auto_delete` - (Optional, Boolean) Indicates whether this virtual network interface will be automatically deleted when`target` is deleted. + - `enable_infrastructure_nat` - (Optional, 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 network interface, allowing the workload to perform any needed NAT operations.- `allow_ip_spoofing` must be `false`.- If the virtual network interface is attached: - The target `resource_type` must be `bare_metal_server_network_attachment`. - The target `interface_type` must not be `hipersocket`. + - `ips` - (Optional, List) The reserved IPs bound to this virtual network interface.May be empty when `lifecycle_state` is `pending`. + Nested schema for **ips**: + - `address` - (Required, String) The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `deleted` - (Optional, 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 reserved IP. + - `reserved_ip` - (Required, String) The unique identifier for this reserved IP. + - `name` - (Required, String) The name for this reserved IP. The name is unique across all reserved IPs in a subnet. + - `resource_type` - (Computed, String) The resource type. + - `name` - (Optional, String) The name for this virtual network interface. The name is unique across all virtual network interfaces in the VPC. + - `primary_ip` - (Optional, List) The reserved IP for this virtual network interface. + Nested schema for **primary_ip**: + - `address` - (Required, String) The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `deleted` - (Optional, List) If present, this property indicates the referenced resource has been deleted, and providessome supplementary information. + Nested schema for **deleted**: + - `more_info` - (Required, String) Link to documentation about deleted resources. + - `href` - (Required, String) The URL for this reserved IP. + - `reserved_ip` - (Required, String) The unique identifier for this reserved IP. + - `name` - (Required, String) The name for this reserved IP. The name is unique across all reserved IPs in a subnet. + - `resource_type` - (Computed, String) The resource type. + - `resource_group` - (Optional, List) The resource group id for this virtual network interface. + - `security_groups` - (Optional, Array of string) The security group ids list for this virtual network interface. + - `subnet` - (Optional, List) The associated subnet id. +- `vlan` - (Optional, Integer) Indicates the 802.1Q VLAN ID tag that must be used for all traffic on this attachment. + +## 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 is_bare_metal_server_network_attachment. +- `bare_metal_server_network_attachment_id` - (String) The unique identifier for this bare metal server network attachment. +- `created_at` - (String) The date and time that the bare metal server network attachment was created. +- `href` - (String) The URL for this bare metal server network attachment. +- `lifecycle_state` - (String) The lifecycle state of the bare metal server network attachment. +- `port_speed` - (Integer) The port speed for this bare metal server network attachment in Mbps. +- `primary_ip` - (List) The primary IP address of the virtual network interface for the bare metal servernetwork attachment. +Nested schema for **primary_ip**: + - `address` - (String) The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `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 reserved IP. + - `id` - (String) The unique identifier for this reserved IP. + - `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. +- `resource_type` - (String) The resource type. +- `subnet` - (List) The subnet of the virtual network interface for the bare metal server networkattachment. +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. + Nested schema for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this subnet. + - `id` - (String) The unique identifier for this subnet. + - `name` - (String) The name for this subnet. The name is unique across all subnets in the VPC. + - `resource_type` - (String) The resource type. +- `type` - (String) The bare metal server network attachment type. + + +## Import + +You can import the `ibm_is_bare_metal_server_network_attachment` resource by using `id`. +The `id` property can be formed from `bare_metal_server`, and `id` in the following format: + +``` +/ +``` +- `bare_metal_server`: A string. The bare metal server identifier. +- `id`: A string. The bare metal server network attachment identifier. + +# Syntax +``` +$ terraform import ibm_is_bare_metal_server_network_attachment.is_bare_metal_server_network_attachment / +``` diff --git a/website/docs/r/is_flow_log.html.markdown b/website/docs/r/is_flow_log.html.markdown index 0ddd32f0ad..5a2c5fff5c 100644 --- a/website/docs/r/is_flow_log.html.markdown +++ b/website/docs/r/is_flow_log.html.markdown @@ -81,8 +81,16 @@ Review the argument references that you can specify for your resource. **•** For more information, about creating access tags, see [working with tags](https://cloud.ibm.com/docs/account?topic=account-tag&interface=ui#create-access-console).
**•** You must have the access listed in the [Granting users access to tag resources](https://cloud.ibm.com/docs/account?topic=account-access) for `access_tags`
**•** `access_tags` must be in the format `key:value`. -- `name` - (Required, String) The unique user-defined name for the flow log collector.No. -- `target` - (Required, Forces new resource, String) The ID of the target to collect flow logs. If the target is an instance, subnet, or VPC, flow logs is not collected for any network interfaces within the target that are more specific flow log collector. +- `name` - (Required, String) The unique user-defined name for the flow log collector. +- `target` - (Required, Forces new resource, String) The ID of the target to collect flow logs. + + -> **Note:** + **•** If the target is an instance network attachment, flow logs will be collected for that instance network attachment.
+ **•** If the target is an instance network interface, flow logs will be collected for that instance network interface.
+ **•** If the target is a virtual network interface, flow logs will be collected for the the virtual network interface's `target` resource if the resource is: - an instance network attachment.
+ **•** If the target is a virtual server instance, flow logs will be collected for all network attachments or network interfaces on that instance.
+ **•** If the target is a subnet, flow logs will be collected for all instance network interfaces and virtual network interfaces attached to that subnet.
+ **•** If the target is a VPC, flow logs will be collected for all instance network interfaces and virtual network interfaces attached to all subnets within that VPC. If the target is an instance, subnet, or VPC, flow logs will not be collectedfor any instance network attachments or instance network interfaces within the targetthat are themselves the target of a more specific flow log collector.
- `storage_bucket` - (Required, Forces new resource, String) The name of the IBM Cloud Object Storage bucket where the collected flows will be logged. The bucket must exist and an IAM service authorization must grant IBM Cloud flow logs resources of VPC infrastructure services writer access to the bucket. - `active` - (Optional, String) Indicates whether the collector is active. If **false**, this collector is created in inactive mode. Default value is true. - `resource_group` - (Optional, Forces new resource, String) The resource group ID where the flow log is created. diff --git a/website/docs/r/is_instance.html.markdown b/website/docs/r/is_instance.html.markdown index 6720a5d1ca..c182fe36f7 100644 --- a/website/docs/r/is_instance.html.markdown +++ b/website/docs/r/is_instance.html.markdown @@ -24,7 +24,7 @@ Create, update, or delete a Virtual Servers for VPC instance. For more informati ## Example usage -### Sample for creating an instance in a VPC. +### Sample for creating an instance in a VPC using virtual network interface and network attachments. ```terraform resource "ibm_is_vpc" "example" { @@ -43,6 +43,63 @@ resource "ibm_is_ssh_key" "example" { public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR" } +resource "ibm_is_virtual_network_interface" "example"{ + name = "example-vni" + allow_ip_spoofing = false + enable_infrastructure_nat = true + primary_ip { + auto_delete = false + address = "10.240.0.8" + } + subnet = ibm_is_subnet.example.id +} + +resource "ibm_is_instance" "example" { + name = "example-instance" + image = ibm_is_image.example.id + profile = "bx2-2x8" + metadata_service_enabled = false + + boot_volume { + encryption = "crn:v1:bluemix:public:kms:us-south:a/dffc98a0f1f0f95f6613b3b752286b87:e4a29d1a-2ef0-42a6-8fd2-350deb1c647e:key:5437653b-c4b1-447f-9646-b2a2a4cd6179" + } + + primary_network_attachment { + name = "vexample-primary-att" + virtual_network_interface { + id = ibm_is_virtual_network_interface.example.id + } + } + + network_attachments { + name = "example-network-att" + virtual_network_interface { + name = "example-net-vni" + auto_delete = true + enable_infrastructure_nat = true + primary_ip { + auto_delete = true + address = "10.240.0.6" + } + subnet = ibm_is_subnet.example.id + } + } + vpc = ibm_is_vpc.example.id + zone = ibm_is_subnet.example.zone + keys = [ibm_is_ssh_key.example.id] + + //User can configure timeouts + timeouts { + create = "15m" + update = "15m" + delete = "15m" + } +} +``` + +### Sample for creating an instance in a VPC. + +```terraform resource "ibm_is_instance" "example" { name = "example-instance" image = ibm_is_image.example.id @@ -127,6 +184,51 @@ resource "ibm_is_instance" "example1" { ``` +### Sample for creating an instance in a VPC with reservation + +```terraform +resource "ibm_is_reservation" "example" { + capacity { + total = 5 + } + committed_use { + term = "one_year" + } + profile { + name = "ba2-2x8" + resource_type = "instance_profile" + } + zone = "us-east-3" + name = "reservation-name" +} + +resource "ibm_is_instance" "example" { + name = "example-instance" + image = ibm_is_image.example.id + profile = "bx2-2x8" + metadata_service_enabled = false + 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 + zone = "us-south-1" + keys = [ibm_is_ssh_key.example.id] + + //User can configure timeouts + timeouts { + create = "15m" + update = "15m" + delete = "15m" + } +} + +``` ### Sample for creating an instance with custom security group rules. The following example shows how you can create a virtual server instance with custom security group rules. Note that the security group, security group rules, and the virtual server instance must be created in a specific order to meet the dependencies of the individual resources. To force the creation in a specific order, you use the [`depends_on` parameter](https://www.terraform.io/docs/configuration/resources.html). If you do not provide this parameter, all resources are created at the same time which might lead to resource dependency errors during the provisioning of your virtual server, such as `The security group to attach to is not available`. @@ -474,6 +576,37 @@ Review the argument references that you can specify for your resource. - `protocol` - (Optional, String) The communication protocol to use for the metadata service endpoint. Applies only when the metadata service is enabled. Default is **http** - `response_hop_limit` - (Optional, Integer) The hop limit (IP time to live) for IP response packets from the metadata service. Default is **1** - `name` - (Optional, String) The instance name. +- `network_attachments` - (Optional, List) The network attachments for this virtual server instance, including the primary network attachment. Adding and removing of network attachments must be done from the rear end to avoid unwanted differences and changes in terraform. + Nested schema for **network_attachments**: + - `deleted` - (Optional, List) If present, this property indicates the referenced resource has been deleted, and providessome supplementary information. + Nested schema for **deleted**: + - `more_info` - (Required, String) Link to documentation about deleted resources. + - `href` - (String) The URL for this network attachment. + - `id` - (String) The unique identifier for this network attachment. + - `name` - (Optional, String) Name of the attachment. + - `virtual_network_interface` - (Required, List(1)) The details of the virtual network interface for this network attachment. It can either accept an `id` or properties of `virtual_network_interface` + Nested schema for **virtual_network_interface**: + - `id` - (Optional, String) The `id` of the virtual network interface, id conflicts with other properties of virtual network interface + - `allow_ip_spoofing` - (Optional, Boolean) Indicates whether source IP spoofing is allowed on this interface. If false, source IP spoofing is prevented on this interface. If true, source IP spoofing is allowed on this interface. + - `auto_delete` - (Optional, Boolean) Indicates whether this virtual network interface will be automatically deleted when target is deleted + - `enable_infrastructure_nat` - (Optional, Boolean) If true: The VPC infrastructure performs any needed NAT operations and 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, allow_ip_spoofing must be false, can only be attached to a target with a resource_type of bare_metal_server_network_attachment. + - `name` - (Optional, String) The resource type. + - `ips` - (Optional, Array of String) Additional IP addresses to bind to the virtual network interface. Each item may be either a reserved IP identity, or a reserved IP prototype object which will be used to create a new reserved IP. All IP addresses must be in the primary IP's subnet. + ~> **NOTE** to add `ips` only existing `reserved_ip` is supported, new reserved_ip creation is not supported as it leads to unmanaged(dangling) reserved ips. Use `ibm_is_subnet_reserved_ip` to create a reserved_ip + - `resource_group` - (Optional, String) The resource type. + - `security_groups` - (Optional, Array of String) The resource type. + - `primary_ip` - (Required, List) The primary IP address of the virtual network interface for the network attachment. + Nested schema for **primary_ip**: + - `address` - (Required, String) The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `deleted` - (Optional, List) If present, this property indicates the referenced resource has been deleted, and providessome supplementary information. + Nested schema for **deleted**: + - `more_info` - (Required, String) Link to documentation about deleted resources. + - `href` - (Required, String) The URL for this reserved IP. + - `id` - (Required, String) The unique identifier for this reserved IP. + - `name` - (Required, String) The name for this reserved IP. The name is unique across all reserved IPs in a subnet. + - `resource_type` - (String) The resource type. + - `resource_type` - (String) The resource type. + - `subnet` - (Required, String) The subnet id of the virtual network interface for the network attachment. - `network_interfaces` (Optional, Forces new resource, List) A list of more network interfaces that are set up for the instance. -> **Allowed vNIC per profile.** Follow the vNIC count as per the instance profile's `network_interface_count`. For details see [`is_instance_profile`](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/is_instance_profile) or [`is_instance_profiles`](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/is_instance_profiles). @@ -496,6 +629,38 @@ Review the argument references that you can specify for your resource. - `subnet` - (Required, String) The ID of the subnet. - `security_groups`- (Optional, List of strings)A comma separated list of security groups to add to the primary network interface. - `placement_group` - (Optional, string) Unique Identifier of the Placement Group for restricting the placement of the instance +- `primary_network_attachment` - (Optional, List) The primary network attachment for this virtual server instance. + Nested schema for **primary_network_attachment**: + - `deleted` - (Optional, List) If present, this property indicates the referenced resource has been deleted, and providessome supplementary information. + Nested schema for **deleted**: + - `more_info` - (Required, String) Link to documentation about deleted resources. + - `href` - (String) The URL for this network attachment. + - `id` - (String) The unique identifier for this network attachment. + - `name` - (Required, String) The name of this network attachment + - `resource_type` - (String) The resource type. + - `virtual_network_interface` - (Required, List(1)) The details of the virtual network interface for this network attachment. It can either accept an `id` or properties of `virtual_network_interface` + Nested schema for **virtual_network_interface**: + - `id` - (Optional, List) The `id` of the virtual network interface, id conflicts with other properties of virtual network interface + - `allow_ip_spoofing` - (Optional, Boolean) Indicates whether source IP spoofing is allowed on this interface. If false, source IP spoofing is prevented on this interface. If true, source IP spoofing is allowed on this interface. + - `auto_delete` - (Optional, Boolean) Indicates whether this virtual network interface will be automatically deleted when target is deleted + - `enable_infrastructure_nat` - (Optional, Boolean) If true: The VPC infrastructure performs any needed NAT operations and 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, allow_ip_spoofing must be false, can only be attached to a target with a resource_type of bare_metal_server_network_attachment. + - `name` - (Optional, String) The resource type. + - `ips` - (Optional, Array of String) Additional IP addresses to bind to the virtual network interface. Each item may be either a reserved IP identity, or a reserved IP prototype object which will be used to create a new reserved IP. All IP addresses must be in the primary IP's subnet. + - `resource_group` - (Optional, String) The resource type. + - `security_groups` - (Optional, Array of String) The resource type. + - `primary_ip` - (Required, List) The primary IP address of the virtual network interface for the network attachment. + Nested schema for **primary_ip**: + - `address` - (Required, String) The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `deleted` - (Optional, List) If present, this property indicates the referenced resource has been deleted, and providessome supplementary information. + Nested schema for **deleted**: + - `more_info` - (Required, String) Link to documentation about deleted resources. + - `href` - (Required, String) The URL for this reserved IP. + - `id` - (Required, String) The unique identifier for this reserved IP. + - `name` - (Required, String) The name for this reserved IP. The name is unique across all reserved IPs in a subnet. + - `resource_type` - (String) The resource type. + - `resource_type` - (String) The resource type. + - `subnet` - (Required, String) The subnet id of the virtual network interface for the network attachment. + - `primary_network_interface` - (Required, List) A nested block describes the primary network interface of this instance. Only one primary network interface can be specified for an instance. When using `instance_template`, `primary_network_interface` is not required. Nested scheme for `primary_network_interface`: @@ -523,6 +688,16 @@ Review the argument references that you can specify for your resource. 1. Have matching instance disk support. Any disks associated with the current profile will be deleted, and any disks associated with the requested profile will be created. 2. Be compatible with any placement_target(`dedicated_host`, `dedicated_host_group`, `placement_group`) constraints. For example, if the instance is placed on a dedicated host, the requested profile family must be the same as the dedicated host family. +- `reservation_affinity` - (Optional, List) The reservation affinity for the instance + Nested scheme for `reservation_affinity`: + - `policy` - (Optional, String) The reservation affinity policy to use for this virtual server instance. + + ->**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 virtual server instance. Specified reservations must have a status of active, and have the same profile and zone as this virtual server instance. 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_group` - (Optional, Forces new resource, String) The ID of the resource group where you want to create the instance. - `instance_template` - (Optional, String) ID of the instance template to create the instance from. To create an instance template, use `ibm_is_instance_template` resource. @@ -614,7 +789,34 @@ In addition to all argument reference list, you can access the following attribu # value = ibm_is_instance.example.primary_network_interface.0.primary_ipv4_address // will be deprecated in future value = ibm_is_instance.example.primary_network_interface.0.primary_ip.0.address // use this instead } - ``` +- `reservation`- (List) The reservation used by this virtual server instance. + + 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 instance reservation affinity. + + Nested scheme for `reservation_affinity`: + - `policy` - (String) The reservation affinity policy to use for this virtual server instance. + - `pool` - (List) The pool of reservations available for use by this virtual server instance. + + 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. ``` - `status` - (String) The status of the instance. - `status_reasons` - (List) Array of reasons for the current status. diff --git a/website/docs/r/is_instance_network_attachment.html.markdown b/website/docs/r/is_instance_network_attachment.html.markdown new file mode 100644 index 0000000000..26976587f8 --- /dev/null +++ b/website/docs/r/is_instance_network_attachment.html.markdown @@ -0,0 +1,88 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_instance_network_attachment" +description: |- + Manages Instance NetworkAttachment. +subcategory: "Virtual Private Cloud API" +--- + +# ibm_is_instance_network_attachment + +Create, update, and delete Instance NetworkAttachment with this resource. + +## Example Usage + +```terraform +resource "ibm_is_instance_network_attachment" "example" { + instance = "" + virtual_network_interface { + id = "" + } +} +``` + +## Argument Reference + +You can specify the following arguments for this resource. + +- `instance` - (Required, Forces new resource, String) The virtual server instance identifier. +- `name` - (Optional, String) The name for this instance network attachment. The name is unique across all network attachments for the instance. +- `virtual_network_interface` - (Required, List) The virtual network interface for this instance network attachment. + Nested schema for **virtual_network_interface**: + - `crn` - (Required, String) The CRN for this virtual network interface. + - `href` - (Required, String) The URL for this virtual network interface. + - `id` - (Required, String) The unique identifier for this virtual network interface. + ~> **NOTE** to add `ips` only existing `reserved_ip` is supported, new reserved_ip creation is not supported as it leads to unmanaged(dangling) reserved ips. Use `ibm_is_subnet_reserved_ip` to create a reserved_ip + - `name` - (Required, String) The name for this virtual network interface. The name is unique across all virtual network interfaces in the VPC. + - `resource_type` - (Computed, String) The resource type. + +## 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 Instance NetworkAttachment. +- `created_at` - (String) The date and time that the instance network attachment was created. +- `href` - (String) The URL for this instance network attachment. +- `lifecycle_state` - (String) The lifecycle state of the instance network attachment. + * Allowable values are: `deleting`, `failed`, `pending`, `stable`, `suspended`, `updating`, `waiting`. +- `network_attachment` - (String) The id of the network attachment. +- `port_speed` - (Integer) The port speed for this instance network attachment in Mbps. +- `primary_ip` - (List) The primary IP address of the virtual network interface for the instance networkattachment. + Nested schema for **primary_ip**: + - `address` - (String) The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `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 reserved IP. + - `id` - (String) The unique identifier for this reserved IP. + - `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. +- `resource_type` - (String) The resource type. +- `subnet` - (List) The subnet of the virtual network interface for the instance 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. + Nested schema for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this subnet. + - `id` - (String) The unique identifier for this subnet. + - `name` - (String) The name for this subnet. The name is unique across all subnets in the VPC. + - `resource_type` - (String) The resource type. +- `type` - (String) The instance network attachment type. + + +## Import + +You can import the `ibm_is_instance_network_attachment` resource by using `id`. +The `id` property can be formed from `instance`, and `id` in the following format: + +``` +/ +``` +- `instance`: A string. The virtual server instance identifier. +- `id`: A string. The instance network attachment identifier. + +# Syntax +``` +$ terraform import ibm_is_instance_network_attachment.is_instance_network_attachment / +``` diff --git a/website/docs/r/is_instance_template.html.markdown b/website/docs/r/is_instance_template.html.markdown index dddc1244d4..b56188d045 100644 --- a/website/docs/r/is_instance_template.html.markdown +++ b/website/docs/r/is_instance_template.html.markdown @@ -253,6 +253,38 @@ Review the argument references that you can specify for your resource. ~>**Note:** only one of [**dedicated_host**, **dedicated_host_group**, **placement_group**] can be used - `profile` - (Required, String) The number of instances created in the instance group. +- `primary_network_attachment` - (Optional, List) The primary network attachment for this virtual server instance. + Nested schema for **primary_network_attachment**: + - `deleted` - (Optional, List) If present, this property indicates the referenced resource has been deleted, and providessome supplementary information. + Nested schema for **deleted**: + - `more_info` - (Required, String) Link to documentation about deleted resources. + - `href` - (String) The URL for this network attachment. + - `id` - (String) The unique identifier for this network attachment. + - `name` - (Required, String) The name of this network attachment + - `resource_type` - (String) The resource type. + - `virtual_network_interface` - (Required, List(1)) The details of the virtual network interface for this network attachment. It can either accept an `id` or properties of `virtual_network_interface` + Nested schema for **virtual_network_interface**: + - `id` - (Optional, List) The `id` of the virtual network interface, id conflicts with other properties of virtual network interface + - `allow_ip_spoofing` - (Optional, Boolean) Indicates whether source IP spoofing is allowed on this interface. If false, source IP spoofing is prevented on this interface. If true, source IP spoofing is allowed on this interface. + - `auto_delete` - (Optional, Boolean) Indicates whether this virtual network interface will be automatically deleted when target is deleted + - `enable_infrastructure_nat` - (Optional, Boolean) If true: The VPC infrastructure performs any needed NAT operations and 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, allow_ip_spoofing must be false, can only be attached to a target with a resource_type of bare_metal_server_network_attachment. + - `name` - (Optional, String) The resource type. + - `ips` - (Optional, Array of String) Additional IP addresses to bind to the virtual network interface. Each item may be either a reserved IP identity, or a reserved IP prototype object which will be used to create a new reserved IP. All IP addresses must be in the primary IP's subnet. + - `resource_group` - (Optional, String) The resource type. + - `security_groups` - (Optional, Array of String) The resource type. + - `primary_ip` - (Required, List) The primary IP address of the virtual network interface for the network attachment. + Nested schema for **primary_ip**: + - `address` - (Required, String) The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `deleted` - (Optional, List) If present, this property indicates the referenced resource has been deleted, and providessome supplementary information. + Nested schema for **deleted**: + - `more_info` - (Required, String) Link to documentation about deleted resources. + - `href` - (Required, String) The URL for this reserved IP. + - `id` - (Required, String) The unique identifier for this reserved IP. + - `name` - (Required, String) The name for this reserved IP. The name is unique across all reserved IPs in a subnet. + - `resource_type` - (String) The resource type. + - `resource_type` - (String) The resource type. + - `subnet` - (Required, String) The subnet id of the virtual network interface for the network attachment. + - `primary_network_interfaces` (Required, List) A nested block describes the primary network interface for the template. Nested scheme for `primary_network_interfaces`: @@ -261,6 +293,39 @@ Review the argument references that you can specify for your resource. - `primary_ipv4_address` - (Optional, String) The IPv4 address assigned to the primary network interface. - `security_groups`- (Optional, List) List of security groups of the subnet. - `subnet` - (Required, Force new resource, String) The VPC subnet to assign to the interface. + +- `network_attachments` - (Optional, List) The network attachments for this virtual server instance, including the primary network attachment. Adding and removing of network attachments must be done from the rear end to avoid unwanted differences and changes in terraform. + Nested schema for **network_attachments**: + - `deleted` - (Optional, List) If present, this property indicates the referenced resource has been deleted, and providessome supplementary information. + Nested schema for **deleted**: + - `more_info` - (Required, String) Link to documentation about deleted resources. + - `href` - (String) The URL for this network attachment. + - `id` - (String) The unique identifier for this network attachment. + - `name` - (Optional, String) Name of the attachment. + - `virtual_network_interface` - (Required, List(1)) The details of the virtual network interface for this network attachment. It can either accept an `id` or properties of `virtual_network_interface` + Nested schema for **virtual_network_interface**: + - `id` - (Optional, String) The `id` of the virtual network interface, id conflicts with other properties of virtual network interface + - `allow_ip_spoofing` - (Optional, Boolean) Indicates whether source IP spoofing is allowed on this interface. If false, source IP spoofing is prevented on this interface. If true, source IP spoofing is allowed on this interface. + - `auto_delete` - (Optional, Boolean) Indicates whether this virtual network interface will be automatically deleted when target is deleted + - `enable_infrastructure_nat` - (Optional, Boolean) If true: The VPC infrastructure performs any needed NAT operations and 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, allow_ip_spoofing must be false, can only be attached to a target with a resource_type of bare_metal_server_network_attachment. + - `name` - (Optional, String) The resource type. + - `ips` - (Optional, Array of String) Additional IP addresses to bind to the virtual network interface. Each item may be either a reserved IP identity, or a reserved IP prototype object which will be used to create a new reserved IP. All IP addresses must be in the primary IP's subnet. + ~> **NOTE** to add `ips` only existing `reserved_ip` is supported, new reserved_ip creation is not supported as it leads to unmanaged(dangling) reserved ips. Use `ibm_is_subnet_reserved_ip` to create a reserved_ip + - `resource_group` - (Optional, String) The resource type. + - `security_groups` - (Optional, Array of String) The resource type. + - `primary_ip` - (Required, List) The primary IP address of the virtual network interface for the network attachment. + Nested schema for **primary_ip**: + - `address` - (Required, String) The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `deleted` - (Optional, List) If present, this property indicates the referenced resource has been deleted, and providessome supplementary information. + Nested schema for **deleted**: + - `more_info` - (Required, String) Link to documentation about deleted resources. + - `href` - (Required, String) The URL for this reserved IP. + - `id` - (Required, String) The unique identifier for this reserved IP. + - `name` - (Required, String) The name for this reserved IP. The name is unique across all reserved IPs in a subnet. + - `resource_type` - (String) The resource type. + - `resource_type` - (String) The resource type. + - `subnet` - (Required, String) The subnet id of the virtual network interface for the network attachment. + - `network_interfaces` - (Optional, List) A nested block describes the network interfaces for the template. Nested scheme for `network_interfaces`: @@ -269,6 +334,16 @@ Review the argument references that you can specify for your resource. - `primary_ipv4_address` - (Optional, String) The IPv4 address assigned to the network interface. - `security_groups` - (Optional, List) List of security groups of the subnet. - `subnet` - (Required, Forces new resource, String) The VPC subnet to assign to the interface. +- `reservation_affinity` - (Optional, List) The reservation affinity for the instance + Nested scheme for `reservation_affinity`: + - `policy` - (Optional, String) The reservation affinity policy to use for this virtual server instance. + + ->**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 virtual server instance. Specified reservations must have a status of active, and have the same profile and zone as this virtual server instance. 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_group` - (Optional, Forces new resource, String) The resource group ID. - `total_volume_bandwidth` - (Optional, int) The amount of bandwidth (in megabits per second) allocated exclusively to instance storage volumes - `volume_attachments` - (Optional, Force new resource, List) A nested block describes the storage volume configuration for the template. diff --git a/website/docs/r/is_lb_listener.html.markdown b/website/docs/r/is_lb_listener.html.markdown index c9b04be076..c152ad1689 100644 --- a/website/docs/r/is_lb_listener.html.markdown +++ b/website/docs/r/is_lb_listener.html.markdown @@ -58,7 +58,7 @@ resource "ibm_is_lb_pool_member" "example" { } ``` -### Sample to create a load balancer listener policy for a `https_redirect` action. +### Sample to create a load balancer listener with `https_redirect`. ```terraform resource "ibm_is_lb" "example2" { @@ -77,9 +77,14 @@ resource "ibm_is_lb_listener" "example2" { lb = ibm_is_lb.example2.id port = "9087" protocol = "http" - https_redirect_listener = ibm_is_lb_listener.example1.listener_id - https_redirect_status_code = 301 - https_redirect_uri = "/example?doc=geta" + idle_connection_timeout = 60 + https_redirect { + http_status_code = 302 + listener { + id = ibm_is_lb_listener.example1.listener_id + } + uri = "/example?doc=get" + } } ``` @@ -147,7 +152,7 @@ resource "ibm_is_lb_listener" "example2" { port_max = 400 } ``` - +### Example to create a listener with ## Timeouts The `ibm_is_lb_listener` resource provides the following [Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: @@ -195,6 +200,19 @@ Review the argument references that you can specify for your resource. - `https_redirect_listener` - (Optional, String) ID of the listener that will be set as http redirect target. - `https_redirect_status_code` - (Optional, Integer) The HTTP status code to be returned in the redirect response, one of [301, 302, 303, 307, 308]. - `https_redirect_uri` - (Optional, String) Target URI where traffic will be redirected. + +~**Note** + `https_redirect_listener`, `https_redirect_status_code` and `https_redirect_uri` are deprecated and will be removed in future. Please use `https_redirect` instead + +- `https_redirect` - (Optional, List) If present, the target listener that requests are redirected to. Removing `https_redirect` would update the load balancer listener and disable the `https_redirect` + + Nested schema for **https_redirect**: + - `http_status_code` - (Required, Integer) The HTTP status code for this redirect. Allowable values are: `301`, `302`, `303`, `307`, `308`. + - `listener` - (Required, List) + + Nested schema for **listener**: + - `id` - (Required, String) The unique identifier for this load balancer listener. + - `uri` - (Optional, String) The redirect relative target URI. Removing `uri` would update the load balancer listener and remove the `uri` from `https_redirect` - `idle_connection_timeout` - (Optional, Integer) The idle connection timeout of the listener in seconds. Supported for load balancers in the `application` family. Default value is `50`, allowed value is between `50` - `7200`. ## Attribute reference @@ -202,7 +220,20 @@ In addition to all argument reference list, you can access the following attribu - `id` - (String) The unique identifier of the load balancer listener. - `status` - (String) The status of load balancer listener. - +- `https_redirect` - (List) If present, the target listener that requests are redirected to. + + Nested schema for **https_redirect**: + - `http_status_code` - (Integer) The HTTP status code for this redirect. + - `listener` - (List) + + Nested schema for **listener**: + - `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 listener's canonical URL. + - `id` - (String) The unique identifier for this load balancer listener. + - `uri` - (String) The redirect relative target URI. ## Import The `ibm_is_lb_listener` resource can be imported by using the load balancer ID and listener ID. diff --git a/website/docs/r/is_lb_listener_policy.html.markdown b/website/docs/r/is_lb_listener_policy.html.markdown index b1b66cb646..2d10caed99 100644 --- a/website/docs/r/is_lb_listener_policy.html.markdown +++ b/website/docs/r/is_lb_listener_policy.html.markdown @@ -35,19 +35,16 @@ resource "ibm_is_lb_listener" "example" { port = "9086" protocol = "http" } + resource "ibm_is_lb_listener_policy" "example" { - lb = ibm_is_lb.example.id - listener = ibm_is_lb_listener.example.listener_id - action = "redirect" - priority = 2 - name = "example-listener-policy" - target_http_status_code = 302 - target_url = "https://www.redirect.com" - rules { - condition = "contains" - type = "header" - field = "1" - value = "2" + lb = ibm_is_lb.example.id + listener = ibm_is_lb_listener.example.listener_id + action = "redirect" + priority = 4 + name = "example-listener-policy" + target { + http_status_code = 302 + url = "https://www.example.com" } } ``` @@ -79,9 +76,13 @@ resource "ibm_is_lb_listener_policy" "example" { action = "https_redirect" priority = 2 name = "example-listener" - target_https_redirect_listener = ibm_is_lb_listener.example_https_target.listener_id - target_https_redirect_status_code = 301 - target_https_redirect_uri = "/example?doc=geta" + target { + http_status_code = 302 + listener { + id = ibm_is_lb_listener.example_https_target.listener_id + } + uri = "/example?doc=get" + } rules { condition = "contains" type = "header" @@ -91,7 +92,7 @@ resource "ibm_is_lb_listener_policy" "example" { } ``` -### Creating a load balancer listener policy for a `forward` action by using `lb` and `lb listener`. +### Creating a load balancer listener policy for a `forward` action. ```terraform @@ -118,17 +119,13 @@ resource "ibm_is_lb_pool" "example" { } resource "ibm_is_lb_listener_policy" "example" { - lb = ibm_is_lb.example.id - listener = ibm_is_lb_listener.example.listener_id - action = "forward" - priority = 2 - name = "example-listener" - target_id = ibm_is_lb_pool.example.pool_id - rules { - condition = "contains" - type = "header" - field = "1" - value = "2" + lb = ibm_is_lb.example.id + listener = ibm_is_lb_listener.example.listener_id + action = "forward" + priority = 3 + name = "example-listener" + target { + id = ibm_is_lb_pool.example.pool_id } } ``` @@ -162,9 +159,29 @@ Review the argument references that you can specify for your resource. - `target_https_redirect_status_code` - (Optional, Integer) When `action` is set to **https_redirect**, specify the HTTP status code to be returned in the redirect response. Supported values are `301`, `302`, `303`, `307`, `308`. - `target_https_redirect_uri` - (Optional, String) When `action` is set to **https_redirect**, specify the target URI where traffic will be redirected. -~> **Note:** When action is `forward`, `target_id` should specify which pool the load balancer forwards the traffic to. -When action is `redirect`, `target_url` should specify the `url` and `target_http_status_code` to specify the code used in the redirect response. -When action is `https_redirect`, `target_https_redirect_listener` should specify the ID of the listener, `target_https_redirect_status_code` to specify the code used in the redirect response and `target_https_redirect_uri` to specify the target URI where traffic will be redirected. +~> **Note:** `target_id`, `target_http_status_code`, `target_url`, `target_https_redirect_listener`, `target_https_redirect_status_code`, `target_https_redirect_uri` are deprecated and will be removed soon. Please use `target` instead. + +- `target` - (Optional, List) - If `action` is `forward`, the response is a `LoadBalancerPoolReference`- If `action` is `redirect`, the response is a `LoadBalancerListenerPolicyRedirectURL`- If `action` is `https_redirect`, the response is a `LoadBalancerListenerHTTPSRedirect`. + Nested schema for **target**: + - `deleted` - (Computed, 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` - (Optional, String) The pool's canonical URL. + - `http_status_code` - (Optional, Integer) The HTTP status code for this redirect. Allowable values are: `301`, `302`, `303`, `307`, `308`. + - `id` - (Optional, String) The unique identifier for this load balancer pool. + - `listener` - (Optional, List) + Nested schema for **listener**: + - `deleted` - (Computed, 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` - (Optional, String) The listener's canonical URL. + - `id` - (Optional, String) The unique identifier for this load balancer listener. + - `name` - (Computed, String) The name for this load balancer pool. The name is unique across all pools for the load balancer. + - `url` - (Optional, String) The redirect target URL. + +~> **Note:** When action is `forward`, `target.id` should specify which pool the load balancer forwards the traffic to. +When action is `redirect`, `target.url` should specify the `url` and `target.http_status_code` to specify the code used in the redirect response. +When action is `https_redirect`, `target.listener.id` should specify the ID of the listener, `target.http_status_code` to specify the code used in the redirect response and `target.uri` to specify the target URI where traffic will be redirected. Network load balancer does not support `ibm_is_lb_listener_policy`. ## Attribute reference diff --git a/website/docs/r/is_reservation.html.markdown b/website/docs/r/is_reservation.html.markdown new file mode 100644 index 0000000000..3d397b0ed6 --- /dev/null +++ b/website/docs/r/is_reservation.html.markdown @@ -0,0 +1,177 @@ +--- + +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : reservation" +description: |- + Manages IBM reservation. +--- + +# ibm_is_reservation +Create, update, or delete a reservation. + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "us-south" +} +``` + + +## Example usage + +```terraform +resource "ibm_is_reservation" "example" { + capacity { + total = 5 + } + committed_use { + term = "one_year" + } + profile { + name = "ba2-2x8" + resource_type = "instance_profile" + } + zone = "us-east-3" + name = "reservation-terraform-1" +} +``` + + +## Argument reference +Review the argument references that you can specify for your resource. + +- `affinity_policy` - (Optional, String) affinity policy to use for this reservation. [ **restricted** ] +- `capacity` - (List) The capacity reservation configuration to use. + + Nested scheme for `capacity`: + - `total` - (Integer) The total amount to use for this capacity reservation. +- `committed_use` - (List) The committed use configuration to use for this reservation. + + Nested scheme for `committed_use`: + - `expiration_policy` - (Optional, String) The policy to apply when the committed use term expires. [**release**, **renew**] + ~> **Note:** + **•** `release` Release any available capacity and let the reservation expire.
+ **•** `renew` Renew for another term, provided the term remains listed in the reservation_terms for the profile. Otherwise, let the reservation expire.
+ - `term` - (String) The term for this committed use reservation. [**one_year**, **three_year**] +- `name` - (Optional, String) The name for this reservation. The name must not be used by another reservation in the region. If unspecified, the name will be a hyphenated list of randomly-selected words. +- `profile` - (List) The virtual server instance profile to use for this reservation. + + Nested scheme for `profile`: + - `name` - (String) The globally unique name of the profile. + - `resource_type` - (String) The resource type of the profile. [ **instance_profile** ] +- `resource_group` - (Optional, List) The resource group to use. If unspecified, the account's default resource group will be used. + + Nested scheme for `resource_group`: + - `id` - (String) The unique identifier for this resource group. +- `zone` - (String) The zone to use for this reservation. + + +## Attribute reference +You can access the following attribute references after your data source is created. +- `affinity_policy` - (String) The affinity policy to use for this reservation. +- `capacity` - (List) The capacity configuration for this reservation. If absent, this reservation has no assigned capacity. + + Nested scheme for `capacity`: + - `allocated` - (Integer) The amount allocated to this capacity reservation. + - `available` - (Integer) The amount of this capacity reservation available for new attachments. + - `status` - (String) The status of the capacity reservation. + + ->**status** +
• allocating: The capacity reservation is being allocated for use +
• allocated: The total capacity of the reservation has been allocated for use +
• degraded: The capacity reservation has been allocated for use, but some of the capacity is not available +
• unallocated: The capacity reservation is not allocated for use + - `total` - (Integer) The total amount of this capacity reservation. + - `used` - (Integer) The amount of this capacity reservation used by existing attachments. +- `committed_use` - (List) The committed use configuration for this reservation. If absent, this reservation has no commitment for use. + + Nested scheme for `committed_use`: + - `expiration_at` - (Timestamp) The expiration date and time for this committed use reservation. + - `expiration_policy` - (String) The policy to apply when the committed use term expires. + + ->**expiration_policy** +
• release: Release any available capacity and let the reservation expire +
• renew: Renew for another term, provided the term remains listed in the reservation_terms for the profile. Otherwise, let the reservation expire + - `term` - (String) The term for this committed use reservation. + + ->**term** +
• one_year: 1 year +
• three_year: 3 years +- `created_at` - (Timestamp) The date and time that the reservation was created. +- `crn` - (String) The CRN for this reservation. +- `href` - (String) The URL for this reservation. +- `id` - (String) The unique identifier for this reservation. +- `lifecycle_state` - (String) The lifecycle state of this reservation. + + ->**lifecycle_state** +
• deleting +
• failed +
• pending +
• stable +
• suspended +
• updating +
• waiting +- `profile` - (List) The virtual server instance profile this reservation. + + Nested scheme for `profile`: + - `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 + + ->**resource_type** +
• instance_profile +- `resource_group` - (List) The resource group for this reservation. + + Nested scheme 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. + + ->**resource_type** +
• reservation +- `status` - (String) The status of the reservation. + + ->**status** +
• activating +
• active +
• deactivating +
• expired +
• failed +
• inactive +- `status_reasons` - (List) The reasons for the current status (if any). + + Nested scheme for `status_reasons`: + - `code` - (String) A snake case string succinctly identifying the status reason. + + ->**code** +
• cannot_activate_no_capacity_available +
• cannot_renew_unsupported_profile_term + - `message` - (String) An explanation of the status reason. + - `more_info` - (string) Link to documentation about this status reason +- `zone` - (String) The globally unique name for this zone. + +## Import +The `ibm_is_reservation` resource can be imported by using the ID. + +**Syntax** + +``` +$ terraform import ibm_is_reservation.example +``` + +**Example** + +``` +$ terraform import ibm_is_reservation.example d7bec597-4726-451f-8a63-e62e6f12122c +``` + +## References + +* [IBM Cloud Terraform Docs](https://cloud.ibm.com/docs/vpc?topic=vpc-provisioning-reserved-capacity-vpc&interface=ui +https://cloud.ibm.com/docs/vpc?topic=vpc-about-reserved-virtual-servers-vpc) \ No newline at end of file diff --git a/website/docs/r/is_reservation_activate.html.markdown b/website/docs/r/is_reservation_activate.html.markdown new file mode 100644 index 0000000000..db87a485f9 --- /dev/null +++ b/website/docs/r/is_reservation_activate.html.markdown @@ -0,0 +1,157 @@ +--- + +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM: is_reservation_activate" +description: |- + Activates IBM VPC custom reservation. +--- + +# ibm_is_reservation_activate + +Provide support to activate a reservation. This resource activates a reservation, resulting in its status becoming `active`. + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "us-south" +} +``` + +## Example usage + +```terraform +resource "ibm_is_reservation" "example" { + capacity { + total = 10 + } + committed_use { + term = "one_year" + } + profile { + name = "ba2-2x8" + resource_type = "instance_profile" + } + zone = "us-east-3" + name = "reservation-terraform-1" +} + +resource "ibm_is_reservation_activate" "example_activation" { + reservation = ibm_is_reservation.example.id +} +``` + +## Argument reference +Review the argument references that you can specify for your resource. + +- `reservation` - (Required, Forces new resource, String) The id of the reservation to be activated. + +## Attribute reference +You can access the following attribute references after your data source is created. +- `affinity_policy` - (String) The affinity policy to use for this reservation. +- `capacity` - (List) The capacity configuration for this reservation. If absent, this reservation has no assigned capacity. + + Nested scheme for `capacity`: + - `allocated` - (Integer) The amount allocated to this capacity reservation. + - `available` - (Integer) The amount of this capacity reservation available for new attachments. + - `status` - (String) The status of the capacity reservation. + + ->**status** +
• allocating: The capacity reservation is being allocated for use +
• allocated: The total capacity of the reservation has been allocated for use +
• degraded: The capacity reservation has been allocated for use, but some of the capacity is not available +
• unallocated: The capacity reservation is not allocated for use + - `total` - (Integer) The total amount of this capacity reservation. + - `used` - (Integer) The amount of this capacity reservation used by existing attachments. +- `committed_use` - (List) The committed use configuration for this reservation. If absent, this reservation has no commitment for use. + + Nested scheme for `committed_use`: + - `expiration_at` - (Timestamp) The expiration date and time for this committed use reservation. + - `expiration_policy` - (String) The policy to apply when the committed use term expires. + + ->**expiration_policy** +
• release: Release any available capacity and let the reservation expire +
• renew: Renew for another term, provided the term remains listed in the reservation_terms for the profile. Otherwise, let the reservation expire + - `term` - (String) The term for this committed use reservation. + + ->**term** +
• one_year: 1 year +
• three_year: 3 years +- `created_at` - (Timestamp) The date and time that the reservation was created. +- `crn` - (String) The CRN for this reservation. +- `href` - (String) The URL for this reservation. +- `id` - (String) The unique identifier for this reservation. +- `lifecycle_state` - (String) The lifecycle state of this reservation. + + ->**lifecycle_state** +
• deleting +
• failed +
• pending +
• stable +
• suspended +
• updating +
• waiting +- `profile` - (List) The virtual server instance profile this reservation. + + Nested scheme for `profile`: + - `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 + + ->**resource_type** +
• instance_profile +- `resource_group` - (List) The resource group for this reservation. + + Nested scheme 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. + + ->**resource_type** +
• reservation +- `status` - (String) The status of the reservation. + + ->**status** +
• activating +
• active +
• deactivating +
• expired +
• failed +
• inactive +- `status_reasons` - (List) The reasons for the current status (if any). + + Nested scheme for `status_reasons`: + - `code` - (String) A snake case string succinctly identifying the status reason. + + ->**code** +
• cannot_activate_no_capacity_available +
• cannot_renew_unsupported_profile_term + - `message` - (String) An explanation of the status reason. + - `more_info` - (string) Link to documentation about this status reason +- `zone` - (String) The globally unique name for this zone. + + +## Import +The `ibm_is_reservation_activate` resource can be imported by using reservation ID. + +**Syntax** + +``` +$ terraform import ibm_is_reservation_activate.example_activation +``` + +**Example** + +``` +$ terraform import ibm_is_reservation_activate.example_activation d7bec597-4726-451f-8a63-e62e6f121c32c +``` + +## References + +* [IBM Cloud Terraform Docs](https://cloud.ibm.com/docs/vpc?topic=vpc-provisioning-reserved-capacity-vpc&interface=ui +https://cloud.ibm.com/docs/vpc?topic=vpc-about-reserved-virtual-servers-vpc) \ No newline at end of file diff --git a/website/docs/r/is_share.html.markdown b/website/docs/r/is_share.html.markdown index 2319e75337..029d01af0b 100644 --- a/website/docs/r/is_share.html.markdown +++ b/website/docs/r/is_share.html.markdown @@ -51,6 +51,33 @@ resource "ibm_is_share" "example-2" { } } ``` +## Example Usage (Create a file share with inline mount target with a VNI) + +```terraform +resource "ibm_is_subnet" "example" { + name = "my-subnet" + vpc = ibm_is_vpc.vpc2.id + zone = "br-sao-2" + total_ipv4_address_count = 16 +} +resource "ibm_is_virtual_network_interface" "example" { + name = "my-example-vni" + subnet = ibm_is_subnet.example.id +} +resource "ibm_is_share" "example-3" { + zone = "us-south-1" + size = 220 + name = "my-share-1" + profile = "dp2" + mount_targets { + name = "my-mount-target" + virtual_network_interface { + id = ibm_is_virtual_network_interface.example.id + } + } +} +``` + ## Example Usage (Create a cross regional replication) ```terraform resource "ibm_is_share" "example-3" { @@ -89,6 +116,13 @@ The following arguments are supported: Nested scheme for `virtual_network_interface`: - `name` - (Required, String) Name for this virtual network interface. + - `id` - (Optional) The ID for virtual network interface. Mutually exclusive with other `virtual_network_interface` arguments. + + ~> **Note** + `id` is mutually exclusive with other `virtual_network_interface` prototype arguments + - `allow_ip_spoofing` - (Optional, Bool) Indicates whether source IP spoofing is allowed on this interface. If false, source IP spoofing is prevented on this interface. If true, source IP spoofing is allowed on this interface. + - `auto_delete` - (Optional, Bool) Indicates whether this virtual network interface will be automatically deleted when target is deleted + - `enable_infrastructure_nat` - (Optional, Bool) 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 network interface, allowing the workload to perform any needed NAT operations.- `allow_ip_spoofing` must be `false`.- If the virtual network interface is attached: - The target `resource_type` must be `bare_metal_server_network_attachment`. - The target `interface_type` must not be `hipersocket`. - `primary_ip` - (Optional, List) The primary IP address to bind to the virtual network interface. May be either a reserved IP identity, or a reserved IP prototype object which will be used to create a new reserved IP. Nested scheme for `primary_ip`: @@ -125,6 +159,13 @@ The following arguments are supported: - `virtual_network_interface` (Optional, List) The virtual network interface for this share mount target. Required if the share's `access_control_mode` is `security_group`. Nested scheme for `virtual_network_interface`: - `name` - (Required, String) Name for this virtual network interface. + - `id` - (Optional) The ID for virtual network interface. Mutually exclusive with other `virtual_network_interface` arguments. + + ~> **Note** + `id` is mutually exclusive with other `virtual_network_interface` prototype arguments + - `allow_ip_spoofing` - (Optional, Bool) Indicates whether source IP spoofing is allowed on this interface. If false, source IP spoofing is prevented on this interface. If true, source IP spoofing is allowed on this interface. + - `auto_delete` - (Optional, Bool) Indicates whether this virtual network interface will be automatically deleted when target is deleted + - `enable_infrastructure_nat` - (Optional, Bool) 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 network interface, allowing the workload to perform any needed NAT operations.- `allow_ip_spoofing` must be `false`.- If the virtual network interface is attached: - The target `resource_type` must be `bare_metal_server_network_attachment`. - The target `interface_type` must not be `hipersocket`. - `primary_ip` - (Optional, List) The primary IP address to bind to the virtual network interface. May be either a reserved IP identity, or a reserved IP prototype object which will be used to create a new reserved IP. Nested scheme for `primary_ip`: - `auto_delete` - (Optional, Bool) Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound. Defaults to `true` diff --git a/website/docs/r/is_share_mount_target.html.markdown b/website/docs/r/is_share_mount_target.html.markdown index 3bc0c11a3d..32d37b0d45 100644 --- a/website/docs/r/is_share_mount_target.html.markdown +++ b/website/docs/r/is_share_mount_target.html.markdown @@ -90,6 +90,25 @@ resource "ibm_is_share_mount_target" "example" { } name = "my-example-mount-target" } + +//Create mount target with VNI ID +resource "ibm_is_subnet" "example" { + name = "my-subnet" + vpc = ibm_is_vpc.vpc2.id + zone = "br-sao-2" + total_ipv4_address_count = 16 +} +resource "ibm_is_virtual_network_interface" "example" { + name = "my-example-vni" + subnet = ibm_is_subnet.example.id +} +resource "ibm_is_share_mount_target" "mtarget1" { + share = ibm_is_share.share.id + virtual_network_interface { + id = ibm_is_virtual_network_interface.example.id + } + name = "my-example-mount-target" +} ``` ## Argument Reference @@ -99,19 +118,28 @@ The following arguments are supported: - `virtual_network_interface` (Optional, List) The virtual network interface for this share mount target. Required if the share's `access_control_mode` is `security_group`. - `name` - (Required, String) Name for this virtual network interface. Nested scheme for `virtual_network_interface`: + - `id` - (Optional) The ID for virtual network interface. Mutually exclusive with other `virtual_network_interface` arguments. + + ~> **Note** + `id` is mutually exclusive with other `virtual_network_interface` prototype arguments - `primary_ip` - (Optional, List) The primary IP address to bind to the virtual network interface. May be either a reserved IP identity, or a reserved IP prototype object which will be used to create a new reserved IP. Nested scheme for `primary_ip`: + - `auto_delete` - (Optional, Bool) Indicates whether this reserved IP member will be automatically deleted when either target is deleted, or the reserved IP is unbound. Defaults to `true` - `address` - (Optional, Forces new resource, String) The IP address to reserve. If unspecified, an available address on the subnet will automatically be selected. + - `name`- (Optional, String) The name for this reserved IP. The name must not be used by another reserved IP in the subnet. Names starting with ibm- are reserved for provider-owned resources, and are not allowed. - - `reserved_ip`- (Optional, String) The unique identifier for this reserved IP + - `reserved_ip`- (Optional, String) The unique identifier for this reserved IP. + + ~> **Note** + Within `primary_ip`, `reserved_ip` is mutually exclusive to `auto_delete`, `address` and `name` + - `resource_group` - (Optional, String) The ID of the resource group to use. - `security_groups`- (Optional, List of string) The security groups to use for this virtual network interface. - `subnet` - (Optional, string) The associated subnet. - ~> **Note** - Within `primary_ip`, `reserved_ip` is mutually exclusive to `auto_delete`, `address` and `name` + - `vpc` - (Optional, string) The VPC in which instances can mount the file share using this share target. Required if the share's `access_control_mode` is vpc. ~> **Note** @@ -126,12 +154,11 @@ The following arguments are supported: The following attributes are exported: + - `access_control_mode` - (String) The access control mode for the share. -- `mount_target` - (String) The unique identifier of the share target -- `created_at` - (String) The date and time that the share target was created. -- `href` - (String) The URL for this share target. -- `id` - (String) The unique identifier of the ShareTarget. The id is composed of \/\ -- `lifecycle_state` - (String) The lifecycle state of the mount target. +- `allow_ip_spoofing` - (Bool) Indicates whether source IP spoofing is allowed on this interface. If false, source IP spoofing is prevented on this interface. If true, source IP spoofing is allowed on this interface. +- `auto_delete` - (Bool) Indicates whether this virtual network interface will be automatically deleted when target is deleted +- `enable_infrastructure_nat` - (Bool) 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 network interface, allowing the workload to perform any needed NAT operations.- `allow_ip_spoofing` must be `false`.- If the virtual network interface is attached: - The target `resource_type` must be `bare_metal_server_network_attachment`. - The target `interface_type` must not be `hipersocket`. - `mount_path` - (String) The mount path for the share. The server component of the mount path may be either an IP address or a fully qualified domain name. This property will be absent if the lifecycle_state of the mount target is 'pending', failed, or deleting. @@ -139,6 +166,10 @@ The following attributes are exported: -> **If the share's access_control_mode is:** • security_group: The IP address used in the mount path is the primary_ip address of the virtual network interface for this share mount target.
• vpc: The fully-qualified domain name used in the mount path is an address that resolves to the share mount target.
+- `created_at` - (String)The date and time that the share target was created. +- `href` - (String)The URL for this share target. +- `id` - (String)The unique identifier of the ShareTarget. The id is composed of \/\ +- `lifecycle_state` - (String)The lifecycle state of the mount target. - `resource_type` - (String) The type of resource referenced. - `transit_encryption` - (String) The transit encryption mode for this share target. diff --git a/website/docs/r/is_share_replica_operations.html.markdown b/website/docs/r/is_share_replica_operations.html.markdown index 49b6443a40..01b0dfaf83 100644 --- a/website/docs/r/is_share_replica_operations.html.markdown +++ b/website/docs/r/is_share_replica_operations.html.markdown @@ -6,9 +6,9 @@ description: |- subcategory: "VPC infrastructure" --- -# ibm\_is_share_target +# is_share_replica_operations -Provides a resource for ShareTarget. This allows ShareTarget to be created, updated and deleted. +Provides a resource for managing the share operations failover and split. ~> **NOTE** `ibm_is_share_replica_operations` is used for either failing over to replica share or splitting the source and replica shares. @@ -67,7 +67,6 @@ The following arguments are supported: - `split_share` - (Boolean, string) If set to true the replication relationship between source share and replica will be removed. ~>**Note** - `split_share` and `fallback_policy` are mutually exclusive ## Attribute Reference diff --git a/website/docs/r/is_virtual_network_interface.html.markdown b/website/docs/r/is_virtual_network_interface.html.markdown new file mode 100644 index 0000000000..1f71d22ce2 --- /dev/null +++ b/website/docs/r/is_virtual_network_interface.html.markdown @@ -0,0 +1,107 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_virtual_network_interface" +description: |- + Manages Virtual Network Interface. +subcategory: "Virtual Private Cloud API" +--- + +# ibm_is_virtual_network_interface + +Create, update, and delete VirtualNetworkInterfaces with this resource. + +## Example Usage + +```terraform +resource "ibm_is_virtual_network_interface" "is_virtual_network_interface_instance" { + allow_ip_spoofing = true + auto_delete = false + enable_infrastructure_nat = true + name = "my-virtual-network-interface" + subnet = "7ec86020-1c6e-4889-b3f0-a15f2e50f87e" +} +``` + +## Argument Reference + +You can specify the following arguments for this resource. + + +- `access_tags` - (Optional, List of Strings) A list of access management tags to attach to the virtual network interface. + + ~> **Note:** + **•** You can attach only those access tags that already exists.
+ **•** For more information, about creating access tags, see [working with tags](https://cloud.ibm.com/docs/account?topic=account-tag&interface=ui#create-access-console).
+ **•** You must have the access listed in the [Granting users access to tag resources](https://cloud.ibm.com/docs/account?topic=account-access) for `access_tags`
+ **•** `access_tags` must be in the format `key:value`. + +- `allow_ip_spoofing` - (Optional, Boolean) Indicates whether source IP spoofing is allowed on this interface. If `false`, source IP spoofing is prevented on this interface. If `true`, source IP spoofing is allowed on this interface. +- `auto_delete` - (Optional, Boolean) Indicates whether this virtual network interface will be automatically deleted when`target` is deleted. Must be false if the virtual network interface is unbound. +- `enable_infrastructure_nat` - (Optional, 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 network interface, allowing the workload to perform any needed NAT operations.- `allow_ip_spoofing` must be `false`.- If the virtual network interface is attached: - The target `resource_type` must be `bare_metal_server_network_attachment`. - The target `interface_type` must not be `hipersocket`. + +~> **NOTE** to add `ips` only existing `reserved_ip` is supported, new reserved_ip creation is not supported as it leads to unmanaged(dangling) reserved ips. Use `ibm_is_subnet_reserved_ip` to create a reserved_ip +- `ips` - (Optional, List) The reserved IPs bound to this virtual network interface.May be empty when `lifecycle_state` is `pending`. + Nested schema for **ips**: + - `reserved_ip` - (Required, String) The unique identifier for this reserved IP. +- `name` - (Optional, String) The name for this virtual network interface. The name is unique across all virtual network interfaces in the VPC. +- `primary_ip` - (Optional, List) The reserved IP for this virtual network interface. + Nested schema for **primary_ip**: + - `address` - (Required, String) The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `deleted` - (Optional, List) If present, this property indicates the referenced resource has been deleted, and providessome supplementary information. + Nested schema for **deleted**: + - `more_info` - (Required, String) Link to documentation about deleted resources. + - `href` - (Required, String) The URL for this reserved IP. + - `reserved_ip` - (Required, String) The unique identifier for this reserved IP. + - `name` - (Required, String) The name for this reserved IP. The name is unique across all reserved IPs in a subnet. + - `resource_type` - (Computed, String) The resource type. +- `resource_group` - (Optional, String) The resource group id for this virtual network interface. +- `security_groups` - (Optional, Array of string) The security group ids list for this virtual network interface. +- `subnet` - (Optional, List) The associated subnet id. +- `tags` (Optional, Array of Strings) Enter any tags that you want to associate with your VPC. Tags might help you find your VPC more easily after it is created. Separate multiple tags with a comma (`,`). + +## 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 VirtualNetworkInterface. +- `created_at` - (String) The date and time that the virtual network interface was created. +- `crn` - (String) The CRN for this virtual network interface. +- `href` - (String) The URL for this virtual network interface. +- `lifecycle_state` - (String) The lifecycle state of the virtual network interface. Allowable values are: `deleting`, `failed`, `pending`, `stable`, `suspended`, `updating`, `waiting`. +- `mac_address` - (String) The MAC address of the interface. Absent when the interface is not attached to a target. +- `resource_type` - (String) The resource type. +- `target` - (List) The target of this virtual network interface.If absent, this virtual network interface is not attached to a target. + 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 share mount target. + - `id` - (String) The unique identifier for this share mount target. + - `name` - (String) The name for this share mount target. The name is unique across all mount targets for the file share. + - `resource_type` - (String) The resource type. +- `vpc` - (List) The VPC this virtual 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` - (String) The zone name of the zone this virtual network interface resides in. + + +## Import + +You can import the `ibm_is_virtual_network_interface` resource by using `id`. The unique identifier for this virtual network interface. + +# Syntax +``` +$ terraform import ibm_is_virtual_network_interface.is_virtual_network_interface +``` + +# Example +``` +$ terraform import ibm_is_virtual_network_interface.is_virtual_network_interface 0767-fa41aecb-4f21-423d-8082-630bfba1e1d9 +``` diff --git a/website/docs/r/is_virtual_network_interface_floating_ip.html.markdown b/website/docs/r/is_virtual_network_interface_floating_ip.html.markdown new file mode 100644 index 0000000000..e278455e7d --- /dev/null +++ b/website/docs/r/is_virtual_network_interface_floating_ip.html.markdown @@ -0,0 +1,53 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_virtual_network_interface_floating_ip" +description: |- + Manages Virtual Network Interface Floating IP. +subcategory: "Virtual Private Cloud API" +--- + +# ibm_is_virtual_network_interface_floating_ip + +Create, read, and delete Virtual Network Interface Floating IP with this resource. + +## Example Usage + +```terrform +resource "ibm_is_virtual_network_interface_floating_ip" "vni_fip" { + virtual_network_interface = ibm_is_virtual_network_interface.example.id + floating_ip = ibm_is_floating_ip.example.id +} +``` + +## Argument Reference + +You can specify the following arguments for this resource. + +- `virtual_network_interface` - (Required, String) The virtual network interface identifier +- `floating_ip` - (Required, String) The floating IP identifier +## 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 VirtualNetworkInterfaceFloatingIP. The ID is composed of `/`. +- `address` - (String) The globally unique IP address. +- `crn` - (String) The CRN for this floating IP. +- `href` - (String) The URL for this floating IP. +- `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + Nested scheme for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. +- `name` - (String) The name for this floating IP. The name is unique across all floating IPs in the region. + +## Import + +You can import the `ibm_is_virtual_network_interface_floating_ip` resource by using `< vni_id >/< floating_ip_id >` combination. The unique identifier for this floating IP. + +# Syntax +``` +$ terraform import ibm_is_virtual_network_interface_floating_ip.vni_fip < vni_id >/< floating_ip_id > +``` + +# Example +``` + +``` diff --git a/website/docs/r/is_virtual_network_interface_ip.html.markdown b/website/docs/r/is_virtual_network_interface_ip.html.markdown new file mode 100644 index 0000000000..d8de88e0d3 --- /dev/null +++ b/website/docs/r/is_virtual_network_interface_ip.html.markdown @@ -0,0 +1,57 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_virtual_network_interface_ip" +description: |- + Manages virtual_network_interface reserved ip attachment. +subcategory: "Virtual Private Cloud API" +--- + +# ibm_is_virtual_network_interface_ip + +Create, update, and delete ReservedIP virtual network instance attachment with this resource. + +## Example Usage + +```hcl +resource "ibm_is_virtual_network_interface_ip" "is_reserved_ip_instance" { + reserved_ip = ibm_is_subnet_reserved_ip.example.reserved_ip + virtual_network_interface = ibm_is_virtual_network_interface.example.id +} +``` + +## Argument Reference + +You can specify the following arguments for this resource. + +- `reserved_ip` - (Required, Forces new resource, String) The reserved IP identifier. +- `virtual_network_interface` - (Required, Forces new resource, String) The virtual network interface identifier. + +## Attribute Reference + +After your resource is created, you can read values from the listed arguments and the following attributes. + +- `address` - (String) The IP address.If the address has not yet been selected, the value will be `0.0.0.0`.This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. +- `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + Nested scheme for **deleted**: + - `more_info` - (String) Link to documentation about deleted resources. +- `href` - (String) The URL for this reserved IP. +- `id` - (String) The unique identifier for this reserved IP. +- `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. + + +## Import + +You can import the `ibm_is_virtual_network_interface_ip` resource by using `id`. +The `id` property can be formed from `virtual_network_interface`, and `reserved_ip` in the following format: + +``` +/ +``` +* `virtual_network_interface`: A string. The subnet identifier. +* `reserved_ip`: A string. The reserved IP identifier. + +# Syntax +``` +$ terraform import ibm_is_virtual_network_interface_ip.is_reserved_ip / +``` diff --git a/website/docs/r/is_vpn_gateway.html.markdown b/website/docs/r/is_vpn_gateway.html.markdown index e5b632a5a9..a0e030c34d 100644 --- a/website/docs/r/is_vpn_gateway.html.markdown +++ b/website/docs/r/is_vpn_gateway.html.markdown @@ -74,12 +74,10 @@ In addition to all argument reference list, you can access the following attribu - `address` - (String) The public IP address assigned to the VPN gateway member. - `private_address` - (String) The private IP address assigned to the VPN gateway member. - `role` - (String) The high availability role assigned to the VPN gateway member. - - `status` - (String) The status of the VPN gateway member. - `public_ip_address` - (String) The IP address assigned to this VPN gateway. - `public_ip_address2` - (String) The Second Public IP address assigned to this VPN gateway member. - `private_ip_address` - (String) The Private IP address assigned to this VPN gateway member. - `private_ip_address2` - (String) The Second Private IP address assigned to this VPN gateway. -- `status` - (String) The status of the VPN gateway. Supported values are **available**, **deleting**, **failed**, or **pending**. - `health_reasons` - (List) The reasons for the current health_state (if any). Nested scheme for `health_reasons`: diff --git a/website/docs/r/pi_dhcp.html.markdown b/website/docs/r/pi_dhcp.html.markdown index b39b0b9c83..4681c2d289 100644 --- a/website/docs/r/pi_dhcp.html.markdown +++ b/website/docs/r/pi_dhcp.html.markdown @@ -40,7 +40,6 @@ In addition to all argument reference list, you can access the following attribu Nested scheme for `leases`: - `instance_ip` - (String) The IP of the PVM Instance. - `instance_mac` - (String) The MAC Address of the PVM Instance. -- `network` - (String) The ID of the DHCP Server private network (deprecated - replaced by `network_id`). - `network_id`- (String) The ID of the DHCP Server private network. - `network_name` - The name of the DHCP Server private network. - `status` - (String) The status of the DHCP Server. diff --git a/website/docs/r/pi_instance.html.markdown b/website/docs/r/pi_instance.html.markdown index 429320d53d..1b79b56f62 100644 --- a/website/docs/r/pi_instance.html.markdown +++ b/website/docs/r/pi_instance.html.markdown @@ -64,8 +64,13 @@ Review the argument references that you can specify for your resource. - `pi_anti_affinity_instances` - (Optional, String) List of pvmInstances to base storage anti-affinity policy against; required if requesting `anti-affinity` and `pi_anti_affinity_volumes` is not provided. - `pi_anti_affinity_volumes`- (Optional, String) List of volumes to base storage anti-affinity policy against; required if requesting `anti-affinity` and `pi_anti_affinity_instances` is not provided. - `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. -- `pi_deployment_type` - (Optional, String) Custom deployment type; Allowable value: `EPIC`. +- `pi_deployment_type` - (Optional, String) Custom deployment type; Allowable value: `EPIC` or `VMNoStorage`. - `pi_health_status` - (Optional, String) Specifies if Terraform should poll for the health status to be `OK` or `WARNING`. The default value is `OK`. + +**Notes** Ibmi software licenses for IBMi virtual server instances -- only for IBMi instances. Default to `false` and `0` if no values provided +- `pi_ibmi_css` - (Optional, Boolean) IBMi Cloud Storage Solution. +- `pi_ibmi_pha` - (Optional, Boolean) IBMi Power High Availability. +- `pi_ibmi_rds_users` - (Optional, Integer) IBMi Rational Dev Studio Number of User Licenses. - `pi_image_id` - (Required, String) The ID of the image that you want to use for your Power Systems Virtual Server instance. The image determines the operating system that is installed in your instance. To list available images, run the `ibmcloud pi images` command. - **Note**: only images belonging to your project can be used image for deploying a Power Systems Virtual Server instance. To import an images to your project, see [ibm_pi_image](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/pi_image). - `pi_instance_name` - (Required, String) The name of the Power Systems Virtual Server instance. @@ -74,7 +79,6 @@ Review the argument references that you can specify for your resource. - **Note**: Provisioning VTL instances is temporarily disabled. - `pi_memory` - (Optional, Float) The amount of memory that you want to assign to your instance in gigabytes. - Required when not creating SAP instances. Conflicts with `pi_sap_profile_id`. -- `pi_migratable`- (Optional, Bool) Indicates the VM is migrated or not. - `pi_network` - (Required, List of Map) List of one or more networks to attach to the instance. The `pi_network` block supports: @@ -94,18 +98,21 @@ Review the argument references that you can specify for your resource. - `pi_sap_deployment_type` - (Optional, String) Custom SAP deployment type information (For Internal Use Only). - `pi_shared_processor_pool` - (Optional, String) The shared processor pool for instance deployment. Conflicts with `pi_sap_profile_id`. - `pi_storage_pool` - (Optional, String) Storage Pool for server deployment; if provided then `pi_affinity_policy` will be ignored; Only valid when you deploy one of the IBM supplied stock images. Storage pool for a custom image (an imported image or an image that is created from a VM capture) defaults to the storage pool the image was created in. -- `pi_storage_pool_affinity` - (Optional, Bool) Indicates if all volumes attached to the server must reside in the same storage pool. The default value is `true`. To attach data volumes from a different storage pool (mixed storage) set to `false` and use `pi_volume_attach` resource. Once set to `false`, cannot be set back to `true` unless all volumes attached reside in the same storage type and pool. +- `pi_storage_pool_affinity` - (Optional, Boolean) Indicates if all volumes attached to the server must reside in the same storage pool. The default value is `true`. To attach data volumes from a different storage pool (mixed storage) set to `false` and use `pi_volume_attach` resource. Once set to `false`, cannot be set back to `true` unless all volumes attached reside in the same storage type and pool. - `pi_storage_type` - (Optional, String) - Storage type for server deployment; If storage type is not provided the storage type will default to `tier3`. - `pi_storage_connection` - (Optional, String) - Storage Connectivity Group (SCG) for server deployment. Only supported value is `vSCSI`. - `pi_sys_type` - (Optional, String) The type of system on which to create the VM (s922/e880/e980/s1022). - Supported SAP system types are (e880/e980). - `pi_user_data` - (Optional, String) The user data `cloud-init` to pass to the instance during creation. It can be a base64 encoded or an unencoded string. If it is an unencoded string, the provider will encode it before it passing it down. - `pi_virtual_cores_assigned` - (Optional, Integer) Specify the number of virtual cores to be assigned. +- `pi_virtual_optical_device` - (Optional, String) Virtual Machine's Cloud Initialization Virtual Optical Device. - `pi_volume_ids` - (Optional, List of String) The list of volume IDs that you want to attach to the instance during creation. + ## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your resource is created. - `health_status` - (String) The health status of the VM. +- `ibmi_rds` - (Boolean) IBMi Rational Dev Studio. - `id` - (String) The unique identifier of the instance. The ID is composed of `/`. - `instance_id` - (String) The unique identifier of the instance. - `max_processors`- (Float) The maximum number of processors that can be allocated to the instance with shutting down or rebooting the `LPAR`. diff --git a/website/docs/r/pi_key.html.markdown b/website/docs/r/pi_key.html.markdown index d43ef988cc..49ac710353 100644 --- a/website/docs/r/pi_key.html.markdown +++ b/website/docs/r/pi_key.html.markdown @@ -32,7 +32,6 @@ Review the argument references that you can specify for your resource. 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 the key. The ID is composed of `/`. -- `key_id` - (String) User defined name for the SSH key (deprecated - replaced by `name`). - `name` - (String) User defined name for the SSH key - `creation_date` - (String) Date of SSH Key creation. - `ssh_key` - (String) SSH RSA key. diff --git a/website/docs/r/pi_network.html.markdown b/website/docs/r/pi_network.html.markdown index 4abefe7694..a48ce11c10 100644 --- a/website/docs/r/pi_network.html.markdown +++ b/website/docs/r/pi_network.html.markdown @@ -69,7 +69,7 @@ Review the argument references that you can specify for your resource. The `pi_ipaddress_range` block supports: - `pi_ending_ip_address` - (Required, String) The ending ip address. - `pi_starting_ip_address` - (Required, String) The staring ip address. **Note** if the `pi_gateway` or `pi_ipaddress_range` is not provided, it will calculate the value based on CIDR respectively. -- `pi_network_jumbo` - (Optional, Bool) MTU Jumbo option of the network (for multi-zone locations only). `deprecated` use `pi_network_mtu` instead. +- `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). diff --git a/website/docs/r/pi_network_port.html.markdown b/website/docs/r/pi_network_port.html.markdown deleted file mode 100644 index afcb10662e..0000000000 --- a/website/docs/r/pi_network_port.html.markdown +++ /dev/null @@ -1,75 +0,0 @@ ---- - -subcategory: "Power Systems" -layout: "ibm" -page_title: "IBM: pi_network_port" -description: |- - Manages an Network Port in the Power Virtual Server Cloud. A network port is equivalent to reserving an IP in the subnet. - When the port is created the status will be "DOWN". This network port however is not attached to an instance. ---- - -# ibm_pi_network_port -Creates or updates network port in the Power Virtual Server Cloud. For more information, about network in IBM power virutal server, see [adding or removing a public network -](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-modifying-server#adding-removing-network).. - -## Example usage - -In the following example, you can create an network_port: - -```terraform -resource "ibm_pi_network_port" "test-network-port" { - pi_network_name = "Zone1-CFN" - pi_cloud_instance_id = "51e1879c-bcbe-4ee1-a008-49cdba0eaf60" - pi_network_port_description = "IP Reserved for Oracle RAC " -} -``` - -**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` - - Example usage: - - ```terraform - provider "ibm" { - region = "lon" - zone = "lon04" - } - ``` - -## Timeouts - -ibm_pi_network_port provides the following [timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: - -- **create** - (Default 60 minutes) Used for creating a network_port. -- **delete** - (Default 60 minutes) Used for deleting a network_port. - -## 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_network_name` - (Required, String) Network ID or name. -- `pi_network_port_description` - (Optional, String) The description for the Network Port. -- `pi_network_port_ipaddress` - (Optional, String) The requested ip address of this port. - -## 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 the instance. The ID is composed of `//`. -- `macaddress` - (String) The MAC address of the port. -- `portid` - (String) The ID of the port. -- `public_ip` - (String) The public IP associated with the port. -- `status` - (String) The status of the port. - - -## Import - -The `ibm_pi_network_port` resource can be imported by using `power_instance_id`, `port_id` and `pi_network_name`. - -**Example** - -``` -$ terraform import ibm_pi_network_port.example d7bec597-4726-451f-8a63-e62e6f19c32c/cea6651a-bc0a-4438-9f8a-a0770bbf3ebb/network-name -``` diff --git a/website/docs/r/pi_network_port_attach.html.markdown b/website/docs/r/pi_network_port_attach.html.markdown index de0c14dfa5..b12d5b2a7f 100644 --- a/website/docs/r/pi_network_port_attach.html.markdown +++ b/website/docs/r/pi_network_port_attach.html.markdown @@ -61,14 +61,13 @@ In addition to all argument reference list, you can access the following attribu - `id` - (String) The unique identifier of the instance. The ID is composed of `//`. - `macaddress` - (String) The MAC address of the port. - `network_port_id` - (String) The ID of the port. -- `portid` - (Deprecated, String) The ID of the port. - `public_ip` - (String) The public IP associated with the port. - `status` - (String) The status of the port. ## Import -The `ibm_pi_network_port` resource can be imported by using `power_instance_id`, `pi_network_name` and `port_id`. +The `ibm_pi_network_port` resource can be imported by using `power_instance_id`, `pi_network_name` and `network_port_id`. **Example** diff --git a/website/docs/r/pi_snapshot.html.markdown b/website/docs/r/pi_snapshot.html.markdown index 59d4885f29..e16eac403f 100644 --- a/website/docs/r/pi_snapshot.html.markdown +++ b/website/docs/r/pi_snapshot.html.markdown @@ -58,7 +58,7 @@ Review the argument references that you can specify for your resource. ## 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 the snapshot. The ID is composed of /. +- `id` - (String) The unique identifier of the snapshot. The ID is composed of /. - `snapshot_id` - (String) ID of the PVM instance snapshot. - `status` - (String) Status of the PVM instance snapshot. - `creation_date` - (String) Creation Date. @@ -67,7 +67,7 @@ In addition to all argument reference list, you can access the following attribu ## Import -The `ibm_pi_snapshot` resource can be imported by using `power_instance_id` and `pi_snap_shot_id`. +The `ibm_pi_snapshot` resource can be imported by using `power_instance_id` and `snapshot_id`. **Example** diff --git a/website/docs/r/pi_volume_attach.html.markdown b/website/docs/r/pi_volume_attach.html.markdown index 776fe077f3..12aeddf359 100644 --- a/website/docs/r/pi_volume_attach.html.markdown +++ b/website/docs/r/pi_volume_attach.html.markdown @@ -8,7 +8,7 @@ description: |- --- # ibm_pi_volume_attach -Attaches volume to a Power Systems Virtual Server instance. For more information, about managing volume, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). +Attaches and Detaches a volume to a Power Systems Virtual Server instance. For more information, about managing volume, 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 attaches volume to a power systems virtual server instance. diff --git a/website/docs/r/pi_workspace.html.markdown b/website/docs/r/pi_workspace.html.markdown index b17e5ca2a4..2f3ae69fd3 100644 --- a/website/docs/r/pi_workspace.html.markdown +++ b/website/docs/r/pi_workspace.html.markdown @@ -1,49 +1,54 @@ ---- - -subcategory: "Power Systems" -layout: "ibm" -page_title: "IBM: pi_workspace" -description: |- - Manages a workspace in the Power Virtual Server cloud. ---- - -# ibm_pi_workspace - -Create or Delete a PowerVS Workspace - -## Example usage - -```terraform -data "ibm_resource_group" "group" { - name = "test" -} - -resource "ibm_pi_workspace" "powervs_service_instance" { - pi_name = "test-name" - pi_datacenter = "us-east" - pi_resource_group_id = data.ibm_resource_group.group.id - pi_plan = "public" -} -``` - -## 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` - -## Argument reference - -Review the argument references that you can specify for your resource. - -- `pi_name` - (Required, String) A descriptive name used to identify the workspace. -- `pi_datacenter` - (Required, String) Target location or environment to create the resource instance. -- `pi_resource_group_id` - (Required, String) The ID of the resource group where you want to create the workspace. You can retrieve the value from data source `ibm_resource_group`. -- `pi_plan` - (Required, String) Plan associated with the offering; Valid values are `public` or `private`. - -## Attribute reference - -In addition to all argument reference listed, you can access the following attribute references after your resource source is created. - -- `id` - (String) Workspace ID. \ No newline at end of file +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_workspace" +description: |- + Manages a workspace in the Power Virtual Server cloud. +--- + +# ibm_pi_workspace + +Create or Delete a PowerVS Workspace + +## Example usage + +```terraform +data "ibm_resource_group" "group" { + name = "test" +} + +resource "ibm_pi_workspace" "powervs_service_instance" { + pi_name = "test-name" + pi_datacenter = "us-east" + pi_resource_group_id = data.ibm_resource_group.group.id + pi_plan = "public" +} +``` + +## 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` + +## Argument reference + +Review the argument references that you can specify for your resource. + +- `pi_name` - (Required, String) A descriptive name used to identify the workspace. +- `pi_datacenter` - (Required, String) Target location or environment to create the resource instance. +- `pi_resource_group_id` - (Required, String) The ID of the resource group where you want to create the workspace. You can retrieve the value from data source `ibm_resource_group`. +- `pi_plan` - (Required, String) Plan associated with the offering; Valid values are `public` or `private`. + +## Attribute reference + +In addition to all argument reference listed, you can access the following attribute references after your resource source is created. + +- `id` - (String) Workspace ID. +- `workspace_details` - (Map) Workspace information. + + Nested schema for `workspace_details`: + - `creation_date` - (String) Date of workspace creation. + - `crn` - (String) Workspace crn. \ No newline at end of file diff --git a/website/docs/r/project.html.markdown b/website/docs/r/project.html.markdown index 3f0b5d0280..5e09665ee4 100644 --- a/website/docs/r/project.html.markdown +++ b/website/docs/r/project.html.markdown @@ -18,6 +18,7 @@ resource "ibm_project" "project_instance" { name = "My static website" description = "Sample static website test using the IBM catalog deployable architecture" destroy_on_delete = true + monitoring_enabled = true } location = "us-south" resource_group = "Default" @@ -30,9 +31,11 @@ You can specify the following arguments for this resource. * `definition` - (Required, List) The definition of the project. Nested schema for **definition**: - * `description` - (Optional, String) A brief explanation of the project's use in the configuration of a deployable architecture. It is possible to create a project without providing a description. - * Constraints: The maximum length is `1024` characters. The minimum length is `0` characters. The value must match regular expression `/^$|^(?!\\s)(?!.*\\s$)[^\\x00-\\x1F]*$/`. + * `description` - (Required, String) A brief explanation of the project's use in the configuration of a deployable architecture. It is possible to create a project without providing a description. + * Constraints: The default value is ``. The maximum length is `1024` characters. The minimum length is `0` characters. The value must match regular expression `/^$|^(?!\\s)(?!.*\\s$)[^\\x00-\\x1F]*$/`. * `destroy_on_delete` - (Required, Boolean) The policy that indicates whether the resources are destroyed or not when a project is deleted. + * `monitoring_enabled` - (Boolean) A boolean flag to enable project monitoring. + * Constraints: The default value is `false`. * `name` - (Required, String) The name of the project. It is unique within the account across regions. * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^(?!\\s)(?!.*\\s$)[^'"`<>{}\\x00-\\x1F]+$/`. * `location` - (Required, Forces new resource, String) The IBM Cloud location where a resource is deployed. @@ -52,7 +55,7 @@ Nested schema for **configs**: * `definition` - (List) The name and description of a project configuration. Nested schema for **definition**: * `description` - (String) A project configuration description. - * Constraints: The maximum length is `1024` characters. The minimum length is `0` characters. The value must match regular expression `/^$|^(?!\\s)(?!.*\\s$)[^\\x00-\\x1F]*$/`. + * Constraints: The default value is ``. The maximum length is `1024` characters. The minimum length is `0` characters. The value must match regular expression `/^$|^(?!\\s)(?!.*\\s$)[^\\x00-\\x1F]*$/`. * `name` - (String) The configuration name. It is unique within the account across projects and regions. * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9][a-zA-Z0-9-_ ]*$/`. * `deployment_model` - (String) The configuration type. @@ -99,7 +102,7 @@ Nested schema for **environments**: * `definition` - (List) The environment definition used in the project collection. Nested schema for **definition**: * `description` - (String) The description of the environment. - * Constraints: The maximum length is `1024` characters. The minimum length is `0` characters. The value must match regular expression `/^$|^(?!\\s)(?!.*\\s$)[^\\x00-\\x1F]*$/`. + * Constraints: The default value is ``. The maximum length is `1024` characters. The minimum length is `0` characters. The value must match regular expression `/^$|^(?!\\s)(?!.*\\s$)[^\\x00-\\x1F]*$/`. * `name` - (String) The name of the environment. It is unique within the account across projects and regions. * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^(?!\\s)(?!.*\\s$)[^'"`<>{}\\x00-\\x1F]+$/`. * `href` - (String) A URL. diff --git a/website/docs/r/project_config.html.markdown b/website/docs/r/project_config.html.markdown index ab71abbf40..9459f221fa 100644 --- a/website/docs/r/project_config.html.markdown +++ b/website/docs/r/project_config.html.markdown @@ -57,7 +57,7 @@ Nested schema for **definition**: * `profile_name` - (Optional, String) The name of the compliance profile. * Constraints: The maximum length is `1024` characters. The minimum length is `0` characters. The value must match regular expression `/^(?!\\s)(?!.*\\s$)[^`<>\\x00-\\x1F]*$/`. * `description` - (Optional, String) A project configuration description. - * Constraints: The maximum length is `1024` characters. The minimum length is `0` characters. The value must match regular expression `/^$|^(?!\\s)(?!.*\\s$)[^\\x00-\\x1F]*$/`. + * Constraints: The default value is ``. The maximum length is `1024` characters. The minimum length is `0` characters. The value must match regular expression `/^$|^(?!\\s)(?!.*\\s$)[^\\x00-\\x1F]*$/`. * `environment_id` - (Optional, String) The ID of the project environment. * Constraints: The maximum length is `128` characters. The value must match regular expression `/^[\\.\\-0-9a-zA-Z]+$/`. * `inputs` - (Optional, Map) The input variables for configuration definition and environment. diff --git a/website/docs/r/project_environment.html.markdown b/website/docs/r/project_environment.html.markdown index 218a8dfa38..db8000b55d 100644 --- a/website/docs/r/project_environment.html.markdown +++ b/website/docs/r/project_environment.html.markdown @@ -53,7 +53,7 @@ Nested schema for **definition**: * `profile_name` - (Optional, String) The name of the compliance profile. * Constraints: The maximum length is `1024` characters. The minimum length is `0` characters. The value must match regular expression `/^(?!\\s)(?!.*\\s$)[^`<>\\x00-\\x1F]*$/`. * `description` - (Optional, String) The description of the environment. - * Constraints: The maximum length is `1024` characters. The minimum length is `0` characters. The value must match regular expression `/^$|^(?!\\s)(?!.*\\s$)[^\\x00-\\x1F]*$/`. + * Constraints: The default value is ``. The maximum length is `1024` characters. The minimum length is `0` characters. The value must match regular expression `/^$|^(?!\\s)(?!.*\\s$)[^\\x00-\\x1F]*$/`. * `inputs` - (Optional, Map) The input variables for configuration definition and environment. * `name` - (Required, String) The name of the environment. It is unique within the account across projects and regions. * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^(?!\\s)(?!.*\\s$)[^'"`<>{}\\x00-\\x1F]+$/`. diff --git a/website/docs/r/resource_instance.html.markdown b/website/docs/r/resource_instance.html.markdown index 062c8ab5df..bcf881ad9c 100644 --- a/website/docs/r/resource_instance.html.markdown +++ b/website/docs/r/resource_instance.html.markdown @@ -132,6 +132,33 @@ resource "ibm_resource_instance" "instance" { } ``` +### Example to provision an OpenPages service instance +The following example enables you to create a service instance of OpenPages. + +```terraform +data "ibm_resource_group" "group" { + name = "default" +} +resource "ibm_resource_instance" "openpages_instance" { + name = "openpages-instance-1" + service = "openpages" + plan = "essentials" + location = "global" + resource_group_id = data.ibm_resource_group.default_group.id + parameters_json = <