From 8466749fd29efadbb8b9f814af28371144ec03b5 Mon Sep 17 00:00:00 2001 From: Andy McCullough Date: Tue, 30 Aug 2022 18:32:18 +0100 Subject: [PATCH] Squashed commit of the following: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit b1f893fdbf8757104d0bd89a98aabfb1a8c95491 Author: Sadik Tekin Date: Tue Aug 30 15:39:11 2022 +0100 Policy Mode Docs (#18181) commit 4b6431e6e063018f59355b160836dadb857c9e3f Author: stephybun Date: Tue Aug 30 16:14:56 2022 +0200 remove preview comment for spot node pools and fix identity block in docs (#18180) commit b6db3e48da8d9538f5582ce225db22160d92369e Author: Tom Harvey Date: Tue Aug 30 15:10:37 2022 +0200 updating to include #18183 commit 8924a86a55015797d88caf81e108fe0e09e42097 Merge: 20b663df52 6baa23350b Author: Tom Harvey Date: Tue Aug 30 15:10:05 2022 +0200 Merge pull request #18183 from hashicorp/deps/go-azure-sdk-v0.20220830.1105041 Dependencies: update `go-azure-sdk` to `v0.20220830.1105041` commit 20b663df52c4fc6d6cbc6630545537b666f408c2 Author: catriona-m <86247157+catriona-m@users.noreply.github.com> Date: Tue Aug 30 13:36:04 2022 +0100 Update changelog for #18098 commit df55361ed757831287526c6f38f22b5ccffbb500 Author: catriona-m <86247157+catriona-m@users.noreply.github.com> Date: Tue Aug 30 13:34:26 2022 +0100 `log_analytics` - switch to using hashicorp/go-azure-sdk (#18098) * update log analytics sdk * update log analytics sdk * convert if-else to switch statement * correct validator * remove unused generates * update sentinel nrt to use go-azure-sdk workspace parser * fix merge commit 6baa23350b97185c3d6af7e21d328da7aba7bb39 Author: Steve Jones Date: Tue Aug 30 13:06:02 2022 +0200 update sdk to v0.20220830.1105041, adjust casing fixes in container_group and service_fabric_managed_cluster commit 1e5083a7239118c4c605ff3e61151406e053afd2 Merge: 9bbc36723c 4758d20bc5 Author: Tom Harvey Date: Tue Aug 30 12:02:56 2022 +0200 Merge pull request #18176 from magodo/v3_upgrade_doc_miss_customer_managed_key Upgrade guide (v3): adding up the change for `customer_managed_key` of `azurerm_storage_account` commit 9bbc36723cec9f03513168fa4798ee14d1adabd0 Author: stephybun Date: Tue Aug 30 11:57:02 2022 +0200 Update for #18124 commit 4e79902dddba72cdcc13dd7ba74c4431dc961338 Author: Igor Beliakov <46579601+weisdd@users.noreply.github.com> Date: Tue Aug 30 11:53:35 2022 +0200 feat(AKS): add support for spot node pools upgrades (#18124) Signed-off-by: Igor Beliakov Signed-off-by: Igor Beliakov commit fc67715766bb6bfd32dd6646104d3546991ecae0 Author: magodo Date: Tue Aug 30 17:31:31 2022 +0800 CHANGELOG #17351 commit ef018c45c3c357a6edfefef48374a0b93e5c50f7 Author: JT <100274846+jiaweitao001@users.noreply.github.com> Date: Tue Aug 30 17:27:58 2022 +0800 `azurerm_hdinsight_kafka_cluster`, `azurerm_hdinsight_spark_cluster`, `azurerm_hdinsight_interactive_query_cluster`, `azurerm_hdinsight_hbase_cluster`, `azurerm_hdinsight_hadoop_cluster` - add support for `disk_encryption_properties` property (#17351) commit ca7b392f1d66138b8ca13d41f6a95334f750eb8e Author: magodo Date: Tue Aug 30 17:09:31 2022 +0800 CHANGELOG Fix typo commit 09e53470d3ab01f33f9a94bbf349f19927ef8868 Author: magodo Date: Tue Aug 30 17:08:36 2022 +0800 CHANGELOG #17926 commit 8960805383acccde1c2d231c5962166335b0302b Author: magodo Date: Tue Aug 30 17:07:29 2022 +0800 Update ACR API version to 2022-02-01-preview and add up the new properties (#17926) Update ACR API version to 2022-02-01-preview and add up the new properties commit 4758d20bc54f4f474e86832913ff63887571dbc4 Author: magodo Date: Tue Aug 30 16:20:06 2022 +0800 v3 Upgrade doc: adding up the change for `customer_managed_key` of `azurerm_storage_account` commit 15935cb296710ce06ade3a8e8c25acfc08979f3a Author: Tao <104055472+teowa@users.noreply.github.com> Date: Tue Aug 30 15:54:29 2022 +0800 Hotfix - Recover Mistakenly Deleted DCE Client Code (#18174) commit 1163a9e397d33720cfdb810c01edc4ef08180af2 Author: magodo Date: Tue Aug 30 14:54:14 2022 +0800 CHANGELOG #17879 commit 416ad43ce627c6a521ed247dd035fc51fba7ef61 Author: Elena Xin <39109137+sinbai@users.noreply.github.com> Date: Tue Aug 30 14:53:29 2022 +0800 new resource azurerm_api_management_gateway_certificate_authority (#17879) New Resource : `azurerm_api_management_gateway_certificate_authority` commit 1bdae6af4a7b16f230f0d47eef17558c0c9cdbc8 Author: magodo Date: Tue Aug 30 14:52:05 2022 +0800 CHANGELOG #17881 commit e34679a28e846a9ec74c90e149fa0402536c66ea Author: Xu Wu Date: Tue Aug 30 14:51:05 2022 +0800 New Resource: `azurerm_automation_hybrid_runbook_worker_group` (#17881) New Resource: `azurerm_automation_hybrid_runbook_worker_group` commit 10e0f472b56129f8b872ae1a3c776f2d3b9fd7d8 Author: magodo Date: Tue Aug 30 14:16:25 2022 +0800 CHANGELOG #18005 commit 641ab60e77a42de69c7c1c8545ff777ef1c5e988 Author: magodo Date: Tue Aug 30 14:15:03 2022 +0800 `azurerm_storage_account` - support for the `public_network_access_enabled` property (#18005) `azurerm_storage_account` - support for the `public_network_access_enabled` property commit 8c8dcd34a2b5effbeb744880805ff2f78ed9a444 Author: Noel Jones <31277326+Noel-Jones@users.noreply.github.com> Date: Tue Aug 30 06:23:37 2022 +0100 Support for static IP configuration in azurerm_private_endpoint #13061 (#17864) Co-authored-by: Noel Jones commit 4ab312caeabb776b4d7cd02ee3294ac8e5b2bf08 Author: Richard Cheney Date: Tue Aug 30 06:18:21 2022 +0100 Permit additional partner_id formats (#17441) Co-authored-by: kt commit e1bdb30178bd7d3f19be604ca03fcab7784e79e4 Author: Xiaxin <92154856+xiaxyi@users.noreply.github.com> Date: Tue Aug 30 13:11:06 2022 +0800 `azurerm_servicebus_namespace` - Adding support of property `public_network_access_enabled`, `minimum_tls_version` (#17805) `azurerm_servicebus_namespace` - Adding support of property `public_network_access_enabled`, `minimum_tls_version` commit 35f896759da0c06b9693448509b346defee1e92e Author: kt Date: Mon Aug 29 22:01:13 2022 -0700 CHANGELOG #15120 commit ac875e28812b623c3547ab0f616cad893dc6d484 Author: magodo Date: Tue Aug 30 13:00:20 2022 +0800 New resource: `azurerm_container_registry_task_schedule` (#15120) Co-authored-by: kt commit 9604249cc04c93d2fd1f9cbf6f8dc56fa6091f06 Author: Xu Wu Date: Tue Aug 30 12:54:44 2022 +0800 Docs: Fix outdated reference link of `timezone` of `azurerm_automation_schedule` (#18160) Co-authored-by: xuwu1 commit aa1b6b4bff8a50d8ba6a787ad27d07c6a934b872 Author: kt Date: Mon Aug 29 21:15:38 2022 -0700 CHANGELOG #18151 commit 9fa9a8f2883d1d71bbdb8cedea0a3408979990a9 Author: Yichun Ma Date: Tue Aug 30 12:14:57 2022 +0800 `azurerm_iothub_dps` - support for `data_residency_enabled` property (#18151) commit 403db16d3f7aa28b68910b3ba12fabb4c6c6464d Author: Xiaxin <92154856+xiaxyi@users.noreply.github.com> Date: Tue Aug 30 12:13:39 2022 +0800 `azurerm_windows_function_app`, `azurerm_linux_function_app`: fix the `runtime_scale_monitoring_enabled` not being set issue (#18149) commit 4274f700503a67ffdb159093193ff44a79885a61 Author: kt Date: Mon Aug 29 20:55:25 2022 -0700 CHANGELOG #18137 commit c901e52888478c0cca734873e4ae70f635da783c Author: JT <100274846+jiaweitao001@users.noreply.github.com> Date: Tue Aug 30 11:54:53 2022 +0800 `azurerm_stream_analytics_reference_input_blob` - support for `authentication_mode` (#18137) commit 5e935003bad83434a7069d10e2a051ca4ec190f3 Author: kt Date: Mon Aug 29 20:54:09 2022 -0700 CHANGELOG #18133 commit 7e8985a723936012392907fc5c6101b0dc04388d Author: Neil Ye Date: Tue Aug 30 11:53:40 2022 +0800 New Resource: `azurerm_cosmosdb_sql_dedicated_gateway` (#18133) commit 108e630aafda8ef366a2daba835eb34abf9f40b4 Author: kt Date: Mon Aug 29 20:51:38 2022 -0700 CHANGELOG #18120 commit cd9bf948d68e9101edc2f451726c708f53867b9a Author: JT <100274846+jiaweitao001@users.noreply.github.com> Date: Tue Aug 30 11:51:06 2022 +0800 `azurerm_stream_analytics_output_cosmosdb` - support for `partition_key` property (#18120) commit f001c8999b4afc78d97c26683c20a6524f5b10ff Author: kt Date: Mon Aug 29 20:50:06 2022 -0700 CHANGELOG #18117 commit bf81809948f81fe61edbde9372662a1bfd377026 Author: JT <100274846+jiaweitao001@users.noreply.github.com> Date: Tue Aug 30 11:49:16 2022 +0800 `azurerm_stream_analytics_output_powerbi` - support for `token_user_principal_name` and `token_user_display_name` properties (#18117) commit 52b53dcea303ca15079e60ded382cc49a0e28fb7 Author: kt Date: Mon Aug 29 20:44:52 2022 -0700 CHANGELOG #18096 commit 1ab58972d7891a5fa098fca0a3026068b67abb9d Author: JT <100274846+jiaweitao001@users.noreply.github.com> Date: Tue Aug 30 11:43:38 2022 +0800 `azurerm_stream_analytics_output_eventhub`, `azurerm_stream_analytics_output_mssql`, `azurerm_stream_analytics_output_servicebus_topic` - support for `authentication_mode` property (#18096) commit 8756a7dcf15912b6ccd9831d829b1fbcd8760d33 Author: magodo Date: Tue Aug 30 11:37:30 2022 +0800 CHANGELOG #16367 commit 274fb16a46d0769d6ff0291c0aa2fa35ca8acd65 Author: kt Date: Mon Aug 29 20:35:41 2022 -0700 CHANGELOG @#17992 commit ae2a339b4962e67fc3828db767041895098b6c73 Author: Tao <104055472+teowa@users.noreply.github.com> Date: Tue Aug 30 11:34:31 2022 +0800 New Data Source: `azurerm_monitor_data_collection_endpoint` (#17992) commit b85c2578af063a6016f9e1d00d4dcfd68bdc6eac Author: Xiaxin <92154856+xiaxyi@users.noreply.github.com> Date: Tue Aug 30 11:34:09 2022 +0800 `azurerm_monitor_diagnostic_setting`: adding support for `category_group` (#16367) `azurerm_monitor_diagnostic_setting`: adding support for `category_group` commit 2c805cf951d7b67e724cf438b18e6b40d22fc15e Author: Xiaxin <92154856+xiaxyi@users.noreply.github.com> Date: Tue Aug 30 11:04:37 2022 +0800 `azurerm_web_pubsub`, `azurerm_web_pubsub_hub` resource: Migrating `id` and `web_pubsub_id` (#17823) commit f1cac0c94ae01ea74ebb1ca1cf38dff536d5152c Author: kt Date: Mon Aug 29 20:03:51 2022 -0700 CHANGELOG #17805 commit 7a8d9d5bab758588997a219591ee7af12e633167 Author: kt Date: Mon Aug 29 20:01:33 2022 -0700 CHANGELOG #17798 commit e22f5e900c70b4aa0a6f05ba69e9919e019a7a61 Author: xuzhang3 <57888764+xuzhang3@users.noreply.github.com> Date: Tue Aug 30 11:00:48 2022 +0800 New Resource: `azurerm_api_management_product_tag` - Support API Management product tag (#17798) Co-authored-by: xuzhang3 commit 1878173d8666cbb0906fb07f42617e51b28957c2 Author: kt Date: Mon Aug 29 19:57:51 2022 -0700 CHANGELOG #17767 commit 85b9d40f53355da837647d0919b220a37530020a Author: xuzhang3 <57888764+xuzhang3@users.noreply.github.com> Date: Tue Aug 30 10:57:08 2022 +0800 Enhance - `azurerm_redis_cache` - Recreate Redis cache when downgrade the SKU (#17767) Co-authored-by: xuzhang3 Co-authored-by: kt commit 68dec4ef7377f209fe960b1402204b783421ce96 Author: kt Date: Mon Aug 29 19:56:13 2022 -0700 CHANGELOG #17744 commit 5a0083e840e72bc2c1ed5a6fadecae488a3c8541 Author: Xiaxin <92154856+xiaxyi@users.noreply.github.com> Date: Tue Aug 30 10:55:45 2022 +0800 new resource: azurerm_search_shared_private_link_service (#17744) commit b2dc9d4418208726121c6bfd976bd5bbd2b2556f Author: kt Date: Mon Aug 29 19:44:34 2022 -0700 CHJANGELOG #17538 commit 1398fdd791ca19dc687ccfb06c571de524765266 Author: Xu Wu Date: Tue Aug 30 10:44:03 2022 +0800 New Resource: `azurerm_automation_connection_type` (#17538) Co-authored-by: xuwu1 Co-authored-by: kt commit 76adfcde77002d7683570e38c46a96d3dd5291eb Author: kt Date: Mon Aug 29 19:34:14 2022 -0700 CHANGELOG #17313 commit 8517a08c4b83279824846f77b0a1547d36147e38 Author: Xu Wu Date: Tue Aug 30 10:32:01 2022 +0800 `policy_remediation_xxx_resource` - support for the `resource_count`, `parallel_deployments` and `failure_percentage` properties (#17313) Co-authored-by: xuwu1 commit fb778e01f950a683d04488852dc2f30503fb0bdc Author: kt Date: Mon Aug 29 19:29:24 2022 -0700 CHANGELOG #15999 commit 0901fb2f2dd57e4aada5f7347f39d680b9ac7062 Author: magodo Date: Tue Aug 30 10:28:44 2022 +0800 New resource: `azurerm_sentinel_alert_rule_nrt` (#15999) commit 8733bfeb2ef70861e4a51d200e1d93ac9b121a7f Author: magodo Date: Tue Aug 30 09:32:22 2022 +0800 Update to include #16907 commit 61db9d4f7a377c359ed63b31c5866b90eebdc0b9 Author: JT <100274846+jiaweitao001@users.noreply.github.com> Date: Tue Aug 30 09:31:12 2022 +0800 New Resource: `azurerm_spring_cloud_connection` and `azurerm_app_service_connection` (#16907) New Resource: `azurerm_spring_cloud_connection` and `azurerm_app_service_connection` commit 04e8fae85dbb8f8512bd0240e45f263844dfc8b2 Author: Jay Thakkar Date: Mon Aug 29 14:51:17 2022 -0700 Doc Fix: Cosmos SQL DB Resource name (#18170) commit 614cf19906185a91997845c1138b17b18f610102 Author: kt Date: Mon Aug 29 12:28:57 2022 -0700 CHANGELOG #15967 commit 09dbd0177aa760680c961daef6bf6e69336aa58d Author: Xiaxin <92154856+xiaxyi@users.noreply.github.com> Date: Tue Aug 30 03:27:15 2022 +0800 `Dependency` New Resource - azurerm_healthcare_medtech_service (#15967) commit 6fb2cc3724157ef58a17f3ca6d36fb06c97d583c Author: Amier Chery <92801461+Amier3@users.noreply.github.com> Date: Mon Aug 29 14:31:37 2022 -0400 Revert "Update feature request template (#18167)" (#18168) This reverts commit bad5e389c322b80d85992457e6140e6a607864a9. commit bad5e389c322b80d85992457e6140e6a607864a9 Author: Amier Chery <92801461+Amier3@users.noreply.github.com> Date: Mon Aug 29 14:29:58 2022 -0400 Update feature request template (#18167) Including a field for ' are you interested in contributing ' commit 8e5864e00ab11dcd3b85113505e2fbe2014d30b7 Author: Matthew Frahry Date: Mon Aug 29 11:12:42 2022 -0700 Update changelog for #18161 commit ade96ede369d7113b63cd6e11c95441d8073ddfd Author: Heng Lu <79895375+ms-henglu@users.noreply.github.com> Date: Tue Aug 30 02:12:05 2022 +0800 `azurerm_spring_cloud_service` - ignore default zero value for `read_timeout_seconds` (#18161) commit 319650596fc58acbeba31570b25e4dd71b9bd230 Author: t3mi Date: Mon Aug 29 20:41:31 2022 +0300 update docs for cdn_frontdoor_(firewall/security)_policy (#18163) commit 925b272980f76279b9b3830c3df8090eb005f661 Author: David Gardiner Date: Mon Aug 29 16:21:01 2022 +0930 Correct resource name references in documentation (#18091) - I assume these were originally copy/pasted from API Management commit ef5eec681003803863d314407932df03407ac0cc Author: Kiran Pradeep Date: Sat Aug 27 00:51:02 2022 +0530 For azurerm_static_site, documentation does not mention identity and principal_id access (#18125) commit a782d6cc7b4b2a26e79854dd224c4139a5aa4148 Author: Tao <104055472+teowa@users.noreply.github.com> Date: Sat Aug 27 03:18:55 2022 +0800 Docs: Fix wrong import command and config in `azurerm_monitor_scheduled_query_rules_alert_v2` (#18136) commit 2b61f737a784ba4e74237855daead2950f6ec527 Author: Frederico Frazão Date: Fri Aug 26 20:18:20 2022 +0100 fix(docs): PostgreSQL flexible server PointInTimeRestore (#18145) commit 9123b62a7d19d50ea38c3be020b9b4e38f37ac83 Author: Matthew Frahry Date: Fri Aug 26 11:05:14 2022 -0700 Update changelog for #18142 commit 256e4f3103da87166c2d7aba81e768d059e93939 Author: Giuseppe Chiesa <68604164+GiuseppeChiesa-TomTom@users.noreply.github.com> Date: Fri Aug 26 20:04:22 2022 +0200 `azurerm_kubernetes_cluster` - `kube_config` is now set when AAD is enabled for a v1.24 cluster (#18142) commit c1a461d425d55674ab0114ae45fab7a0c65444f4 Author: Yogesh Chhetri <36565350+yogeshCt3@users.noreply.github.com> Date: Fri Aug 26 21:41:16 2022 +0530 Removed typo space in README.md hyperlink (#18138) commit 6109fdd95dad02bb7f83dd46a1c10e47e1314f36 Author: Lucas Fernández <64142310+CorrenSoft@users.noreply.github.com> Date: Fri Aug 26 02:20:39 2022 -0300 azurerm_app_configuration: add support for public_network_access (#17549) commit f5f3bb63c48a85aebdf5a4bf30a4605c7fd1a235 Author: JT <100274846+jiaweitao001@users.noreply.github.com> Date: Fri Aug 26 13:05:57 2022 +0800 `HDInsight`: Fix autoscale related failing tests (#17795) commit 99542c6949b7478276acb9b47535ab451ed300b6 Author: magodo Date: Fri Aug 26 11:13:20 2022 +0800 Update for #17840 commit ae65d4181baec8941b64451ef554272737797fbd Author: Zhenhua Hu Date: Fri Aug 26 11:12:37 2022 +0800 New Resource: `azurerm_dashboard_grafana` (#17840) New Resource: `azurerm_dashboard_grafana` (#17840) commit dce4255bb81d572ce8476d37938b304f2775d128 Author: magodo Date: Fri Aug 26 10:06:47 2022 +0800 Update for #17929 commit a6d0883b8c054da130f4fa1659921799e51b47fe Author: Neil Ye Date: Fri Aug 26 10:04:02 2022 +0800 New Resource: `azurerm_log_analytics_query_pack_query` (#17929) New Resource: `azurerm_log_analytics_query_pack_query` (#17929) commit f3feb8150b1c3959ae5777e29264f7695bf382bc Author: kt Date: Thu Aug 25 17:10:02 2022 -0700 v3.20.0 commit af80666f9732c57dc2b55f2687a127f69e815428 Author: Matthew Frahry Date: Thu Aug 25 16:06:26 2022 -0700 Update changelog for #18041 commit f15b9a87e0363b7ae43d6da1a455aaa7b4ec57e4 Author: richardfric <69456996+richardfric@users.noreply.github.com> Date: Fri Aug 26 01:05:56 2022 +0200 `azurerm_mssql_elastic_pool` - list of values for `maintenance_configuration_name` is now correct (#18041) commit 3b924c8a435f306eb7d5d57f552ee8f789b7e00c Author: Matthew Frahry Date: Thu Aug 25 14:39:38 2022 -0700 Update changelog for #18131 commit 56ae5b22089e5f3076871d8794707b05215de08c Author: Matthew Frahry Date: Thu Aug 25 14:38:31 2022 -0700 `data.azurerm_kubernetes_cluster` - `kube_config` is now set when AAD is enabled for a v1.24 cluster (#18131) commit 90cdad708b98345276843a0105c6f9f3c681d547 Author: Tom Bamford Date: Thu Aug 25 14:55:39 2022 +0100 Changelog for #18118 commit c582fb7ebf4d01bc6adeb8920190e75cea2b40e3 Author: Christian Köberl Date: Thu Aug 25 15:48:47 2022 +0200 Add generic OIDC authentication (#18118) * Add generic OIDC authentication Adds a way to provide the OIDC token directly to the provider. This enables to use the provider without tokens/passwords in GitLab CI See: https://docs.gitlab.com/ee/ci/cloud_services/ Closes #16901 * Documentation wording for OIDC authentication * Use EnvDefaultFUnc for single variable Co-authored-by: Tom Bamford commit 6613b0d791ed576c7b6bd7e7529c1b9c8e7d9508 Author: Matthew Frahry Date: Wed Aug 24 16:15:32 2022 -0700 Update changelog for #18106 commit 54e9758ba9873bb7c7ae4bba69069a9469c1ee9a Author: Neil Ye Date: Thu Aug 25 07:14:26 2022 +0800 azurerm_postgresql_flexible_server - update point_in_time_restore_time_in_utc to RFC3339 (#18106) commit dd913a3fa62a4d86cb6d1e4a2880f1a64c4cfa47 Author: kt Date: Wed Aug 24 12:39:43 2022 -0700 azurerm_sql_managed_instance_failover_group in docs (#18111) commit 9fd82e52cbb00b1344f0116303ac80c75abc68df Merge: 65202cebdd 34478164c6 Author: Amier Chery <92801461+Amier3@users.noreply.github.com> Date: Wed Aug 24 15:05:33 2022 -0400 Merge pull request #18081 from samgladstone/patch-1 Add warning that OIDC auth only works in GitHub Actions commit 65202cebddb5c4e771b5bbe6ba880156770c616e Merge: bc60755c46 4de22c51ba Author: Amier Chery <92801461+Amier3@users.noreply.github.com> Date: Wed Aug 24 15:00:50 2022 -0400 Merge pull request #18094 from jayendranarumugam/patch-1 added missing tags property commit bc60755c46c286e286e52a4bd739690c4f6af234 Author: jackofallops <11830746+jackofallops@users.noreply.github.com> Date: Wed Aug 24 17:00:42 2022 +0100 update for #18100 commit 0545d7faf39867783e133d78a779c1533272373d Author: jackofallops <11830746+jackofallops@users.noreply.github.com> Date: Wed Aug 24 16:59:59 2022 +0100 Dependencies: update `go-azure-sdk` to `v0.20220824.1090858` (#18100) commit c65e4c1e71c654af704099ae20d72ef2faf7cb48 Author: stephybun Date: Wed Aug 24 17:13:53 2022 +0200 Update for #18101 commit ab4094c7d23ef1fac4e1e0062d27252679c3e721 Author: stephybun Date: Wed Aug 24 17:12:54 2022 +0200 `consumption` - switch to `hashicorp/go-azure-sdk` (#18101) * use go-azure-sdk for consumption * go mod tidy and vendor * remove setting etag in the data sources commit 4de22c51ba1b84de39ed95b5c9538ac60084fefd Author: Jayendran Arumugam <25414541+jayendranarumugam@users.noreply.github.com> Date: Wed Aug 24 13:10:29 2022 +0530 added missing tags property commit 5e306e12298242cfe5c8f246b0175bc3fb886894 Author: jackofallops <11830746+jackofallops@users.noreply.github.com> Date: Wed Aug 24 06:09:09 2022 +0100 Update for #18070 commit b33b3d3883ba9c6349391fab3080d8f1d2145985 Author: jackofallops <11830746+jackofallops@users.noreply.github.com> Date: Wed Aug 24 05:50:24 2022 +0100 Update for #18074 commit ed9f0d1ae8c3ebc558b31de67464eb1e75d7b2ac Author: stephybun Date: Wed Aug 24 06:48:31 2022 +0200 `azurerm_kubernetes_cluster_node_pool` - nil check first element when expanding upgrade settings (#18074) commit 0c4f8395f8f9e4200798fe6594928cd17f92cea3 Author: Matthew Frahry Date: Tue Aug 23 20:09:37 2022 -0700 Update changelog for #18061 commit 74704906054cd31e844f40f6f3ec8d4ad1a7b283 Author: lonegunmanb Date: Wed Aug 24 11:08:05 2022 +0800 `azurerm_data_factory_dataset_json` - `filename` and `path` in `azure_blob_storage_location` block can now be empty (#18061) Co-authored-by: zjhe commit 2d18c62fe702bfa9eeb890bcbb7c5951ae3fe49f Author: kt Date: Tue Aug 23 08:58:19 2022 -0700 CHANGELOG #17765 commit fea1debe436fe51165da11f7a8f1a11b7e6f275a Author: Neil Ye Date: Tue Aug 23 23:57:49 2022 +0800 New Resource: `azurerm_backup_policy_vm_workload` (#17765) Co-authored-by: neil-yechenwei Co-authored-by: Neil Ye (PACTERA TECHNOLOGIES INC) commit 54e68cf593023bfb0d825776ef53a8d4596573a1 Author: kt Date: Tue Aug 23 08:45:03 2022 -0700 CHANGELOG #17772 commit 6c7868dbd0606310a2c3836270be3c43ac635c7e Author: Tao <104055472+teowa@users.noreply.github.com> Date: Tue Aug 23 23:41:13 2022 +0800 New Resource: `azurerm_monitor_scheduled_query_rules_alert_v2` (#17772) commit 34478164c6002fc0afcf7b785b61122c1688360e Author: Sam Gladstone <42203151+samgladstone@users.noreply.github.com> Date: Tue Aug 23 12:37:51 2022 +0100 Update service_principal_oidc.html.markdown commit 9444b80556a6403fb3568aab76fddf0379b9b119 Author: Sam Gladstone <42203151+samgladstone@users.noreply.github.com> Date: Tue Aug 23 12:21:02 2022 +0100 Add warning that OIDC auth only works in GitHub Actions commit 07b2e25ea187d2bdaf3cd2a96e120e06b5013459 Author: catriona-m <86247157+catriona-m@users.noreply.github.com> Date: Mon Aug 22 23:12:12 2022 +0100 dependencies: update go-azure-sdk to v0.20220819.1134400 (#18046) commit 56357b664fb313199b294a7745898fecccae1377 Author: magodo Date: Tue Aug 23 00:54:34 2022 +0800 Update the document about the import id for `azurerm_servicebus_namespace_network_rule_set` (#18055) commit 9c038ad433272e7dc07337fc197842134d6b0acb Author: kt Date: Mon Aug 22 09:51:10 2022 -0700 cosmosdb - prevent panic (#18070) commit 6be27548882d586b974ff6ee936f5689300b9df5 Author: jackofallops Date: Fri Aug 19 17:22:17 2022 +0100 v3.19.1 commit e413d3bc0361af2589a83fb449dbbec07c39b106 Author: jackofallops <11830746+jackofallops@users.noreply.github.com> Date: Fri Aug 19 17:20:09 2022 +0100 Update for #18048 commit 92ae101c3dff5a6cf03822628749d58ae922bf01 Author: stephybun Date: Fri Aug 19 18:09:32 2022 +0200 parse resource ids insensitively in the read functions (#18048) commit accdeebe6072390c531b88f8e322b80acceecfb8 Author: kt Date: Thu Aug 18 16:16:40 2022 -0700 v3.19.0 commit 60c922e64f636b623813ab09f829b8e0961b3a20 Author: kt Date: Thu Aug 18 16:15:18 2022 -0700 CHANGELOG #17114 commit 2a89d571a482cc60b036ec8824e14292356775ac Author: magodo Date: Fri Aug 19 07:12:42 2022 +0800 `azurerm_cdn_endpoint_custom_domain` - user managed https allows key vault secret (#17114) Co-authored-by: kt commit f1754fe4404db6328745cc12e307b1bce145b34a Author: kt Date: Thu Aug 18 16:08:03 2022 -0700 CHANGELOG #16987 commit f4b8e64972bdfe271bfa8de16ffdf52af4c8cb05 Author: shu-ying789 <96756505+shu-ying789@users.noreply.github.com> Date: Fri Aug 19 07:05:29 2022 +0800 `azurerm_data_factory_data_flow` `azurerm_data_factory_flowlet_data_flow` - `flowlet` (#16987) commit b6458015dfc529079a0d8888bea49c723494d469 Author: Mathieu Ouellet Date: Thu Aug 18 18:39:29 2022 -0400 `d/azurerm_virtual_machine_scale_set`: Add scale set instances details (#14754) commit 3d074ffba504e3f32dd63f6241da01dc9f878fe1 Author: kt Date: Thu Aug 18 15:30:06 2022 -0700 CHANGELOG #18035 commit 565e97a70d1817eb4060df9beff54d096745dd8f Author: jackofallops <11830746+jackofallops@users.noreply.github.com> Date: Thu Aug 18 23:27:47 2022 +0100 App Service: fix content settings and MSI storage access (#18035) commit 219e888c72b95d2adb83e6cbee4da5f82e63efc1 Author: qiqingzhang <46072066+qiqingzhang@users.noreply.github.com> Date: Fri Aug 19 03:28:26 2022 +0800 wait LRO (#17448) Co-authored-by: Heng Lu <79895375+ms-henglu@users.noreply.github.com> Co-authored-by: Heng Lu Co-authored-by: kt commit 58a2c8d3b5b548f97554dde61ccdd8d14cda3732 Author: kt Date: Thu Aug 18 11:47:03 2022 -0700 CHANGELOG #18036 commit 6cb2d226533bd65c5ac988b3c287c4dc16eddf1d Author: Stamatis Katsaounis Date: Thu Aug 18 21:45:30 2022 +0300 Add data sources for every type of private DNS record (#18036) commit a24d7552d59aaf43c418643a7f4b74d1adc22955 Author: kt Date: Thu Aug 18 11:40:04 2022 -0700 CHANGELOG #16758 commit 9116957b51cfe01c06a619752589e8abbb954c54 Author: xuzhang3 <57888764+xuzhang3@users.noreply.github.com> Date: Fri Aug 19 02:39:06 2022 +0800 Enhacne: `azurerm_batch_account ` - storage_account_authentication_mode, storage_account_node_identit, allowed_authentication_modes (#16758) Co-authored-by: xuzhang3 commit 2089f76d33afd4f86eccd848a6161c262b22fe9e Author: lonegunmanb Date: Fri Aug 19 02:24:38 2022 +0800 `azurerm_private_endpoint` Try to add retry on creation (#16315) Co-authored-by: zjhe commit 7f5b1608e519278e65e1a7266b372629a45beff6 Author: kt Date: Thu Aug 18 11:16:34 2022 -0700 CHANGELOG #17954 commit cedfbb946b831ba685dc9936c36e43c4f8eebb32 Author: catriona-m <86247157+catriona-m@users.noreply.github.com> Date: Thu Aug 18 19:16:03 2022 +0100 switch maintenance sdk to use hashicorp/go-azure-sdk (#17954) Co-authored-by: kt commit aad502215f8228dee2fc024a955d9e5c47c19892 Author: Heng Lu <79895375+ms-henglu@users.noreply.github.com> Date: Fri Aug 19 02:15:41 2022 +0800 `azurerm_kubernetes_cluster` - improve docs for `kubelet_identity` (#18027) commit e01497164766fa5883c3c0deb5ac60307bbf68e0 Author: Sadik Tekin Date: Thu Aug 18 16:44:10 2022 +0100 remove resource_discovery_mode attribute (#17008) commit ae07c1fbed928617910b3772af14b38e82f8ac72 Merge: b3dea1fd68 6fb3dcf1ad Author: Amier Chery <92801461+Amier3@users.noreply.github.com> Date: Thu Aug 18 09:33:57 2022 -0400 Merge pull request #17994 from teowa/fix_doc_lb_datasource Docs: Change data source `azurerm_lb`, `azurerm_lb_backend_address_pool` to `Load Balancer` subcategory commit b3dea1fd689d8c7347977e37d0e1fc429f5277c2 Author: jackofallops <11830746+jackofallops@users.noreply.github.com> Date: Thu Aug 18 10:47:55 2022 +0100 Update for #18028 commit 8a05220b99f6421fc9ebef4f54a8394088bb54a6 Author: jackofallops <11830746+jackofallops@users.noreply.github.com> Date: Thu Aug 18 10:46:51 2022 +0100 Data Source: `azurerm_windows_web_app` - add missing schema definition for 'virtual_network_subnet_id' (#18028) commit 17218e98c658d3fea0ab78b1ab37b5f03d3dc2e4 Author: kt Date: Wed Aug 17 20:07:54 2022 -0700 CHANGELOG #17651 commit 3aff64f98e92bb86c14e81944b3949b616d131a4 Author: Zhenhua Hu Date: Thu Aug 18 11:07:06 2022 +0800 `azurerm_application_gateway` - support for the `globalConfiguration` property (#17651) commit 4e52ce365feb318918794c1c9957167257a0e8c8 Author: kt Date: Wed Aug 17 20:03:44 2022 -0700 CHANGELOG #17630 commit cc4ec82ec9ab1b47727918ae9960dbaf4f6c81b7 Author: Heng Lu <79895375+ms-henglu@users.noreply.github.com> Date: Thu Aug 18 11:02:47 2022 +0800 `azurerm_spring_cloud_app` - `public_endpoint_enabled`; `azurerm_spring_cloud_gateway_route_config`- support for the `open_api`;`azurerm_spring_cloud_service` - `log_stream_public_endpoint_enabled``read_timeout_seconds` properties (#17630) commit ecb16d914e3b64fd5e433fc0926a06e1f6e5943d Author: kt Date: Wed Aug 17 19:05:03 2022 -0700 Update CHANGELOG.md commit ae51dc7ee49cab0cc26c412e2751ae54e6313cc6 Author: magodo Date: Thu Aug 18 09:54:28 2022 +0800 Update CHANGELOG to include #17770 commit 75e9a571b48f12df61f558c08e071e77b7a7b294 Author: Xiaxin <92154856+xiaxyi@users.noreply.github.com> Date: Thu Aug 18 09:53:54 2022 +0800 `azurerm_lb_backend_address_pool_address` - support for the `backend_address_ip_configuration_id` property (#17770) `azurerm_lb_backend_address_pool_address` - support for the `backend_address_ip_configuration_id` property commit b709a31f40bdeb762f0bb80e24a4cd1d51ad4215 Author: magodo Date: Thu Aug 18 09:51:27 2022 +0800 Update CHANGELOG to include #17365 commit 27c44ab7ced28f73baca7da18ef102c5ca28fbc3 Author: Neil Ye Date: Thu Aug 18 09:50:30 2022 +0800 `azurerm_log_analytics_workspace` - support for the `cmk_for_query_forced` property (#17365) `azurerm_log_analytics_workspace` - support for the `cmk_for_query_forced` property commit d5556d4fe23a411897eeb5fbcdf0d9066fe70337 Author: magodo Date: Thu Aug 18 09:44:39 2022 +0800 Update CHANGELOG to include #17137 commit cde23f6d3cbe1753003804c6531324044b323e86 Author: Elena Xin <39109137+sinbai@users.noreply.github.com> Date: Thu Aug 18 09:42:04 2022 +0800 `azurerm_key_vault_access_policy` - Data source fix lowercased return values for `(key|secret|certificate)_permissions` for provider v4.0 (#17137) `azurerm_key_vault_access_policy` - Data source fix lowercased return values for `(key|secret|certificate)_permissions` for provider v4.0 commit e5baaa52424175adbc9ad484d0c83f394789aa80 Author: kt Date: Wed Aug 17 11:10:33 2022 -0700 CHANGELOG #18014 commit d1485df3eda79fb0623e898685747cfda9b5372d Author: jackofallops <11830746+jackofallops@users.noreply.github.com> Date: Wed Aug 17 19:04:55 2022 +0100 `azurerm_windows_function_app` and `azurerm_windows_function_app_slot` fix bug in setting value for 'WindowsFxString' (#18014) commit 012e0f943d1cd9c68a19b5b85d8366a9cf7b2f3b Author: Amier Chery <92801461+Amier3@users.noreply.github.com> Date: Wed Aug 17 12:04:53 2022 -0400 Update changelog for #15782 commit 37108b2e10fa99820486f030eed2493935f99787 Merge: 8bff490e2b 3dd65a9110 Author: Amier Chery <92801461+Amier3@users.noreply.github.com> Date: Wed Aug 17 11:38:02 2022 -0400 Merge pull request #18016 from laurilarjo/fix-typo-doc-static-web-app Docs: Fix typo in static site page commit 8bff490e2b7f4c37071e7c94ffafef2e1b490e01 Author: Matthew Frahry Date: Wed Aug 17 08:27:17 2022 -0700 Update changelog for #17986 commit 227128e6819c1505292cfd96df35c1b9b7345de6 Author: Matthew Frahry Date: Wed Aug 17 08:26:32 2022 -0700 `dns` - switch to `go-azure-sdk` (#17986) commit 62919322b1968bf72b4e22fdc248f763a3c328ad Author: jackofallops <11830746+jackofallops@users.noreply.github.com> Date: Wed Aug 17 15:49:53 2022 +0100 Update for #17715 commit 3766ab7f16e70c674b0c937a4198f86863109690 Author: Wodans Son <20408400+WodansSon@users.noreply.github.com> Date: Wed Aug 17 08:48:19 2022 -0600 [New Resources:] `azurerm_cdn_frontdoor_firewall_policy` and `azurerm_cdn_frontdoor_security_policy` (#17715) Co-authored-by: tombuildsstuff commit 8bf12611f1e97eff65fb546b94584908d9b4e2b8 Author: jackofallops <11830746+jackofallops@users.noreply.github.com> Date: Wed Aug 17 11:02:31 2022 +0100 Update for #18015 commit d609d9c8be4cc7a2e3a023383825e7ca70edeb9d Author: jackofallops <11830746+jackofallops@users.noreply.github.com> Date: Wed Aug 17 10:59:54 2022 +0100 Dependencies: update `go-azure-helpers` to `v0.39.1` (#18015) commit 3dd65a9110bc442fa4f4c4194e76dc94e7ec8aa2 Author: Lauri Larjo Date: Wed Aug 17 12:27:44 2022 +0300 Fix typo in doc commit 2eea021bc460507b89d742edfc90b018ae5a20f7 Author: catriona-m <86247157+catriona-m@users.noreply.github.com> Date: Wed Aug 17 10:27:30 2022 +0100 update changelog for #17700 commit 6d54ffa103e27bf680ed984195142c45e307e83e Author: catriona-m <86247157+catriona-m@users.noreply.github.com> Date: Wed Aug 17 10:24:27 2022 +0100 dataprotection - swap to hashicorp/go-azure-sdk (#17700) * use hashicorp/go-azure-sdk for dataprotection * lint * fix ids * resolve conflicts commit d6848b2a037ccc84929c52bae01d069573c27f0e Author: magodo Date: Wed Aug 17 16:58:20 2022 +0800 Update CHANGELOG to include #17757 commit 138bbe0e40540bbbf927b0a11b53ab931dbd5d6e Author: Zhenhua Hu Date: Wed Aug 17 16:56:37 2022 +0800 `azurerm_web_application_firewall_policy` - support for the `excluded_rule_set ` property (#17757) `azurerm_web_application_firewall_policy` - support for the `excluded_rule_set ` property commit cb9a58bc577f2ac763673927db1222ca291c2d11 Author: Matthew Frahry Date: Tue Aug 16 23:28:29 2022 -0700 Update changelog for #13899 commit ff227a9c1e69673e76bd88145846f625b5fdf385 Author: aristosvo <8375124+aristosvo@users.noreply.github.com> Date: Wed Aug 17 08:27:51 2022 +0200 `azurerm_application_gateway`: Support for `components` in `rewrite_rule_set.rewrite_rule.url` (#13899) commit 00bafb888f8f3f5b909b66dfbb75f5dc46638617 Author: kt Date: Tue Aug 16 18:18:58 2022 -0700 CHANGELOG #17756 commit e1ee3e8d1926fec1bb29b4dafa2f396783f36582 Author: Heng Lu <79895375+ms-henglu@users.noreply.github.com> Date: Wed Aug 17 09:17:59 2022 +0800 `azurerm_data_factory_integration_runtime_azure_ssis` - support for the `express_vnet_injection` property (#17756) commit b6b32e13f0848509a963743c6a718dd718506540 Author: kt Date: Tue Aug 16 18:14:54 2022 -0700 CHANGELOG #17416 commit 6c7917a248f473c0f2731f3b049cf0021202a1ee Author: dkuzmenok <103177770+dkuzmenok@users.noreply.github.com> Date: Wed Aug 17 03:14:05 2022 +0200 `azurerm_batch_pool` - Added support for `identity_reference` into `container_registries` (#17416) Co-authored-by: Denis Kuzmenok commit a7aa576180981b71e9f22995144f470203d92563 Author: kt Date: Tue Aug 16 17:52:48 2022 -0700 CHANGELOG #17853 commit 366290922697b7908b400a4ecab8363cddd005f8 Author: magodo Date: Wed Aug 17 08:52:06 2022 +0800 `azurerm_active_directory_domain_service` - Support for `kerberos_armoring_enabled` and `kerberos_rc4_encryption_enabled` (#17853) commit 817750521ff19e03687988602859fcf82d88bba2 Merge: dfe591d2d3 2f31161872 Author: Amier Chery <92801461+Amier3@users.noreply.github.com> Date: Tue Aug 16 18:32:25 2022 -0400 Merge pull request #15782 from jblunck/fix-typed-entities azure_storage_table_entity: support propoerty data types commit dfe591d2d3283f549eda9da900cbb25b9f299c87 Author: kt Date: Tue Aug 16 09:17:23 2022 -0700 CHANGELOG #17635 commit 34e666649ff2447c0e416a89e4fd80d81f36cf6c Author: Xiaxin <92154856+xiaxyi@users.noreply.github.com> Date: Wed Aug 17 00:16:50 2022 +0800 new resource: azurerm_eventhub_namespace_schema_group (#17635) commit 1321418eaa8a8d9b27a1f5e6f734d908f10c1d0c Author: kt Date: Mon Aug 15 23:17:04 2022 -0700 CHANGELOG #17454 commit 0673a30b6c7c7a8f10b18da609597e5dcf30121f Author: Xu Wu Date: Tue Aug 16 14:15:43 2022 +0800 `azurerm_automation_account` - support for the `encryption` and `local_authentication_enabled` property (#17454) Co-authored-by: xuwu1 commit 9d74747194ae0c4328a9fc73cb7540392777a927 Author: Heng Lu <79895375+ms-henglu@users.noreply.github.com> Date: Tue Aug 16 14:10:45 2022 +0800 fix spring cloud enterprise tier config server failure (#17856) commit 83e1a27287b44cbebfa82fc9a82f44e09fb6c073 Author: kt Date: Mon Aug 15 22:40:23 2022 -0700 CHANGELOG #17768 commit bb9437b813a3413bc48ba0d8e8ed01457dad507c Author: Yichun Ma Date: Tue Aug 16 13:39:47 2022 +0800 `azurerm_shared_image_version` - support for `blob_uri`, `storage_account_id` (#17768) commit 4c724ee60cde80dc970eb161477fb5f22931af4b Author: Xiaxin <92154856+xiaxyi@users.noreply.github.com> Date: Tue Aug 16 13:39:13 2022 +0800 Migrating servicebus auth rule ID (#17824) commit 266953e1003f92de9a5e207c13581f46a58a3352 Author: kt Date: Mon Aug 15 22:38:33 2022 -0700 CHANGELOG #17842 commit 5aecd3afd52166acb540c4c008c8fd20baf6cfb8 Author: Xu Wu Date: Tue Aug 16 13:37:50 2022 +0800 `firewall_policy_resource` - support for the `private_ranges` and `allow_sql_redirect` properties (#17842) Co-authored-by: xuwu1 Co-authored-by: kt commit 5e559680270f73469934804db0a731d3820fb3ef Author: Anton <44246099+antonblr@users.noreply.github.com> Date: Mon Aug 15 22:34:49 2022 -0700 azurerm_postgresql_server - Fix legacy database ids handling (#17871) commit e29a4428fc569d70b496e12a8b3baf869a7c9a26 Author: Austin Ek Date: Tue Aug 16 00:27:29 2022 -0500 Fix outputs for `azurerm_windows_function_app` and `azurerm_linux_function_app`, both resource and data source (#17361) commit 2c5806c9389e2e977ec3e18bfd36b245351da9fb Author: kt Date: Mon Aug 15 22:25:40 2022 -0700 CHANGELOG #17116 commit bb605de6728fe865e7f2f93da62049f6f6c60847 Author: Marc Sensenich Date: Tue Aug 16 01:24:48 2022 -0400 `azurerm_storage_account` support for setting defaultToOAuthAuthentication (#17116) commit 7e5b911b4147945b562bea8d84ef285e5b36aa83 Author: Klaas Demter Date: Tue Aug 16 07:21:40 2022 +0200 Update azurerm_network_interface to correctly reflect what dynamic means in azure context (#15264) Co-authored-by: kt commit d2e7b468090e282dffb1a264d58164dccf39f865 Author: kt Date: Mon Aug 15 22:20:05 2022 -0700 CHANGELOG #17250 commit d932f7ca47bfffae7c544ef6c95b914be2df4d2c Author: Serge Date: Tue Aug 16 08:19:12 2022 +0300 resource `azurerm_shared_image` - add architecture option. (#17250) commit 589928fcb007321a5af3b549b0603963dc670ed4 Author: kt Date: Mon Aug 15 22:17:24 2022 -0700 CHANGELOG #17226 commit 5e8d5ea25c7087020f30954c18ab5a421fe4a891 Author: Allen Humphreys Date: Tue Aug 16 01:16:02 2022 -0400 Allow Delete eviction policy on Azure VMs (#17226) commit c3dd75f7db41ba0eb62d8aff742d40b183d978c8 Author: kt Date: Mon Aug 15 22:04:40 2022 -0700 CHANGELOG #16208 commit 83706a505470c655b227052ee318470c717a8758 Author: magodo Date: Tue Aug 16 13:03:48 2022 +0800 `data.azurerm_management_group` - Add new attributes: `management_group_ids`, `all_management_group_ids` and `all_subscription_ids` (#16208) commit 0a805a4ca85fc9a9027227d57460ecedbfc53c8c Author: magodo Date: Tue Aug 16 12:59:02 2022 +0800 `azurerm_key_vault_{key,secret,certificate}`: Resource/DataSource increase read timeout from 5min to 30min (#17782) commit b401b4447d2f218e88f6f2917977afd9fdab10f1 Author: magodo Date: Tue Aug 16 11:57:17 2022 +0800 `azurerm_storage_management_policy` - Relieve the rule name validation (#17973) commit 56e0d593300fd0a8bc6327a57d7cecd2dfa64b64 Author: kt Date: Mon Aug 15 20:56:49 2022 -0700 CHANGELOG #17934 commit 3cb003ad218a4cde468856e7cb99fe149e02dee0 Author: Xu Wu Date: Tue Aug 16 11:56:17 2022 +0800 `azurerm_automation_account` - support for the `private_endpoint_connection` property (#17934) Co-authored-by: xuwu1 commit f8595297de843a1a4f81f997305583f4ed94560a Author: Michael Madeja Date: Mon Aug 15 22:55:21 2022 -0500 azurerm_key_vault_access_policy - Update KeyVault Access Policy Key Permissions with new parameters (#17895) commit 71376237966d063d0d55a7b063c594b943416a1e Author: Michael-Wearne <107827478+Michael-Wearne@users.noreply.github.com> Date: Tue Aug 16 13:42:36 2022 +1000 MSSQL size increase to 16384 (#17712) commit 87b29c19e229be91920f2feb4bf87efbccc70dcb Author: Andrei Mahalean Date: Tue Aug 16 15:42:02 2022 +1200 azurerm_application_gateway - Mark probe.match.body as not required (#17696) Co-authored-by: kt commit 714d2ebccfdd03238e1d8fdb81aaa49b01077605 Author: kt Date: Mon Aug 15 20:29:04 2022 -0700 CHANGELOG #16595 commit 57bdd873e2acc53a4a506a1db8a32e30386fae65 Author: Elena Xin <39109137+sinbai@users.noreply.github.com> Date: Tue Aug 16 11:28:18 2022 +0800 `azurerm_mssql_server` - Fix `azurerm_mssql_server` automatically sets `minimum_tls_version` even if not provided issue (#16595) commit 0357a5709aa5a18afbcb37d2c263acbeb2216a36 Author: jackofallops <11830746+jackofallops@users.noreply.github.com> Date: Mon Aug 15 15:06:58 2022 +0100 update for #17998 commit 44ea89c525cb1f9073f0319d4a88cbe8e6ce51a0 Author: jackofallops <11830746+jackofallops@users.noreply.github.com> Date: Mon Aug 15 15:06:20 2022 +0100 Dependencies: bump `go-azure-sdk` to `v0.20220815.1092453` (#17998) commit 9073e1fcc6bfabc65cf93f83737b81445a7caa99 Author: Tao <104055472+teowa@users.noreply.github.com> Date: Mon Aug 15 17:45:02 2022 +0800 Docs: fix diagnostic_categories typo (#17995) commit 3665a26e30bfe35fefc3b1c0854ccd3fc36a2b28 Author: jackofallops <11830746+jackofallops@users.noreply.github.com> Date: Mon Aug 15 09:47:08 2022 +0100 Updated for #17996 commit baebfe5840a0df400e0defd9b004f846e13d92dc Author: jackofallops <11830746+jackofallops@users.noreply.github.com> Date: Mon Aug 15 09:46:06 2022 +0100 Dependencies: bump `go-azure-helpers` to `v0.39.0` (#17996) commit 6fb3dcf1ad441a7e924ba8dec44d079a25daecb7 Author: Tao <104055472+teowa@users.noreply.github.com> Date: Mon Aug 15 14:45:49 2022 +0800 Docs: move lb datasource to 'Load Balancer' subcategory commit df4bd62ea39ca2a3afdb31a0313b438891125441 Author: jackofallops <11830746+jackofallops@users.noreply.github.com> Date: Mon Aug 15 07:41:35 2022 +0100 remove duplicate yaml section created by merge to main (#17993) commit 1a225ae7a531884d05b8b7ed0cbac66d0abf863e Author: jackofallops <11830746+jackofallops@users.noreply.github.com> Date: Mon Aug 15 07:25:51 2022 +0100 GHA: add explicit workflow permissions (#17966) commit 773c3e9b79384174519f02a3edd18b6c9174d2cb Author: Matthew Frahry Date: Fri Aug 12 17:02:50 2022 -0700 Updating changelog for #17616 commit fe8d1f63ef2d2d77600058cf3afacef78d4f4b2a Author: Tom Harvey Date: Sat Aug 13 02:01:11 2022 +0200 dedicated hosts: refactoring to use `hashicorp/go-azure-sdk` (#17616) commit bfff31e78123fa755818326414551e6b64f2acae Author: catriona-m <86247157+catriona-m@users.noreply.github.com> Date: Fri Aug 12 18:18:36 2022 +0100 gha - allow waiting-response to be added/removed from forked repo prs (#17985) commit e4b4c025d455afa6245d567e51b9618f3e1e23a5 Author: kt Date: Fri Aug 12 10:16:03 2022 -0700 CHANGELOG #17477 commit fc8ea921a04ad9e803d657d0c0290445989406a8 Author: Stamatis Katsaounis Date: Fri Aug 12 20:10:14 2022 +0300 Add data sources for every type of public DNS record (#17477) * Add data sources for every type of public DNS record * Fix tests * Fix Azure tests * Update docs as per review * Update timeouts url commit c0ad7835c4a70e70410511f295767b343e90cb73 Author: stephybun Date: Fri Aug 12 19:09:01 2022 +0200 `mariadb` - switch to `go-azure-sdk` (#17939) * rebase * remove unused parse and validation functions * vendor * bump server create timeout to 90 minutes commit baedea9c7bdaa2218428aba615c8ee6211da5ea3 Author: stephybun Date: Fri Aug 12 19:08:46 2022 +0200 swap to go-azure-sdk (#17984) commit b5a1ddd081f53ddc643f859c1f155bf9651dde2a Author: Lars Maes Date: Fri Aug 12 18:38:20 2022 +0200 Revert "Update naming validation to allow length to be 1 - 128 (#17965)" (#17977) commit b45ebe10afbf222278e1868f880017389f63e236 Author: Paddy Morgan Date: Fri Aug 12 17:32:43 2022 +0100 Fix grammar for `waf_configuration.enabled` (#17978) commit 101bcfe9744c6af4de4853215ab8cfe187856552 Author: Zhenhua Hu Date: Fri Aug 12 13:04:18 2022 +0800 Add example for Private Link Scope (#17873) commit 563fc390737d66833de2e15e1d860015b7f80de7 Author: kt Date: Thu Aug 11 20:38:48 2022 -0700 CHANGELOG ##17552 commit 6cedf008c4a64a0aa6ec3f06dbcc98da176e1679 Author: Elena Xin <39109137+sinbai@users.noreply.github.com> Date: Fri Aug 12 11:38:04 2022 +0800 azurerm_key_vault : Support public_network_access_enabled proptery for resource azurerm_key_vault (#17552) The purpose of this PR: Support public_network_access_enabled property for azurerm_key_vault and data.azurerm_key_vault. Delete func enableSoftDelete as it is unused. Fix issue #17533. commit 5c3d3c71171f6de593a6363447fc08265ba36e23 Author: Thomas Meckel <14177833+tmeckel@users.noreply.github.com> Date: Fri Aug 12 05:19:54 2022 +0200 bugfix: azurerm_application_gateway: unable to create private DNS record out of frontend_ip_configuration[*].private_ip_address (#17632) Co-authored-by: Thomas Meckel commit d9c31a83f835c08ce90ceab23b29830bf3bdda2f Author: kt Date: Thu Aug 11 20:13:43 2022 -0700 CHANGELOG #17766 commit 5ed7d81432c5204c17ab3704aca988a8f531e4e2 Author: Yichun Ma Date: Fri Aug 12 11:12:44 2022 +0800 `d\images`: Use fixed id (#17766) commit fa545a57af0b7fa5f61338b8a1864cc04877798a Author: kt Date: Thu Aug 11 20:06:10 2022 -0700 CHANGELOG #17790 commit d5cc32e1fff0a87ef5904979729cf06ff4311f1e Author: richardfric <69456996+richardfric@users.noreply.github.com> Date: Fri Aug 12 05:05:25 2022 +0200 mssql_elastic_pool - add support for maintenance_configuration_name (#17790) commit e20efa892c469db16e10b20f3711237e97f32c45 Author: Tao <104055472+teowa@users.noreply.github.com> Date: Fri Aug 12 10:46:51 2022 +0800 fix KeyVault test: `TestAccKeyVault_softDeleteRecoveryDisabled` (#17878) commit 979a8ee906f3e060bfbbdd804de1e04bfcca8883 Author: kt Date: Thu Aug 11 19:42:46 2022 -0700 CHANGELOG #17904 commit 2e9832d54b88042317430c6f2449dadd1bb4e6b0 Author: JT <100274846+jiaweitao001@users.noreply.github.com> Date: Fri Aug 12 10:41:57 2022 +0800 `data_protection_backup_policy_postgresql_resource`: fix provider crash if given an empty criteria block (#17904) commit 4516da73d459060a9a2d138b998b5c23a09e5d4d Author: Yichun Ma Date: Fri Aug 12 10:38:31 2022 +0800 `r\virtual_machine_extension` `r\virtual_machine_scale_set_extension`: Fix validation of `name` (#17941) commit dfd483efc1716d7fb2b37d7913bff5937e54185a Author: Dave Cheney Date: Fri Aug 12 12:37:41 2022 +1000 internal/services/cognitive: add kind = "OpenAI" (#17959) commit 300a4f41a3297e4f37fffb7564e0301f82366373 Author: JT <100274846+jiaweitao001@users.noreply.github.com> Date: Fri Aug 12 10:36:30 2022 +0800 `service_fabric_mananged_cluster_resource`: fix authentication block (#17960) commit 9e06eb4560ba0de21aeb2e87d25974a98d0ff861 Author: Tao <104055472+teowa@users.noreply.github.com> Date: Fri Aug 12 10:33:00 2022 +0800 Fix Import As Exists Error Message of`azurerm_monitor_diagnostic_setting` (#17963) commit 307a68a330a67f977b3f89a7fb14abdeda61aced Author: kt Date: Thu Aug 11 19:30:16 2022 -0700 CHANGELOG #17964 commit 2b01b08b2218509a6a6894e3d17e1e59dd997ad2 Author: Zhenhua Hu Date: Fri Aug 12 10:28:26 2022 +0800 azurerm_disk_encryption_set: fix creation issue when disk encryption set and key vault in different subscriptions (#17964) commit 796f2ec98c4aec30c9acf4eb882ec312d7e1985f Author: shu-ying789 <96756505+shu-ying789@users.noreply.github.com> Date: Fri Aug 12 10:01:13 2022 +0800 `cdn` `iotcentral` `network` - `documents example improvement` (#17447) Co-authored-by: kt commit 36f2095857e8052a2db0ef006822694a9b65042b Author: Aidan Feldman Date: Thu Aug 11 22:01:04 2022 -0400 clarify how to associate an App Service Environment v3 with a Service Plan (#17694) commit f3429b2c1a0b0cd24da66a82a1d96eab7b7812a3 Author: Alpha Date: Fri Aug 12 10:00:19 2022 +0800 feat: update the Linux /window function app at v3 provider for doc and testcase (#16609) commit dc8900926787e6aaf8ae3e6ff22b7263bca7f464 Author: cryptozero <32773449+cryptozero@users.noreply.github.com> Date: Fri Aug 12 03:52:56 2022 +0200 Add azurerm_subnet_network_security_group_association to associate we… (#17917) commit 535814348163cf15f88fa70c2570f15bde092c2b Author: kt Date: Thu Aug 11 18:13:59 2022 -0700 v3.18.0 commit 92281d90f8d2abc1164ace0dfc8ede9357f4a234 Author: kt Date: Thu Aug 11 08:00:29 2022 -0700 azurerm_cognitive_account - update docs wrt bing search types (#17958) commit e31b6febe9c5cc7d37dc5ae93b77ee49a52fdf7c Author: Lars Maes Date: Thu Aug 11 16:26:45 2022 +0200 Update naming validation to allow length to be 1 - 128 (#17965) * Update naming validation to allow length to be 1 - 128 See: https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/resource-name-rules#microsoftauthorization length of a definitionname is 1 - 128 and not 3 - 24 * update comment about name length commit 112aa158aefdb8a1da6a9829bf41416bb0730ea8 Author: Tom Harvey Date: Thu Aug 11 13:01:29 2022 +0200 updating to include #17905 commit 1c384a8df064e4272e2a9c0041a064affa0e32ca Merge: 94044ebe6e 5dbde1463d Author: Tom Harvey Date: Thu Aug 11 13:00:56 2022 +0200 Merge pull request #17905 from hashicorp/dependencies/go-azure-sdk dependencies: updating to `v0.20220805.1100614` of `github.com/hashicorp/go-azure-sdk` commit 5dbde1463d6bc4d79204beec53702b124a94f749 Author: tombuildsstuff Date: Thu Aug 11 11:54:01 2022 +0200 depednencies: updating to `v0.20220809.1122626` of `github.com/hashicorp/go-azure-sdk` commit 1394ae31dbde262a61c92653c3519b13e1949561 Author: tombuildsstuff Date: Fri Aug 5 12:23:16 2022 +0200 dependencies: updating to `v0.20220805.1100614` of `github.com/hashicorp/go-azure-sdk` commit 94044ebe6e195dc8474aa4cb32d40b5beb5b2a04 Author: Tom Harvey Date: Thu Aug 11 06:14:08 2022 +0200 updating to include #17523 commit b587334851cd7cf3e277ee6481ea6a63a8f94874 Merge: f39b04a047 f59c07edbc Author: Tom Harvey Date: Thu Aug 11 06:13:45 2022 +0200 Merge pull request #17523 from magodo/update_storage_api_to_2021_09_01 Update storage api to 2021-09-01 commit f39b04a04703160467220f0d5d8930f23d61d4e7 Author: Yun Liu Date: Wed Aug 10 23:14:37 2022 +0800 Update document for property `engine` in `azurerm_kusto_cluster` (#17695) Co-authored-by: kt commit b46896ea7818a08f63e4fb8fb8e5017be84376f5 Author: catriona-m <86247157+catriona-m@users.noreply.github.com> Date: Wed Aug 10 16:09:14 2022 +0100 gha - fix waiting-response label (#17952) commit f0e323747704f17458be3a57279c52407bd33603 Author: jackofallops <11830746+jackofallops@users.noreply.github.com> Date: Wed Aug 10 14:40:22 2022 +0100 Update for #16299 commit c7bb7bea30db8ae3647ceaf4cb9ae343d9c4d235 Author: Xiaxin <92154856+xiaxyi@users.noreply.github.com> Date: Wed Aug 10 21:39:15 2022 +0800 DataSource: `azurerm_blueprint_definition` - Fix `version` property output (#16299) commit 060a06146719c5c74f1400e9d2bca0a7e6023731 Author: kt Date: Tue Aug 9 22:21:01 2022 -0700 make terrafmt (#17947) commit eda7d25f66d0af540d482d0632070925c2ab2d93 Author: kt Date: Tue Aug 9 22:04:47 2022 -0700 remove make tools from some actions (#17946) commit 620839508fa6f8a0e46c6129b94b64a42aa00b55 Author: kt Date: Tue Aug 9 09:27:43 2022 -0700 CHANGELOG #17101 commit 099ad51a0540863ef1fcf526f933d2cc757ea126 Author: Xiaxin <92154856+xiaxyi@users.noreply.github.com> Date: Wed Aug 10 00:25:50 2022 +0800 `azurerm_servicebus_subscription`: support client affine property, `azurerm_servicebus_subscription_rule`: add property `sql_filter_compatibility_level` (#17101) commit 57e33be1641918733d902c0d5d8e1c0cccf05690 Author: kt Date: Tue Aug 9 09:15:05 2022 -0700 CHANGELOG #17338 commit ebd138d57949f8bcc25b025c725fd87afb902100 Author: xuzhang3 <57888764+xuzhang3@users.noreply.github.com> Date: Wed Aug 10 00:14:29 2022 +0800 [azurerm_express_route_circuit_peering]- enhance - support for ipv4_enabled gateway_manager_etag (#17338) Co-authored-by: xuzhang3 commit 2f31161872cc124c591ca17240d4111262616be2 Author: Jan Blunck Date: Fri Mar 11 08:30:25 2022 +0100 Update internal/services/storage/storage_table_entity_resource_test.go Run terrafmt commit 2dfd38a995eda5487b2ab8a9ebe5730bd46f8736 Author: kt Date: Thu Mar 10 11:57:57 2022 -0800 Update internal/services/storage/storage_table_entity_resource_test.go commit 8ec0cd1facda8a47d3aff119d1db9ec1d91f880c Author: Jan Blunck Date: Thu Mar 10 08:55:13 2022 +0100 azure_storage_table_entity: support propoerty data types This change makes flattenEntity parse OData Data Types and persist them in the Terraform state. Fixes #5286 #12337 commit dc94da0fce0adae91132555915bb401630043fd3 Author: kt Date: Tue Aug 9 07:37:28 2022 -0700 CHANGELOG #15783 commit 9a3f3ccb8eb94c7a96fd1532f1b5161763cb8c0c Author: Yichun Ma Date: Tue Aug 9 22:36:43 2022 +0800 `r\site_recovery_replicated_vm`: Add support for `target_disk_encryption` (#15783) commit 04deb754a95542d1e086ffa1b4a9715b62539f8e Author: kt Date: Tue Aug 9 07:14:15 2022 -0700 Update guide-opening-a-pr.md commit 1efe139c267dcbe508d86fb50322c002a367d396 Author: kt Date: Tue Aug 9 06:48:52 2022 -0700 CHANGELOG #17684 commit 254a50b44854eca4f79490ce293d810374e6bbf3 Author: Tao <104055472+teowa@users.noreply.github.com> Date: Tue Aug 9 21:46:21 2022 +0800 New Resouce: `azurerm_monitor_data_collection_endpoint` (#17684) commit b001430c6ec4c862a17a986b0df0c236dd81216d Author: catriona-m <86247157+catriona-m@users.noreply.github.com> Date: Tue Aug 9 13:53:53 2022 +0100 update changelog for #17880 commit 90265869f5daed14532f38b3e3f19b2c5876dccf Author: JT <100274846+jiaweitao001@users.noreply.github.com> Date: Tue Aug 9 20:47:43 2022 +0800 backup_policy_vm_resource: fix validation issue when frequency is set to Hourly (#17880) commit 0de1c69190e0c7517bcde9a06844761bcf44f1f2 Author: Heng Lu <79895375+ms-henglu@users.noreply.github.com> Date: Tue Aug 9 20:26:42 2022 +0800 add note for spring cloud enterprise sku (#17920) * add note for spring cloud enterprise sku * update notes commit 816e1ae1e78819e5b8489618597483cf1030513d Author: Felix Mönckemeyer Date: Tue Aug 9 14:11:44 2022 +0200 Fix function app examples (#17908) * fix: primary_access_key in function app * fix: linux function app example * fix: formatiing commit f0494ed28a8795628cf1cc7be11de2bfc254c49d Author: Yun Liu Date: Tue Aug 9 20:07:25 2022 +0800 Update doc and deprecated warning in `azurerm_security_center_server_vulnerability_assessment` with correct resource name (#17874) * update doc with correct resource name * Update azurerm_security_center_server_vulnerability_assessment.html.markdown Co-authored-by: catriona-m <86247157+catriona-m@users.noreply.github.com> commit f670b59b92a3be68ce4fc3973ab5cdd8fa1fb9c5 Merge: 002d245f6b d589d08c6e Author: Tom Harvey Date: Tue Aug 9 10:55:10 2022 +0200 Merge pull request #17932 from teowa/fix_doc_monitor_sqra_import Fix doc of `mointor_schduled_query_rule_alert`: import command case sensitivity commit d589d08c6e0c1e81dd78f432fe720f6b0656ed35 Author: Tao <104055472+teowa@users.noreply.github.com> Date: Tue Aug 9 15:58:11 2022 +0800 fix doc of schduled query rule alert: import command case sensitivity commit 002d245f6b8e7ddbc9b87cce01fccb2910d695c2 Author: jackofallops <11830746+jackofallops@users.noreply.github.com> Date: Tue Aug 9 08:27:00 2022 +0100 Update for #17464 commit d0269ae463502e3c097c42ddc95429262d182eb7 Author: Wodans Son <20408400+WodansSon@users.noreply.github.com> Date: Tue Aug 9 01:22:57 2022 -0600 `azurerm_subnet` - deprecate old enforce fields in favour of the new enable fields (#17464) Co-authored-by: jackofallops <11830746+jackofallops@users.noreply.github.com> commit aa684885b6f271a15c3d401e34f7308221ca8b8e Author: Alexander Date: Mon Aug 8 17:37:25 2022 +0200 #17425 — use dot operator for `principal_id`. (#17923) Co-authored-by: Alexander Skwar commit 095faad37f77436de1fd857033de6cf23c951ba5 Author: catriona-m <86247157+catriona-m@users.noreply.github.com> Date: Mon Aug 8 16:36:51 2022 +0100 gha -add check for Get in Delete func for typed resources (#17882) commit 10a2ed50f79f1789320e76b775f38abd23d2c86b Merge: 7b4070bf30 ba74ab5bf0 Author: Tom Harvey Date: Mon Aug 8 07:11:13 2022 +0200 Merge pull request #17889 from mikemadeja/main Fix default SSL settings for postgresql_server_resource commit ba74ab5bf0a215a37bf37c87253c002e52bacb90 Author: Mike Madeja Date: Fri Aug 5 11:15:37 2022 -0500 updated markdown for postresql_server commit a761b593ab6a6215e23d8979aacf43b4ca2ba403 Merge: 6c11a26617 bff3ac87e8 Author: Mike Madeja Date: Fri Aug 5 11:13:40 2022 -0500 Merge branch 'main' of https://github.com/mikemadeja/terraform-provider-azurerm commit 6c11a2661722f2ce3b7e7bf92b6865f790df6d6d Author: Mike Madeja Date: Fri Aug 5 11:13:34 2022 -0500 reverted to use SSL 1.2 commit bff3ac87e88a5fa5ee123ba077f36e0875e485c6 Author: Michael Madeja Date: Fri Aug 5 08:55:42 2022 -0500 Update website/docs/r/postgresql_server.html.markdown Co-authored-by: Tom Harvey commit 7b4070bf3007a0f4f1db127dc37d73971c97b567 Author: Thomas Date: Fri Aug 5 15:31:20 2022 +0200 fix: typo in Azure Orbital service delegation name (#17896) * fix: typo in Azure Orbital service delegation name * chore: updating subnet documentation Co-authored-by: Thomas MICHEL commit c09176dbb29ab5fc5c79a546a6e35687177b98fa Author: themadsicilian <175916+themadsicilian@users.noreply.github.com> Date: Fri Aug 5 05:36:01 2022 -0500 Corrected role assignment example usage (#17894) commit 5bbf4f60cf20f4da53b6a9f69fe5b66b51d94bff Author: Chris Zembower Date: Fri Aug 5 06:17:25 2022 -0400 typos, note regarding lack of MSI support in vnet (#17888) commit 306b5cb3a14a69d456cc585acbaab6876b359852 Author: Tao <104055472+teowa@users.noreply.github.com> Date: Fri Aug 5 18:03:33 2022 +0800 fix doc of schduled query rule: add `tags` (#17901) commit 0527bd9e07865577b0a340b31d0d3d20aaa6f066 Merge: d7b049fd0c cd80664f81 Author: Tom Harvey Date: Fri Aug 5 12:01:42 2022 +0200 Merge pull request #17898 from hashicorp/f/go-1.18.5 build: using Go 1.18.5 commit cd80664f81f6773a64b61b56dec96c489f1451b8 Author: tombuildsstuff Date: Fri Aug 5 09:37:21 2022 +0200 build: using Go 1.18.5 commit d7b049fd0ca4d5c065c806c76f0ce9d9b500e671 Author: kt Date: Thu Aug 4 19:50:03 2022 -0700 v3.17.0 commit 04754cf265a18cbffe1a594c19b7cc2137b8f502 Author: Yichun Ma Date: Fri Aug 5 10:46:30 2022 +0800 `d\shared_image_version`: Fix paging (#17822) commit a8f0ebbc71c8e8f7cf75c09c4d82d58e86ac4763 Author: kt Date: Thu Aug 4 12:39:54 2022 -0700 CHANGELOG #17887 commit c999570f26bb175e4234ac1913d0f081dac5dc25 Author: jackofallops <11830746+jackofallops@users.noreply.github.com> Date: Thu Aug 4 20:39:18 2022 +0100 `azurerm_api_management` - update `sku_name` validation to accept new Premium SKUs (#17887) commit 074285a77dd58285dc4e76c8ead86fb572f7b951 Author: kt Date: Thu Aug 4 11:46:34 2022 -0700 CHANGELOG #17194 commit 9b21c7ef99d1b70e6d4028a9cd7075ed426f244a Author: Mike Madeja Date: Thu Aug 4 11:55:53 2022 -0500 updated TLS commit de274a56b65350ed53927ccdefa8dc7f2918c473 Author: Mike Madeja Date: Thu Aug 4 11:23:02 2022 -0500 updated markdown for PostgreSQL commit ca8db0c146f37a69f94660a5fe090893edea31ab Author: Mike Madeja Date: Thu Aug 4 11:12:47 2022 -0500 changed setting to optional commit 42d93255cabdd1703c83ce99c848b563a1d99ed6 Merge: 2545a30dae cbe33c2a79 Author: Michael Madeja Date: Thu Aug 4 11:07:35 2022 -0500 Merge branch 'hashicorp:main' into main commit cbe33c2a792d33e48c222493622709eb2fb8cb9c Author: magodo Date: Thu Aug 4 15:04:49 2022 +0800 Update to include #17194 commit fb2102850ebf927c3fbbfaecb256f097e254f9f2 Author: Xiaxin <92154856+xiaxyi@users.noreply.github.com> Date: Thu Aug 4 15:02:24 2022 +0800 `azurerm_eventhub_namespace`: support latest released properties:`local_authentication_enabled`,`public_network_access_enabled`,`minimum_tls_version` (#17194) 1. update eventhub namespace SDK from 2021-01-01-preview to stable 2021-11-01 2. Add SAS Auth switch for eventhub namespace commit d1fe8d1efbc9a57ded8f50bdc05f41e32591fd26 Author: catriona-m <86247157+catriona-m@users.noreply.github.com> Date: Wed Aug 3 23:57:46 2022 +0100 gha - fix and improvements to waiting-response (#17870) commit d1c989b6aefb84a5f264ac7555e3cc6a1c1235e2 Author: Heng Lu <79895375+ms-henglu@users.noreply.github.com> Date: Wed Aug 3 20:24:56 2022 +0800 `azurerm_kubernetes_cluster` - fix failed tests (#17861) commit d3fcfc296fa098b8f46b50793df711e44d0dd0e4 Author: Tao <104055472+teowa@users.noreply.github.com> Date: Wed Aug 3 20:21:08 2022 +0800 fix doc of data collection rule (#17857) commit b4f0888a820e7e57b742f58c74da645eebb4c07c Author: Tom Harvey Date: Wed Aug 3 12:33:32 2022 +0200 updating to include #17854 commit c536f8be27b5577aa879ff0cacae0053ac49da30 Merge: 4620cb506b 52abc64532 Author: Tom Harvey Date: Wed Aug 3 12:33:11 2022 +0200 Merge pull request #17854 from jiaweitao001/orbital `Network`: Add support for `orbitalGateway` commit 52abc6453201a89512accb5fcfd50cfa17861d4c Merge: 856b397e89 4620cb506b Author: JT <100274846+jiaweitao001@users.noreply.github.com> Date: Wed Aug 3 11:05:43 2022 +0800 Merge branch 'main' into orbital commit 856b397e89c671df57726188fb50fadc67ddb414 Author: Jiawei Tao Date: Wed Aug 3 10:56:12 2022 +0800 Network: Add support for orbitalGateway commit 4620cb506b866b649c7f666e54ba2431825a2475 Author: catriona-m <86247157+catriona-m@users.noreply.github.com> Date: Tue Aug 2 17:36:30 2022 +0100 add github token to wating-response labeler (#17849) commit e97e2119defd9146ea48e44c89ddb3748580eddb Author: Xiaxin <92154856+xiaxyi@users.noreply.github.com> Date: Wed Aug 3 00:02:41 2022 +0800 Updating Eventhub as the log analytics destination (#17668) commit 4ece915bc5c5fdb1acad90cd21110d0b90afd154 Author: Yichun Ma Date: Wed Aug 3 00:01:55 2022 +0800 `r\mssql_virtual_machine`: add state refresh for `auto_patching` (#17203) commit 132f1ed008b7727e34cbee4895468629d1ef2e56 Author: Neil Ye Date: Tue Aug 2 23:53:34 2022 +0800 azurerm_subnet - support new service for delegation (#17796) commit 9d4d0bfd5ab4f2b0ee98b222fcd6b7002c9d656a Author: kt Date: Tue Aug 2 08:52:54 2022 -0700 CHANGELOG #17737 commit 45b1f37ff17cbe5aad0a35e1bc334ba148466382 Author: magodo Date: Tue Aug 2 23:50:00 2022 +0800 Upgrade API for domain service: 2020-01-01 -> 2021-05-01 (#17737) commit c4f693c48a17be62ddaf2b4f89803afc1187afc6 Author: stephybun Date: Tue Aug 2 15:00:13 2022 +0200 Update for #17577 commit bb74eca24ad40d5c07adce81880d0a6d4515029e Author: diklatze Date: Tue Aug 2 15:56:37 2022 +0300 change sku tier to not force new (#17577) * change sku tier to ot force new * add test * Update internal/services/firewall/firewall_resource.go Co-authored-by: kt * Update internal/services/firewall/firewall_resource_test.go Co-authored-by: kt * add cost and upadated doc * add quotes to around sku value in test config Co-authored-by: Dikla Tzemah Weyl Co-authored-by: kt Co-authored-by: Steph commit b6f38c06fed5b456e4f7c1e37d083ef54a919ab5 Author: catriona-m <86247157+catriona-m@users.noreply.github.com> Date: Tue Aug 2 13:37:13 2022 +0100 gha - check for d.Get in delete and new CreateUpdates (#17830) * checks for d.Get in delete and new CreateUpdate * remove space commit 47dc45ea5fc4f56dc9bf18e4f228616fc7880443 Author: stephybun Date: Tue Aug 2 14:12:28 2022 +0200 Update for #17547 commit 3e7ddffd6dbff7cdb8d6dfa8a25461314868cdc1 Author: AlexPykavy <32162928+AlexPykavy@users.noreply.github.com> Date: Tue Aug 2 14:09:53 2022 +0200 Validate shared image identifier attributes (#17547) To fail fast during the plan stage if there are some violations. Co-authored-by: Alexander Pykavy commit 87f9d189f6962eef03eb0129af44c29af4ec7184 Author: Xiaxin <92154856+xiaxyi@users.noreply.github.com> Date: Tue Aug 2 19:10:39 2022 +0800 Fix test case for `azurerm_signalr_service` (#17835) * fix test case * update test case commit b424e9c291264e8eb71edfe7c0f3fc5c54fe0f44 Author: bubbletroubles <42738824+bubbletroubles@users.noreply.github.com> Date: Tue Aug 2 21:08:40 2022 +1000 `azurerm_app_service_virtual_network_swift_connection` - updated documentation for associating to vNets (#17734) * Updated documentation * Update website/docs/r/app_service_virtual_network_swift_connection.html.markdown Co-authored-by: Tom Harvey * Update website/docs/r/app_service_virtual_network_swift_connection.html.markdown Co-authored-by: Tom Harvey Co-authored-by: Tom Harvey commit ee184edddbd01f8b8b9f6360923563c1a6057eae Author: stephybun Date: Tue Aug 2 09:32:29 2022 +0200 Update for #17780 commit db73ba7d0eea358a1cdc3030b702daa682523a5c Author: Neil Ye Date: Tue Aug 2 15:28:34 2022 +0800 azurerm_log_analytics_cluster - update the validation for size_gb (#17780) * rebase and resolve merge conflicts * update code * update code * update code commit da8cd028f437022963fb009478a9ebbd3ec06e3a Author: stephybun Date: Tue Aug 2 09:10:49 2022 +0200 Update for #17836 commit d98612f01f0eadf7c36c2b5957cda84ffff97705 Author: lonegunmanb Date: Tue Aug 2 15:08:59 2022 +0800 Make `instances` optional since the API doesn't require this parameter. (#17836) If we leave this parameter `nil` in creation, the API will respond `0` when we read, so I add a default value to this argument. Co-authored-by: zjhe commit 9f517db10b719eeceb464ae5af78d6c3000e0abf Author: sneakernuts <671942+sneakernuts@users.noreply.github.com> Date: Tue Aug 2 00:54:51 2022 -0600 Update kubernetes_cluster_node_pool.html.markdown (#17793) Scale-down Mode went GA in April 2022, and spot node pools are now fully supported. commit 2daadb0f15ce7b64107c863ea76526b0b3c6f01a Author: Gergő Rubint Date: Tue Aug 2 08:41:34 2022 +0200 Docs: point `timeouts`, `operation-timeouts` and `lifecycle` links to their new place (#17819) * Docs: point `timeouts` and `operation-timeouts` links to their new place Signed-off-by: Gergő Rubint * Docs: point `lifecycle` links to their new place Signed-off-by: Gergő Rubint commit c379aa69482a6ad3c7add01cba218f09772b63a7 Author: Nirav Bhimani Date: Mon Aug 1 23:40:37 2022 +1000 Update postgresql_flexible_server.html.markdown (#17826) Postgres Flexible Server support version 14 but docs were not updated when v14 support was added. commit cd2772e4fba405d265176b926672a5e3e842f72f Merge: bbeb5c184d 63b6780bd2 Author: Tom Harvey Date: Sun Jul 31 19:06:43 2022 +0100 Merge pull request #17820 from myc2h6o/extension_doc_fix `d\virtual_machine_extension`: Fix `settings` to be Optional in doc commit bbeb5c184d80c7a4adf7897fbede2fec17956809 Author: Tom Harvey Date: Sun Jul 31 13:05:31 2022 +0100 updating to include #17776 commit 0bf55cc86ed2c3ce0f5868dc5faa8fb356c3117c Merge: 5b7ce97924 64041d16cf Author: Tom Harvey Date: Sun Jul 31 13:03:10 2022 +0100 Merge pull request #17776 from hashicorp/refactor/compute-proximity-placement-groups refactor: migrating proximity_placement_group to `hashicorp/go-azure-sdk` commit 5b7ce9792439402bafbffaf3eab233e9c8a7b048 Author: Tom Harvey Date: Sun Jul 31 12:48:07 2022 +0100 updating to include #17729 commit 03e45c1d4b7d08b44af33df375c2a197bf10bf5e Merge: 5cbafc5ce2 d7716da416 Author: Tom Harvey Date: Sun Jul 31 12:46:45 2022 +0100 Merge pull request #17729 from owenfarrell/private_dns_zone_data_source `azurerm_private_dns_zone` - Ensure consistent ID generation commit 63b6780bd2bc05e068ffb05a17a8a2ff16ed0603 Author: Yichun Ma Date: Sat Jul 30 20:18:26 2022 +0800 `d\virtual_machine_extension`: Fix `settings` to be Optional in doc commit 5cbafc5ce27aaf909b80a126380869049639efa7 Author: bubbletroubles <42738824+bubbletroubles@users.noreply.github.com> Date: Sat Jul 30 01:30:01 2022 +1000 `azurerm_log_analytics_cluster` - enable Minimum of 500GB (#17794) commit 9b162b65b1b4d5865551d8ff5a34285d7d9c4ff2 Author: Gergő Rubint Date: Fri Jul 29 17:22:05 2022 +0200 Fix docs typo and invalid target fqdn in azurerm_firewall_policy_rule_collection_group (#17807) commit dff3c08bb294f4049bd6e7ec7fca2b15820414fa Author: kt Date: Thu Jul 28 18:01:16 2022 -0700 v3.16.0 commit 3bac486edba186a2a6f057f8fbb689a447583437 Author: kt Date: Thu Jul 28 18:00:28 2022 -0700 Update CHANGELOG.md commit cde6af013f9ae1373034e9cda2ce3ff485d2febe Author: kt Date: Thu Jul 28 17:37:06 2022 -0700 CHANGELOG #17106 commit b4cd59f29dfdd01181c0f566d55abecb873ba27e Author: Yichun Ma Date: Fri Jul 29 08:36:09 2022 +0800 `r\iothub_dps_certificate`: support `is_verified` (#17106) commit 364bfb4fb656591a9c890ca2f666465cf17547b6 Author: kt Date: Thu Jul 28 17:26:16 2022 -0700 Update CHANGELOG.md commit 8d88b4896fab34fdaa0bf7798a03743ebe1d5756 Author: Yun Liu Date: Fri Jul 29 08:25:53 2022 +0800 new resource `azurerm_kusto_cluster_managed_private_endpoint` (#17667) commit 0e05714875686fcd01308fda793c2cb823a8aa54 Author: kt Date: Thu Jul 28 17:18:06 2022 -0700 CHANGELOG #17347 commit 23be676626cab27565e44c16a0ddb4873884d53f Author: Xu Wu Date: Fri Jul 29 08:17:25 2022 +0800 update automation account to use go-azure-sdk (#17347) Co-authored-by: xuwu1 commit 5836a9f7ea3516b00c5acac072218cad322a4c08 Author: JT <100274846+jiaweitao001@users.noreply.github.com> Date: Fri Jul 29 08:15:02 2022 +0800 `HDInsight`: Adding support for `httpsEndpoints` and `installScriptAction` in hadoop edge node (#17655) commit 1e720dec9771a7183fbe97665a4b198aa45a734c Author: kt Date: Thu Jul 28 17:13:40 2022 -0700 CHANGELOG #16187 commit 15cfe8368428a2b4bdbb3486c5cb35cbc5849fa6 Author: Xiaxin <92154856+xiaxyi@users.noreply.github.com> Date: Fri Jul 29 08:13:13 2022 +0800 New Resourece: azurerm_signalr_shared_private_link_resource (#16187) commit 8c89a5a3383fde07a0136837e01c4e7f835ef2aa Author: Xiaxin <92154856+xiaxyi@users.noreply.github.com> Date: Fri Jul 29 07:08:00 2022 +0800 fixing dotnet core version issue for resource `azurerm_windows_web_app` (#17285) commit d9514e101ed6f8d58c9e149ae8ca62fa84ce4cff Author: kt Date: Thu Jul 28 16:06:36 2022 -0700 CHANGELOG #17557 commit 1021e6f84acc86a3856bb7cc15b64c6844e69318 Author: Zhenhua Hu Date: Fri Jul 29 07:06:10 2022 +0800 New Resource: azurerm_logz_sub_account_tag_rule (#17557) commit df8a845d20352f018a2c6ff2f7cc64921c406a10 Author: Yichun Ma Date: Fri Jul 29 07:02:11 2022 +0800 `d\managed_disk`: Add support for `encryption_settings` (#15774) commit 1c23463a94b34305b4b38c99d91c7b7997e35846 Author: kt Date: Thu Jul 28 15:57:15 2022 -0700 CHANGELOG #17683 commit 748e446cf598149b0af2c014e80416d4f5a6692f Author: Heng Lu <79895375+ms-henglu@users.noreply.github.com> Date: Fri Jul 29 06:56:42 2022 +0800 `azurerm_cognitive_account` - `custom_question_answering_search_service_key` (#17683) commit 11cc0d90ec8e6191c387c3606d0b7b8e70471c16 Author: kt Date: Thu Jul 28 15:55:34 2022 -0700 CHANGELOG #17423 commit 4f72172d5bd53b03b7bbd22857eb72c09659c4d0 Author: Neil Ye Date: Fri Jul 29 06:54:54 2022 +0800 azurerm_bot_service_azure_bot - support streaming_endpoint_enabled (#17423) Co-authored-by: neil-yechenwei commit e602f4ae413b1649f54fc2c59350f5a019e74435 Author: kt Date: Thu Jul 28 15:53:51 2022 -0700 CHANGELOG #17739 commit c5c9df4108f297a3e2641a74599810db86dd93c0 Author: JT <100274846+jiaweitao001@users.noreply.github.com> Date: Fri Jul 29 06:53:19 2022 +0800 `azure_stream_analytics_stream_input_eventhub`: Add support for `authentication_mode` (#17739) commit 9e87070f5446b2d8fe7c2fc7423c4bc6512d066e Author: Matthew Frahry Date: Thu Jul 28 14:37:04 2022 -0700 Update changelog for #16131 commit 9e76a20db649408c3a2db693ab653f60b1c80ed0 Author: vikotha <81368129+vikotha@users.noreply.github.com> Date: Fri Jul 29 03:06:08 2022 +0530 New Resource: `azurerm_datadog_monitor` (#16131) commit e4ca9fe8516ac3c7a36538c50a7cdd6baa4aac34 Author: kt Date: Thu Jul 28 14:09:42 2022 -0700 CHANGELOG #17685 commit 3abeb7f19f3e65095d2aee21cf158c1abcdff3db Author: Neil Ye Date: Fri Jul 29 05:09:05 2022 +0800 New Resource: azurerm_log_analytics_query_pack (#17685) Co-authored-by: neil-yechenwei commit c3612d8142d4a0cd217ea816115c5a7b3398ed59 Author: BeTheFlow95 <47504883+BeTheFlow95@users.noreply.github.com> Date: Thu Jul 28 20:16:57 2022 +0200 Fix typo for TTL Argument Reference in dns_a_record (#17783) commit 20b7e2a0f5edf8f778156c37354ede7f3720ceca Author: kt Date: Thu Jul 28 09:58:10 2022 -0700 CHANGELOG #17789 commit 48b307b0b8f3e4ee84d3a46ffb49f56e6589d7de Author: jackofallops <11830746+jackofallops@users.noreply.github.com> Date: Thu Jul 28 17:41:46 2022 +0100 `azurerm_linux_function_app` and `azurerm_linux_function_app_slot` - fix casing bug in `linux_fx_string` for Node apps (#17789) commit 9681e8768a98f10bb757a2a4f7221e349619ea65 Author: David Gardiner Date: Thu Jul 28 20:14:02 2022 +0930 Remove the invalid 'FREE' SKU from app_service_plan (#17778) Fixes #17032 commit 64041d16cfc51730bc40206d31a64effa74a96b6 Author: tombuildsstuff Date: Thu Jul 28 09:36:18 2022 +0200 goimports commit 5fd32b3b3cf8a4a1891dee79e8890a125a2f36ce Author: jackofallops <11830746+jackofallops@users.noreply.github.com> Date: Thu Jul 28 07:51:34 2022 +0100 Updated for #17494 commit 14877c0e83b3b78702c53ba85c5d8d7d6d3da651 Author: bubbletroubles <42738824+bubbletroubles@users.noreply.github.com> Date: Thu Jul 28 16:50:07 2022 +1000 `azurerm_linux_function_app` `azurerm_linux_function_app_slot` expose `virtual_network_subnet_id` for vNet integration (#17494) commit 8683b0b5140ca558e6c754c6a4629194fdd8ea35 Author: jackofallops <11830746+jackofallops@users.noreply.github.com> Date: Thu Jul 28 07:46:53 2022 +0100 Updated for #17576 commit e83a9aab5bb96ad07fe924c46edfc843965f019c Author: bubbletroubles <42738824+bubbletroubles@users.noreply.github.com> Date: Thu Jul 28 16:45:33 2022 +1000 `azurerm_windows_web_app` `azurerm_windows_web_app_slot` expose `virtual_network_subnet_id` for vNet integration (#17576) commit d162eeec0a17e68eaeacdad319244273d6c55611 Author: jackofallops <11830746+jackofallops@users.noreply.github.com> Date: Thu Jul 28 07:23:16 2022 +0100 Updated for #17572 commit 3c020f81eb254ee27e42bd6a39e320b0a9de0a30 Author: bubbletroubles <42738824+bubbletroubles@users.noreply.github.com> Date: Thu Jul 28 16:21:48 2022 +1000 `azurerm_windows_function_app` `azurerm_windows_function_app_slot` expose `virtual_network_subnet_id` for vNet integration (#17572) commit 0821e38c5ee9399f88397d9de74d35ddac222c3f Author: catriona-m <86247157+catriona-m@users.noreply.github.com> Date: Thu Jul 28 06:51:59 2022 +0100 GHA - add waiting-response label based on comment (#17775) commit 1f03f212a4c7f216b52f4793998e58f63723cc8a Author: jackofallops <11830746+jackofallops@users.noreply.github.com> Date: Thu Jul 28 06:02:43 2022 +0100 Updated for #17584 commit bc710ecb058bb30a34734fd3745f41e1fc846c7c Author: bubbletroubles <42738824+bubbletroubles@users.noreply.github.com> Date: Thu Jul 28 15:01:54 2022 +1000 `azurerm_linux_web_app` `azurerm_linux_web_app_slot` - Documentation and test enhancements related to `virtual_network_subnet_id` argument (#17584) * Update unit-test.yaml * Update unit-test.yaml * Update unit-test.yaml * Update unit-test.yaml * Create .gitattributes * Create build.yml * Create maketests.yaml * Update maketests.yaml * Update maketests.yaml * enhancements * Delete .gitattributes * Delete build.yml * Update unit-test.yaml * Delete maketests.yaml * cleanup * make fmt * Updated read to fix #17559 * Removed ForceNew * make fmt * make terrafmt * fixed test * make terrafmt * Fixed typo in URL * Fixed typo in URL Co-authored-by: Your Name commit 0c7ade05203c79b2ea112ef7b807cff0319f7ac9 Author: tombuildsstuff Date: Wed Jul 27 18:43:20 2022 +0200 gofmt commit 5f7f8aab6b4fe3ca446be7507b1661866633ca43 Author: tombuildsstuff Date: Wed Jul 27 18:42:24 2022 +0200 refactor: removing the legacy resource id parser for proximityplacementgroups commit 789e6598255463c96273b0f9d954120b8a6ac3fb Author: tombuildsstuff Date: Wed Jul 27 18:40:26 2022 +0200 refactor: migrating `proximity_placement_group` to `hashicorp/go-azure-sdk` commit 117cdd4dce11a88e813bda7e46b40f16b03c5340 Author: Tom Harvey Date: Tue Jul 26 14:46:52 2022 +0200 updating to include #17707 commit f81fad79692f1686aaf3e365a43ae7239c2b00d8 Merge: 405141fc2a 3e056dc2c0 Author: Tom Harvey Date: Tue Jul 26 14:46:15 2022 +0200 Merge pull request #17707 from stuartleeks/stuartleeks/fix-api-version-not-found Fix 'API version information for RP "microsoft.insights" was not found' commit 405141fc2a88334bc30bb338185455a69ffbfa3b Merge: 9d258e64f6 c7514a0145 Author: Tom Harvey Date: Tue Jul 26 14:33:56 2022 +0200 Merge pull request #17754 from CorrenSoft/feature/azurerm_api_management_api_operation_policy Fix api_management_api_operation_policy docs: wrong description at property api_name commit 9d258e64f667fad93d6b36842a14aedadf0607c0 Merge: a6d6f08ccd 2bfcc53172 Author: Tom Harvey Date: Tue Jul 26 14:06:03 2022 +0200 Merge pull request #17669 from Korving-F/azurerm_ise_documentation_update Changes documentation to reflect ISE network requirements commit a6d6f08ccdc3de39a2e6558b0e488334c817e59e Merge: c9985749be 1ec2230074 Author: Tom Harvey Date: Tue Jul 26 14:05:34 2022 +0200 Merge pull request #17699 from bubbletroubles/ds-ns `azurerm_dns_ns_record` documentation update commit c9985749be6dc99dee971080e3ad91f2610835cc Merge: 70f58b2dde e49ebd7cf2 Author: Tom Harvey Date: Tue Jul 26 14:04:43 2022 +0200 Merge pull request #17742 from sinacek/front-door-examples Front door examples commit 70f58b2dded8554f2e058e7699baf31ce1641ae2 Author: Tom Harvey Date: Tue Jul 26 09:11:08 2022 +0200 including 3.15.1 commit 26403de066e5ef0ef81516e8f703d12cbaf231f6 Author: Tom Harvey Date: Tue Jul 26 09:10:08 2022 +0200 updating to include #17753 commit 3a9f48995690f35f3b8677a369fb009df8f5768a Merge: 5ae9effa22 69805b623b Author: Tom Harvey Date: Tue Jul 26 09:09:42 2022 +0200 Merge pull request #17753 from hashicorp/dependencies/go-azure-sdk dependencies: updating to use `v0.20220725.1163004` of `github.com/hashicorp/go-azure-sdk` commit 5ae9effa224b7987fad403866a71655e2114778c Author: Matthew Frahry Date: Mon Jul 25 16:09:30 2022 -0700 `azurerm_postgresql_server` `data.azurerm_servicebus_queue` - Fix regression around ids (#17755) commit c7514a0145a592d4a36483a47f6ae62ae15b7351 Author: Lucas Fernández Date: Mon Jul 25 18:26:00 2022 -0300 Fixing api_management_api_operation_policy.html.markdown commit e648f5f44272c1e910d559d93e8dae527b442f87 Author: Matthew Frahry Date: Mon Jul 25 11:49:15 2022 -0700 Update changelog for #17732 commit cb8ecc19220a5a275464717ea97246821c0f22b5 Author: Vladimir Lazarenko Date: Mon Jul 25 20:48:46 2022 +0200 `azurerm_postgresql_aad_administrator`: Fix state migration (#17732) commit 69805b623b02bb8997ae2a9f9cfaa75476c819b4 Author: tombuildsstuff Date: Mon Jul 25 18:31:35 2022 +0200 dependencies: updating to use `v0.20220725.1163004` of `github.com/hashicorp/go-azure-sdk` commit dd35d50e5912c1736f7f63b1fdf0fb30dd9c4c3a Author: Tom Harvey Date: Mon Jul 25 18:02:51 2022 +0200 updating to include #17749 commit e39405f1670be1718860eed7d0d9ef418b62119c Merge: c7c6214ece 54dbea13ac Author: Tom Harvey Date: Mon Jul 25 18:02:01 2022 +0200 Merge pull request #17749 from hashicorp/deps/bump-sdk-v0.20220725.1131927 bump go-azure-sdk to v0.20220725.1131927 commit c7c6214ece41f6cd02ea6a365e057a0a814bdb38 Merge: 13f68c9f76 3767d9aa7c Author: Tom Harvey Date: Mon Jul 25 17:58:03 2022 +0200 Merge pull request #17751 from EvertonSA/docs/update_uai_import docs: fix import command user_assigned_identity commit 13f68c9f76276c1c64124e374165d08402f52f2e Author: Wodans Son <20408400+WodansSon@users.noreply.github.com> Date: Mon Jul 25 09:06:41 2022 -0600 Documentation: `azurerm_cdn_frontdoor_origin` - Fix example usage (#17730) commit 3767d9aa7c5e086819d683bdf153eb34afdbba8f Author: Everton Seiei Arakaki <30481051+EvertonSA@users.noreply.github.com> Date: Mon Jul 25 17:04:41 2022 +0200 docs: fix import command user_assigned_identity commit d7716da4166f8af88656c03ec3d6e24080ac1410 Author: Owen Farrell Date: Mon Jul 25 10:17:06 2022 -0400 Add checks to acceptance tests Signed-off-by: Owen Farrell commit 54dbea13ac60a6804dd0149e41b18b6d96045037 Author: jackofallops Date: Mon Jul 25 15:14:17 2022 +0100 bump go-azure-sdk to v0.20220725.1131927 commit 1b89d257c8ffb23bb2d1f6c0544dbb79e85a1855 Author: jackofallops <11830746+jackofallops@users.noreply.github.com> Date: Mon Jul 25 14:51:08 2022 +0100 Updated for #17719 commit 99162dabfddb7ef7f92b0915c3f9fd028e719dca Author: Tom Harvey Date: Mon Jul 25 15:49:57 2022 +0200 eventhub: consolidating onto API Version 2021-11-01 (#17719) Co-authored-by: catriona-m commit e49ebd7cf29ee52fc5546a9bc3c263d8338acb52 Author: František Hána Date: Mon Jul 25 11:23:54 2022 +0200 formating commit 050d65f1dee3f6a836041dae48dbfd620b8a461f Author: František Hána Date: Mon Jul 25 11:21:55 2022 +0200 fix front door examples commit f3353d604b58f2f7d0a19b22fffffbd40b59112d Merge: 55499dd28d 1b124b71df Author: Tom Harvey Date: Mon Jul 25 09:03:29 2022 +0200 Merge pull request #17733 from simonsabin/patch-1 Correct Sku names to match code commit 55499dd28d9914a4a775a31d80f0bc5bca0605f4 Author: Tom Harvey Date: Mon Jul 25 09:01:14 2022 +0200 updating to include #17726 commit ece8a1bcb51cb9e16542b053ab90c9670ec83d3e Merge: 546ba633b4 15f58fbf9b Author: Tom Harvey Date: Mon Jul 25 09:00:34 2022 +0200 Merge pull request #17726 from hashicorp/dependencies/go-azure-sdk-2 dependencies: updating to `v0.20220722.1091911` of `github.com/hashicorp/go-azure-sdk` commit 1b124b71df2c77d7483bc27d48028fe86902a76b Author: Simon Sabin <1209963+simonsabin@users.noreply.github.com> Date: Sat Jul 23 13:21:32 2022 +0100 Correct Sku names to match code the code has different sku names, correct docs to match https://github.com/hashicorp/terraform-provider-azurerm/blob/546ba633b44b4271d2cb8bfb2e8572366d399c28/internal/services/mssql/mssql_managed_instance_resource.go#L85-L93 commit 7639fba884d00b1bd7ed21568f2e455b6c9aa8d7 Author: Owen Farrell Date: Fri Jul 22 21:01:29 2022 -0400 Remove single-use local variables Signed-off-by: Owen Farrell commit 546ba633b44b4271d2cb8bfb2e8572366d399c28 Author: Michael Madeja Date: Fri Jul 22 18:09:21 2022 -0500 change storage_size_in_gb from 8192 to 16384 (#17711) commit 517bc4386f9b7e1a0d2ff42c06433542a5a907d5 Author: Ben <57881441+benhurjoel@users.noreply.github.com> Date: Sat Jul 23 07:08:38 2022 +0800 Update linux_web_app.html.markdown (#17718) commit e92893f1d36eb3981559b633ee27673500c857f2 Author: catriona-m <86247157+catriona-m@users.noreply.github.com> Date: Fri Jul 22 22:28:52 2022 +0100 GHA - new actions to add/remove wating-response (#17708) commit 15f58fbf9bb6e603623015a727fbf4ef75d001b8 Author: tombuildsstuff Date: Fri Jul 22 14:07:18 2022 +0200 dependencies: updating to `v0.20220722.1091911` of `github.com/hashicorp/go-azure-sdk` commit df114ab23dbb45f118a624b928401a43941d2b54 Author: kt Date: Thu Jul 21 20:19:48 2022 -0700 v3.15.0 commit 6a9db8d904cf6c50731f1b7ce2a4a6b762f53540 Author: kt Date: Thu Jul 21 20:12:28 2022 -0700 Update CHANGELOG.md commit 5c13669fca1aba3ded449059874480832161ed7f Author: Wodans Son <20408400+WodansSon@users.noreply.github.com> Date: Thu Jul 21 21:07:22 2022 -0600 Updating to include #17089 commit 3a01a8f9a864abc174d7c914083f2d1f7f3d373a Author: Tom Harvey Date: Fri Jul 22 05:03:21 2022 +0200 adding #17089 * New Resource: `azurerm_cdn_frontdoor_endpoint` Porting across from #16671 Co-authored-by: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> * cdn: generating the ID Parsers/Validators for CDN FrontDoor Origin & Origin Group * New Resource: `azurerm_cdn_frontdoor_origin_group` Splitting out from #16671 Co-authored-by: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> * New Data Source: `azurerm_cdn_frontdoor_origin_group` * New Resource: `azurerm_cdn_frontdoor_origin` Splitting this out from #16671 Co-authored-by: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> * refactor: linting * Make name check required * fix rule set datasource test * fix test case part duex * Fix test part wej * v3.14.0 * addressing PR comment * go mod tidy * Update changelog Co-authored-by: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> Co-authored-by: kt commit b35cbed5b15ab717f85341493343ad8e26b73da0 Author: kt Date: Thu Jul 21 19:17:59 2022 -0700 CHANGELOG.md #17595 commit 04e4a073d54b445b51eeba8972db8ee5807ce240 Author: magodo Date: Fri Jul 22 10:17:20 2022 +0800 domainservice: refactoring domainservice resources to using go-azure-sdk (#17595) commit bd0f7af7d28ab5c905c3500f9bfc2f937074d942 Author: kt Date: Thu Jul 21 18:39:27 2022 -0700 Update CHANGELOG.md commit 2545a30dae5478dc92d9e8d28e245544dbf75158 Author: Mike Madeja Date: Thu Jul 21 15:22:54 2022 -0500 change storage_size_in_gb from 8192 to 16384 commit 3e056dc2c00b56a21f14af54b4383028102d81ac Author: Stuart Leeks Date: Thu Jul 21 19:03:44 2022 +0000 terrafmt commit 788312bb871a400aaa8634ef568d6b41ab81a324 Author: Stuart Leeks Date: Thu Jul 21 18:31:59 2022 +0000 go mod vendor commit d5a19b00e5f8edab77edd50b8f7df3ccddb23d6c Merge: d44d92b877 5191551bb9 Author: Tom Harvey Date: Thu Jul 21 18:37:39 2022 +0200 Merge pull request #17697 from teowa/fix_doc_feature_api_management fix doc: features-block for `api_management` commit dff91343179767a28b1a45a23db68751a0e99c46 Author: Stuart Leeks Date: Thu Jul 21 13:53:08 2022 +0000 Fix API version error commit 781d863125a4b588d21af762654e86b71aac8955 Author: Stuart Leeks Date: Thu Jul 21 07:59:25 2022 +0000 Add test for API version error commit 1ec223007417002e84fae76ce4703121ae4a102f Author: bubbletroubles <42738824+bubbletroubles@users.noreply.github.com> Date: Thu Jul 21 18:02:23 2022 +1000 Update dns_ns_record.html.markdown commit 5191551bb9e1bb164ba4d384da9d8af0fc4966db Author: Tao <104055472+teowa@users.noreply.github.com> Date: Thu Jul 21 14:06:25 2022 +0800 fix doc of features-block for api_management commit d44d92b8777be1a1ea3e6cd04455f5e88abdb526 Author: Matthew Frahry Date: Wed Jul 20 16:30:59 2022 -0700 Update changelog for #17625 commit ccc278f28c463d4f13709d1a4468a5f6759b1a58 Author: Matthew Frahry Date: Wed Jul 20 16:30:16 2022 -0700 `postgres` - swap to `hashicorp/go-azure-sdk` (#17625) commit 852010ec4bf8fcf32e00051138de124032f6022f Author: Michael A. Pelland <94231072+mapcrux@users.noreply.github.com> Date: Wed Jul 20 00:09:08 2022 -0400 Update windows_web_app.html.markdown (#17679) Linux Web App changed in documentation to Windows Web App commit bf27cfaa37f0a0419c00c08ac90ca7f434e86794 Author: Xiaxin <92154856+xiaxyi@users.noreply.github.com> Date: Wed Jul 20 12:08:11 2022 +0800 Fixing wrong reference for resource `azurerm_servicebus_topic` (#17673) commit 961cefa1d8e84f6f48666427dd8123fe8f6a333e Author: kt Date: Tue Jul 19 21:05:38 2022 -0700 CHANGELOG #17130 commit bc8508ba37d18591743ef7efd5ddb2c6c4c31f75 Author: magodo Date: Wed Jul 20 12:05:04 2022 +0800 `azurerm_storage_account` - add supports for `change_feed_retention_in_days` (#17130) commit 012aaa3fb9829d24063d40a14f70d4aa1d601558 Author: magodo Date: Wed Jul 20 12:04:12 2022 +0800 `azurerm_storage_account` - support disable `blob_properties.0.{delete_retention_policy|container_delete_retention_policy}` & `share_properties.0.retention_policy` (#17256) commit cc2cbcea048bcc59e09cbaf8266c34df8228dbd0 Author: kt Date: Tue Jul 19 21:02:35 2022 -0700 CHANGELOG #17581 commit 01029aaab4aa11965576f5d9d080247ec5ccaab2 Author: Yun Liu Date: Wed Jul 20 12:01:51 2022 +0800 kusto_cluster_resource - allowed_fqdns, allowed_ip_ranges, outbound_network_access_restricted (#17581) commit ee0f2924c67c4c2bf68840cc3d399a84fda64828 Author: kt Date: Tue Jul 19 20:50:15 2022 -0700 CHANGELOG #16578 commit c79ab48b023bd0d93b9097005df76ab8714b2268 Author: Xiaxin <92154856+xiaxyi@users.noreply.github.com> Date: Wed Jul 20 11:49:38 2022 +0800 New Resource - azurerm_route_server_bgp_connection, azurerm_route_server (#16578) commit ee9643fb999f7e5a6aa1eec44abf9efef099f5a9 Author: kt Date: Tue Jul 19 20:42:04 2022 -0700 CHANGELOG #17368 commit 0ad8c6c071dfb2a2352e364b324ce245642c8666 Author: Zhenhua Hu Date: Wed Jul 20 11:41:39 2022 +0800 New Resource: azurerm_application_insights_workbook (#17368) commit 6a81ea0f51a9fd30b05a71543d82d66827ac3821 Author: kt Date: Tue Jul 19 20:33:06 2022 -0700 CHANGELOG #15550 commit 971915d0c807a825066d0e7c68817c00f2da3c55 Author: Xiaxin <92154856+xiaxyi@users.noreply.github.com> Date: Wed Jul 20 11:32:26 2022 +0800 Adding shared private link resource for the Azure web pubsub resource (#15550) commit ad388968de5243f9f950c36bc2021761ec7115d2 Author: Matthew Frahry Date: Tue Jul 19 16:00:37 2022 -0700 Update go-azure-sdk to v0.20220719.1202339 (#17680) commit a6c9513528162a00bb297cc11b3897ff56b6a5ff Author: Matthew Frahry Date: Tue Jul 19 09:20:11 2022 -0700 Update changelog for #17342 commit 4146eda314ce5af94571f90b2ec94bde15eada75 Author: Tao <104055472+teowa@users.noreply.github.com> Date: Wed Jul 20 00:14:39 2022 +0800 New Resource: `azurerm_monitor_data_collection_rule` (#17342) commit 2bfcc53172762622b2959ba43dcbde491769f173 Author: Korving-F Date: Tue Jul 19 09:57:59 2022 +0300 Changes documentation to reflect ISE network requirements commit ee0ab94d586da6efa22e8bc5943ca941d21f4b16 Author: magodo Date: Tue Jul 19 01:58:29 2022 +0800 Import spec fix: azurerm_managed_disk (#17658) commit a93af7379ede9ecba97db421331c763098ca093d Author: Zhenhua Hu Date: Tue Jul 19 01:57:59 2022 +0800 Fix: Get valid API version from error code for `resource group template deployment` resource when original API version is mismatched (#15758) commit f59c07edbc942f6f0cdfcbdf94c75d95b578645b Author: magodo Date: Wed Jul 6 13:11:22 2022 +0800 Update storage api to 2021-09-01 --- .github/labeler-pull-request-triage.yml | 3 + .github/workflows/depscheck.yaml | 5 +- .github/workflows/gencheck.yaml | 5 +- .github/workflows/golint.yaml | 4 +- .github/workflows/gradually-deprecated.yaml | 4 +- .github/workflows/issue-comment-created.yaml | 17 + .github/workflows/issue-opened.yaml | 3 + .github/workflows/link-milestone.yaml | 2 +- .github/workflows/lock.yaml | 3 + .../workflows/pull-request-new-commit.yaml | 18 + .../pull-request-reviewed-workflow.yaml | 48 + .github/workflows/pull-request-reviewed.yaml | 36 + .github/workflows/pull-request.yaml | 3 + .github/workflows/teamcity-test.yaml | 4 + .github/workflows/tflint.yaml | 6 +- .github/workflows/thirty-two-bit.yaml | 7 +- .github/workflows/unit-test.yaml | 6 +- .github/workflows/validate-examples.yaml | 6 +- .github/workflows/website-lint.yaml | 6 +- .go-version | 2 +- .teamcity/components/generated/services.kt | 3 + CHANGELOG-v2.md | 2 +- CHANGELOG.md | 276 +- README.md | 2 +- contributing/topics/guide-new-data-source.md | 2 +- contributing/topics/guide-new-resource.md | 2 +- contributing/topics/guide-opening-a-pr.md | 6 +- examples/app-service/docker-compose/README.md | 2 +- .../app-service/docker-kubernetes/README.md | 2 +- .../private-link-scope/README.md | 9 + .../private-link-scope/main.tf | 64 + .../private-link-scope/variables.tf | 7 + .../linux/load-balanced/main.tf | 5 + go.mod | 5 +- go.sum | 10 +- helpers/validate/float.go | 29 + internal/clients/client.go | 12 +- internal/common/client_options.go | 3 +- internal/provider/provider.go | 75 +- internal/provider/provider_test.go | 10 +- internal/provider/services.go | 13 + .../analysis_services_server_resource.go | 16 +- ..._gateway_certificate_authority_resource.go | 151 + ...way_certificate_authority_resource_test.go | 254 + .../api_management_product_tag_resource.go | 130 + ...pi_management_product_tag_resource_test.go | 121 + .../services/apimanagement/client/client.go | 153 +- .../parse/gateway_certificate_authority.go | 81 + .../gateway_certificate_authority_test.go | 144 + .../apimanagement/parse/product_tag.go | 81 + .../apimanagement/parse/product_tag_test.go | 144 + .../services/apimanagement/registration.go | 80 +- .../services/apimanagement/resourceids.go | 2 + .../validate/api_management_sku.go | 2 +- .../validate/api_management_sku_test.go | 14 +- .../gateway_certificate_authority_id.go | 23 + .../gateway_certificate_authority_id_test.go | 100 + .../apimanagement/validate/product_tag_id.go | 23 + .../validate/product_tag_id_test.go | 100 + .../app_configuration_data_source.go | 6 + .../app_configuration_data_source_test.go | 1 + .../app_configuration_resource.go | 48 + .../app_configuration_resource_test.go | 45 +- .../application_insights_workbook_resource.go | 331 + ...ication_insights_workbook_resource_test.go | 352 + ...ion_insights_workbook_template_resource.go | 28 +- ...nsights_workbook_template_resource_test.go | 4 +- .../applicationinsights/client/client.go | 12 +- .../applicationinsights/registration.go | 1 + .../validate/workbook_name.go | 21 + .../validate/workbook_tags.go | 21 + .../appservice/helpers/function_app_schema.go | 24 +- .../helpers/function_app_slot_schema.go | 156 +- .../appservice/helpers/service_plan.go | 1 - .../appservice/helpers/web_app_schema.go | 29 +- .../linux_function_app_data_source.go | 17 + .../linux_function_app_data_source_test.go | 7 + .../appservice/linux_function_app_resource.go | 79 +- .../linux_function_app_resource_test.go | 425 +- .../linux_function_app_slot_resource.go | 69 +- .../linux_function_app_slot_resource_test.go | 363 +- .../appservice/linux_web_app_resource.go | 25 +- .../appservice/linux_web_app_resource_test.go | 123 +- .../appservice/linux_web_app_slot_resource.go | 25 +- .../linux_web_app_slot_resource_test.go | 124 +- .../appservice/service_plan_resource_test.go | 61 + .../appservice/validate/web_app_name_test.go | 50 + .../windows_function_app_data_source.go | 17 + .../windows_function_app_data_source_test.go | 7 + .../windows_function_app_resource.go | 80 +- .../windows_function_app_resource_test.go | 436 +- .../windows_function_app_slot_resource.go | 92 +- ...windows_function_app_slot_resource_test.go | 303 +- .../appservice/windows_web_app_data_source.go | 6 + .../appservice/windows_web_app_resource.go | 29 + .../windows_web_app_resource_test.go | 219 +- .../windows_web_app_slot_resource.go | 29 + .../windows_web_app_slot_resource_test.go | 212 + .../automation_account_data_source.go | 45 +- .../automation/automation_account_resource.go | 280 +- .../automation_account_resource_test.go | 146 +- .../automation_connection_type_resource.go | 211 + ...utomation_connection_type_resource_test.go | 83 + .../automation_hybrid_runbook_worker_group.go | 180 + ...mation_hybrid_runbook_worker_group_test.go | 129 + internal/services/automation/client/client.go | 11 +- .../automation/parse/connection_type.go | 75 + .../automation/parse/connection_type_test.go | 128 + internal/services/automation/registration.go | 12 + internal/services/automation/resourceids.go | 1 + internal/services/automation/transition.go | 50 + .../automation/validate/connection_type_id.go | 23 + .../validate/connection_type_id_test.go | 88 + .../validate/connection_type_name.go | 19 + .../batch/batch_account_data_source_test.go | 22 +- .../services/batch/batch_account_resource.go | 156 +- .../batch/batch_account_resource_test.go | 255 +- .../batch_application_data_source_test.go | 11 +- .../batch/batch_application_resource_test.go | 22 +- internal/services/batch/batch_pool.go | 31 +- .../services/batch/batch_pool_data_source.go | 4 + .../batch/batch_pool_data_source_test.go | 11 +- .../services/batch/batch_pool_resource.go | 12 +- .../batch/batch_pool_resource_test.go | 130 +- .../blueprint_definition_data_source.go | 16 +- .../blueprint_definition_data_source_test.go | 1 + internal/services/bot/bot_channel_test.go | 9 +- .../bot_service_azure_bot_resource_test.go | 47 + .../services/bot/bot_service_base_resource.go | 17 + .../cdn_endpoint_custom_domain_resource.go | 275 +- ...dn_endpoint_custom_domain_resource_test.go | 128 +- .../cdn_frontdoor_endpoint_resource_test.go | 2 +- .../cdn_frontdoor_firewall_policy_resource.go | 1094 ++ ...frontdoor_firewall_policy_resource_test.go | 341 + .../services/cdn/cdn_frontdoor_helpers.go | 61 +- .../cdn_frontdoor_origin_group_data_source.go | 144 + ...frontdoor_origin_group_data_source_test.go | 37 + .../cdn_frontdoor_origin_group_resource.go | 381 + ...dn_frontdoor_origin_group_resource_test.go | 212 + .../cdn/cdn_frontdoor_origin_resource.go | 455 + .../cdn/cdn_frontdoor_origin_resource_test.go | 636 + ...cdn_frontdoor_rule_set_data_source_test.go | 4 +- .../cdn_frontdoor_security_policy_resource.go | 281 + ...frontdoor_security_policy_resource_test.go | 460 + internal/services/cdn/client/client.go | 60 +- .../cdn_frontdoor_security_params.go | 110 + .../cdn/parse/front_door_custom_domain.go | 131 + .../parse/front_door_custom_domain_test.go | 264 + .../cdn/parse/front_door_endpoint_test.go | 42 +- .../cdn/parse/front_door_firewall_policy.go | 113 + .../parse/front_door_firewall_policy_test.go | 229 + .../services/cdn/parse/front_door_origin.go | 149 + .../cdn/parse/front_door_origin_group.go | 131 + .../cdn/parse/front_door_origin_group_test.go | 264 + .../cdn/parse/front_door_origin_test.go | 299 + .../cdn/parse/front_door_profile_test.go | 34 +- .../cdn/parse/front_door_rule_set_test.go | 42 +- .../cdn/parse/front_door_rule_test.go | 50 +- .../cdn/parse/front_door_security_policy.go | 131 + .../parse/front_door_security_policy_test.go | 264 + .../cdn/parse/frontdoor_custom_domain.go | 131 + .../cdn/parse/frontdoor_custom_domain_test.go | 264 + internal/services/cdn/registration.go | 17 +- internal/services/cdn/resourceids.go | 13 +- internal/services/cdn/validate/cdn.go | 18 +- .../validate/front_door_custom_domain_id.go | 23 + .../front_door_custom_domain_id_test.go | 88 + .../validate/front_door_endpoint_id_test.go | 12 +- .../validate/front_door_firewall_policy_id.go | 23 + .../front_door_firewall_policy_id_test.go | 76 + .../front_door_firewall_policy_name.go | 15 + .../front_door_firewall_policy_name_test.go | 86 + .../validate/front_door_origin_group_id.go | 23 + .../front_door_origin_group_id_test.go | 88 + .../validate/front_door_origin_group_name.go | 15 + .../front_door_origin_group_name_test.go | 110 + .../cdn/validate/front_door_origin_id.go | 23 + .../cdn/validate/front_door_origin_id_test.go | 100 + .../cdn/validate/front_door_origin_name.go | 15 + .../validate/front_door_origin_name_test.go | 110 + .../validate/front_door_profile_id_test.go | 8 +- .../cdn/validate/front_door_rule_id_test.go | 16 +- .../validate/front_door_rule_set_id_test.go | 12 +- .../front_door_security_policy_domain_id.go | 24 + .../validate/front_door_security_policy_id.go | 23 + .../front_door_security_policy_id_test.go | 88 + .../validate/front_door_validation_helpers.go | 163 + .../cognitive/cognitive_account_resource.go | 24 +- .../cognitive_account_resource_test.go | 38 +- internal/services/compute/client/client.go | 15 +- .../compute/dedicated_host_data_source.go | 27 +- .../dedicated_host_group_data_source.go | 33 +- .../compute/dedicated_host_group_resource.go | 106 +- .../dedicated_host_group_resource_test.go | 9 +- .../compute/dedicated_host_resource.go | 158 +- .../compute/dedicated_host_resource_test.go | 9 +- .../compute/disk_encryption_set_resource.go | 47 +- .../services/compute/images_data_source.go | 19 +- .../compute/linux_virtual_machine_resource.go | 11 +- ...x_virtual_machine_resource_disk_os_test.go | 55 + ...achine_scale_set_identity_resource_test.go | 1 + ...inux_virtual_machine_scale_set_resource.go | 6 +- ...machine_scale_set_scaling_resource_test.go | 55 + .../compute/managed_disk_data_source.go | 52 + .../compute/managed_disk_data_source_test.go | 121 + .../services/compute/parse/dedicated_host.go | 75 - .../compute/parse/dedicated_host_group.go | 69 - .../parse/dedicated_host_group_test.go | 112 - .../compute/parse/dedicated_host_test.go | 128 - .../parse/proximity_placement_group.go | 69 - .../parse/proximity_placement_group_test.go | 112 - .../proximity_placement_group_data_source.go | 26 +- .../proximity_placement_group_resource.go | 72 +- ...proximity_placement_group_resource_test.go | 20 +- internal/services/compute/resourceids.go | 4 - .../compute/shared_image_data_source.go | 6 + .../services/compute/shared_image_resource.go | 34 +- .../compute/shared_image_resource_test.go | 55 + .../shared_image_version_data_source.go | 33 +- .../compute/shared_image_version_resource.go | 46 +- .../shared_image_version_resource_test.go | 58 + internal/services/compute/validate/compute.go | 20 + .../services/compute/validate/compute_test.go | 63 + .../validate/dedicated_host_group_id.go | 23 - .../validate/dedicated_host_group_id_test.go | 76 - .../compute/validate/dedicated_host_id.go | 23 - .../validate/dedicated_host_id_test.go | 88 - .../validate/proximity_placement_group_id.go | 23 - .../proximity_placement_group_id_test.go | 76 - .../virtual_machine_extension_resource.go | 4 + .../virtual_machine_scale_set_data_source.go | 196 + ...tual_machine_scale_set_data_source_test.go | 3 + ...al_machine_scale_set_extension_resource.go | 11 +- .../windows_virtual_machine_resource.go | 11 +- ...s_virtual_machine_resource_disk_os_test.go | 52 + .../services/consumption/client/client.go | 6 +- .../consumption/consumption_budget_base.go | 277 +- ...mption_budget_management_group_resource.go | 17 +- ...n_budget_management_group_resource_test.go | 8 +- ...ption_budget_resource_group_data_source.go | 28 +- ...sumption_budget_resource_group_resource.go | 6 +- ...ion_budget_resource_group_resource_test.go | 12 +- ...umption_budget_subscription_data_source.go | 28 +- ...onsumption_budget_subscription_resource.go | 6 +- ...ption_budget_subscription_resource_test.go | 8 +- .../consumption_budget_subscription.go | 6 +- .../consumption/parse/consumption_budget.go | 59 - .../consumption_budget_management_group.go | 58 - ...onsumption_budget_management_group_test.go | 93 - .../consumption_budget_resource_group.go | 69 - .../consumption_budget_resource_group_test.go | 112 - .../parse/consumption_budget_subscription.go | 61 - .../consumption_budget_subscription_test.go | 96 - .../parse/consumption_budget_test.go | 80 - internal/services/consumption/resourceids.go | 4 - .../consumption_budget_management_group_id.go | 23 - ...umption_budget_management_group_id_test.go | 63 - .../consumption_budget_resource_group_id.go | 23 - ...nsumption_budget_resource_group_id_test.go | 76 - .../consumption_budget_subscription_id.go | 23 - ...consumption_budget_subscription_id_test.go | 64 - internal/services/containers/client/client.go | 12 +- .../container_connected_registry_resource.go | 2 +- .../containers/container_group_data_source.go | 4 +- .../containers/container_group_resource.go | 32 +- .../container_registry_agent_pool_resource.go | 2 +- .../containers/container_registry_resource.go | 169 +- .../container_registry_resource_test.go | 152 +- .../container_registry_scope_map_resource.go | 2 +- .../container_registry_task_resource.go | 232 +- ...registry_task_schedule_run_now_resource.go | 164 + ...try_task_schedule_run_now_resource_test.go | 149 + .../container_registry_token_data_source.go | 2 +- .../container_registry_token_resource.go | 2 +- .../container_registry_webhook_resource.go | 2 +- .../services/containers/kubernetes_addons.go | 9 +- .../kubernetes_cluster_auth_resource_test.go | 45 + .../kubernetes_cluster_data_source.go | 6 +- .../kubernetes_cluster_data_source_test.go | 26 + .../kubernetes_cluster_node_pool_resource.go | 16 +- .../kubernetes_cluster_other_resource_test.go | 2 +- .../containers/kubernetes_cluster_resource.go | 6 +- .../kubernetes_cluster_resource_test.go | 19 +- .../kubernetes_cluster_upgrade_test.go | 54 + .../containers/kubernetes_nodepool.go | 4 +- .../parse/container_registry_task_schedule.go | 81 + .../container_registry_task_schedule_test.go | 144 + internal/services/containers/registration.go | 1 + internal/services/containers/resourceids.go | 1 + .../container_registry_task_schedule_id.go | 23 + ...ontainer_registry_task_schedule_id_test.go | 100 + internal/services/cosmos/client/client.go | 6 + .../cosmos/common/autoscale_settings.go | 10 +- .../cosmosdb_cassandra_cluster_resource.go | 5 +- ...cosmosdb_sql_dedicated_gateway_resource.go | 224 + ...sdb_sql_dedicated_gateway_resource_test.go | 158 + internal/services/cosmos/registration.go | 15 +- .../services/costmanagement/client/client.go | 6 +- .../costmanagement/export_base_resource.go | 178 +- .../export_resource_group_resource_test.go | 9 +- .../export_subscription_resource_test.go | 9 +- internal/services/dashboard/client/client.go | 20 + .../dashboard/dashboard_grafana_resource.go | 433 + .../dashboard_grafana_resource_test.go | 182 + internal/services/dashboard/registration.go | 51 + .../databricks_workspace_resource.go | 8 +- internal/services/datadog/client/client.go | 19 + .../datadog/datadog_monitors_resource.go | 429 + .../datadog/datadog_monitors_resource_test.go | 303 + .../services/datadog/parse/datadog_monitor.go | 69 + .../datadog/parse/datadog_monitor_test.go | 112 + internal/services/datadog/registration.go | 29 + internal/services/datadog/resourceids.go | 3 + .../datadog/validate/datadog_email_address.go | 19 + .../validate/datadog_email_address_test.go | 38 + .../datadog/validate/datadog_monitor_id.go | 23 + .../validate/datadog_monitor_id_test.go | 76 + .../datadog/validate/datadog_monitor_name.go | 20 + .../validate/datadog_monitor_name_test.go | 61 + .../datadog/validate/datadog_phone_number.go | 18 + .../validate/datadog_phone_number_test.go | 31 + .../datadog/validate/datadog_users_name.go | 22 + .../validate/datadog_users_name_test.go | 31 + .../datafactory/data_factory_data_flow.go | 97 + .../data_factory_data_flow_resource_test.go | 86 +- .../data_factory_dataset_json_resource.go | 10 +- ...data_factory_dataset_json_resource_test.go | 72 + ...data_factory_flowlet_data_flow_resource.go | 233 + ...factory_flowlet_data_flow_resource_test.go | 412 + ...integration_runtime_azure_ssis_resource.go | 49 +- ...ration_runtime_azure_ssis_resource_test.go | 58 + internal/services/datafactory/registration.go | 1 + .../services/dataprotection/client/client.go | 16 +- ...n_backup_instance_blob_storage_resource.go | 80 +- ...kup_instance_blob_storage_resource_test.go | 11 +- ...rotection_backup_instance_disk_resource.go | 102 +- ...tion_backup_instance_disk_resource_test.go | 9 +- ...ion_backup_instance_postgresql_resource.go | 123 +- ...ackup_instance_postgresql_resource_test.go | 11 +- ...ion_backup_policy_blob_storage_resource.go | 88 +- ...ackup_policy_blob_storage_resource_test.go | 9 +- ..._protection_backup_policy_disk_resource.go | 237 +- ...ection_backup_policy_disk_resource_test.go | 9 +- ...ction_backup_policy_postgresql_resource.go | 308 +- ..._backup_policy_postgresql_resource_test.go | 9 +- ...ata_protection_backup_vault_data_source.go | 53 +- ...rotection_backup_vault_data_source_test.go | 9 +- .../data_protection_backup_vault_resource.go | 102 +- ...a_protection_backup_vault_resource_test.go | 9 +- .../dataprotection/backupinstances.go | 927 -- .../dataprotection/backuppolicies.go | 384 - .../backupvaultoperationresults.go | 110 - .../legacysdk/dataprotection/backupvaults.go | 666 - .../legacysdk/dataprotection/client.go | 41 - .../dataprotection/dataprotection.go | 108 - .../legacysdk/dataprotection/enums.go | 690 -- .../legacysdk/dataprotection/exportjobs.go | 109 - .../exportjobsoperationresult.go | 113 - .../legacysdk/dataprotection/jobs.go | 228 - .../legacysdk/dataprotection/models.go | 6462 ---------- .../dataprotection/operationresult.go | 105 - .../legacysdk/dataprotection/operations.go | 141 - .../dataprotection/operationstatus.go | 105 - .../dataprotection/recoverypoints.go | 239 - .../dataprotection/resourceguards.go | 1730 --- .../dataprotection/restorabletimeranges.go | 114 - .../legacysdk/dataprotection/version.go | 19 - .../dataprotection/parse/backup_instance.go | 75 - .../parse/backup_instance_test.go | 128 - .../dataprotection/parse/backup_policy.go | 75 - .../parse/backup_policy_test.go | 128 - .../services/dataprotection/resourceids.go | 5 - .../services/dataprotection/transition.go | 23 + .../validate/backup_instance_id.go | 23 - .../validate/backup_instance_id_test.go | 88 - .../validate/backup_policy_id.go | 23 - .../validate/backup_policy_id_test.go | 88 - .../validate/backup_vault_id.go | 23 - .../validate/backup_vault_id_test.go | 76 - ...isk_pool_iscsi_target_lun_resource_test.go | 4 +- internal/services/dns/client/client.go | 24 +- .../services/dns/dns_a_record_data_source.go | 106 + .../dns/dns_a_record_data_source_test.go | 44 + .../services/dns/dns_a_record_resource.go | 120 +- .../dns/dns_a_record_resource_test.go | 11 +- .../dns/dns_aaaa_record_data_source.go | 107 + .../dns/dns_aaaa_record_data_source_test.go | 44 + .../services/dns/dns_aaaa_record_resource.go | 124 +- .../dns/dns_aaaa_record_resource_test.go | 11 +- .../dns/dns_caa_record_data_source.go | 112 + .../dns/dns_caa_record_data_source_test.go | 43 + .../services/dns/dns_caa_record_resource.go | 131 +- .../dns/dns_caa_record_resource_test.go | 11 +- .../dns/dns_cname_record_data_source.go | 107 + .../dns/dns_cname_record_data_source_test.go | 43 + .../services/dns/dns_cname_record_resource.go | 115 +- .../dns/dns_cname_record_resource_test.go | 11 +- .../services/dns/dns_mx_record_data_source.go | 108 + .../dns/dns_mx_record_data_source_test.go | 43 + .../services/dns/dns_mx_record_resource.go | 122 +- .../dns/dns_mx_record_resource_test.go | 11 +- .../services/dns/dns_ns_record_data_source.go | 96 + .../dns/dns_ns_record_data_source_test.go | 43 + .../services/dns/dns_ns_record_resource.go | 138 +- .../dns/dns_ns_record_resource_test.go | 11 +- .../dns/dns_ptr_record_data_source.go | 95 + .../dns/dns_ptr_record_data_source_test.go | 43 + .../services/dns/dns_ptr_record_resource.go | 121 +- .../dns/dns_ptr_record_resource_test.go | 11 +- .../dns/dns_soa_record_data_source.go | 129 + .../dns/dns_soa_record_data_source_test.go | 72 + .../dns/dns_srv_record_data_source.go | 116 + .../dns/dns_srv_record_data_source_test.go | 43 + .../services/dns/dns_srv_record_resource.go | 145 +- .../dns/dns_srv_record_resource_test.go | 11 +- .../dns/dns_txt_record_data_source.go | 102 + .../dns/dns_txt_record_data_source_test.go | 43 + .../services/dns/dns_txt_record_resource.go | 118 +- .../dns/dns_txt_record_resource_test.go | 11 +- internal/services/dns/dns_zone_data_source.go | 98 +- internal/services/dns/dns_zone_resource.go | 268 +- .../services/dns/dns_zone_resource_test.go | 10 +- .../dns/migration/dns_zone_V0_to_V1.go | 10 +- internal/services/dns/parse/a_record.go | 75 - internal/services/dns/parse/a_record_test.go | 128 - internal/services/dns/parse/aaaa_record.go | 75 - .../services/dns/parse/aaaa_record_test.go | 128 - internal/services/dns/parse/caa_record.go | 75 - .../services/dns/parse/caa_record_test.go | 128 - internal/services/dns/parse/cname_record.go | 75 - .../services/dns/parse/cname_record_test.go | 128 - internal/services/dns/parse/dns_zone.go | 69 - internal/services/dns/parse/dns_zone_test.go | 112 - internal/services/dns/parse/mx_record.go | 75 - internal/services/dns/parse/mx_record_test.go | 128 - internal/services/dns/parse/ns_record.go | 75 - internal/services/dns/parse/ns_record_test.go | 128 - internal/services/dns/parse/ptr_record.go | 75 - .../services/dns/parse/ptr_record_test.go | 128 - internal/services/dns/parse/soa_record.go | 75 + internal/services/dns/parse/srv_record.go | 75 - .../services/dns/parse/srv_record_test.go | 128 - internal/services/dns/parse/txt_record.go | 75 - .../services/dns/parse/txt_record_test.go | 128 - internal/services/dns/registration.go | 12 +- internal/services/dns/resourceids.go | 12 - internal/services/dns/validate/a_record_id.go | 23 - .../services/dns/validate/a_record_id_test.go | 88 - .../services/dns/validate/aaaa_record_id.go | 23 - .../dns/validate/aaaa_record_id_test.go | 88 - .../services/dns/validate/caa_record_id.go | 23 - .../dns/validate/caa_record_id_test.go | 88 - .../services/dns/validate/cname_record_id.go | 23 - .../dns/validate/cname_record_id_test.go | 88 - internal/services/dns/validate/dns_zone_id.go | 23 - .../services/dns/validate/dns_zone_id_test.go | 76 - .../services/dns/validate/mx_record_id.go | 23 - .../dns/validate/mx_record_id_test.go | 88 - .../services/dns/validate/ns_record_id.go | 23 - .../dns/validate/ns_record_id_test.go | 88 - .../services/dns/validate/ptr_record_id.go | 23 - .../dns/validate/ptr_record_id_test.go | 88 - .../services/dns/validate/srv_record_id.go | 23 - .../dns/validate/srv_record_id_test.go | 88 - .../services/dns/validate/txt_record_id.go | 23 - .../dns/validate/txt_record_id_test.go | 88 - ...ve_directory_domain_service_data_source.go | 53 +- ...ory_domain_service_replica_set_resource.go | 131 +- ...ctive_directory_domain_service_resource.go | 314 +- .../active_directory_domain_service_test.go | 41 +- ...directory_domain_service_trust_resource.go | 130 +- ...tory_domain_service_trust_resource_test.go | 19 +- .../services/domainservices/client/client.go | 6 +- internal/services/eventhub/client/client.go | 24 +- ...eventhub_authorization_rule_data_source.go | 4 +- .../eventhub_authorization_rule_resource.go | 4 +- ...enthub_authorization_rule_resource_test.go | 2 +- .../eventhub/eventhub_cluster_data_source.go | 2 +- .../eventhub/eventhub_cluster_resource.go | 2 +- .../eventhub_cluster_resource_test.go | 2 +- .../eventhub_consumer_group_data_source.go | 2 +- .../eventhub_consumer_group_resource.go | 2 +- .../eventhub_consumer_group_resource_test.go | 2 +- .../services/eventhub/eventhub_data_source.go | 2 +- ...amespace_authorization_rule_data_source.go | 2 +- ...b_namespace_authorization_rule_resource.go | 2 +- ...espace_authorization_rule_resource_test.go | 2 +- ...namespace_customer_managed_key_resource.go | 2 +- ...pace_customer_managed_key_resource_test.go | 2 +- .../eventhub_namespace_data_source.go | 4 +- ...space_disaster_recovery_config_resource.go | 4 +- ..._disaster_recovery_config_resource_test.go | 2 +- .../eventhub/eventhub_namespace_resource.go | 218 +- .../eventhub_namespace_resource_test.go | 124 +- ...thub_namespace_schema_registry_resource.go | 180 + ...namespace_schema_registry_resource_test.go | 71 + .../services/eventhub/eventhub_resource.go | 4 +- .../eventhub/eventhub_resource_test.go | 2 +- .../eventhub/migration/consumer_group.go | 2 +- .../migration/eventhub_authorization_rule.go | 2 +- internal/services/eventhub/registration.go | 1 + .../eventhub/validate/eventhub_names.go | 7 + .../firewall/firewall_policy_resource.go | 50 +- .../firewall/firewall_policy_resource_test.go | 20 +- .../services/firewall/firewall_resource.go | 1 - .../firewall/firewall_resource_test.go | 80 + .../services/hdinsight/common_hdinsight.go | 11 + .../hdinsight_hadoop_cluster_resource.go | 111 +- .../hdinsight_hadoop_cluster_resource_test.go | 92 +- .../hdinsight_hbase_cluster_resource.go | 19 + .../hdinsight_hbase_cluster_resource_test.go | 177 +- ...ight_interactive_query_cluster_resource.go | 19 + ...interactive_query_cluster_resource_test.go | 75 + .../hdinsight_kafka_cluster_resource.go | 19 + .../hdinsight_kafka_cluster_resource_test.go | 77 + .../hdinsight_spark_cluster_resource.go | 19 + .../hdinsight_spark_cluster_resource_test.go | 105 +- internal/services/hdinsight/schema.go | 184 + internal/services/healthcare/client/client.go | 26 +- .../healthcare_medtech_service_data_source.go | 130 + ...thcare_medtech_service_data_source_test.go | 35 + ...dtech_service_fhir_destination_resource.go | 292 + ..._service_fhir_destination_resource_test.go | 233 + .../healthcare_medtech_service_resource.go | 405 + ...ealthcare_medtech_service_resource_test.go | 329 + .../healthcare/parse/med_tech_service.go | 75 + .../med_tech_service_fhir_destination.go | 81 + .../med_tech_service_fhir_destination_test.go | 144 + .../healthcare/parse/med_tech_service_test.go | 128 + internal/services/healthcare/registration.go | 19 +- internal/services/healthcare/resourceids.go | 3 + .../med_tech_service_fhir_destination_id.go | 23 + ...d_tech_service_fhir_destination_id_test.go | 100 + .../validate/med_tech_service_id.go | 23 + .../validate/med_tech_service_id_test.go | 88 + .../validate/medtech_service_name.go | 16 + ...cated_hardware_security_module_resource.go | 6 +- .../iothub/iothub_dps_certificate_resource.go | 18 + .../iothub_dps_certificate_resource_test.go | 48 + .../services/iothub/iothub_dps_resource.go | 15 + .../iothub/iothub_dps_resource_test.go | 44 + .../services/keyvault/access_policy_schema.go | 4 + .../key_vault_access_policy_data_source.go | 53 +- .../key_vault_certificate_data_source.go | 3 +- .../key_vault_certificate_resource.go | 3 +- .../keyvault/key_vault_data_source.go | 9 + .../keyvault/key_vault_data_source_test.go | 11 - .../keyvault/key_vault_key_data_source.go | 3 +- .../keyvault/key_vault_key_resource.go | 3 +- .../services/keyvault/key_vault_resource.go | 27 + .../keyvault/key_vault_resource_test.go | 7 +- .../keyvault/key_vault_secret_data_source.go | 3 +- .../keyvault/key_vault_secret_resource.go | 3 +- .../services/keyvault/migration/key_vault.go | 4 + internal/services/kusto/client/client.go | 5 + ...uster_managed_private_endpoint_resource.go | 191 + ..._managed_private_endpoint_resource_test.go | 145 + .../services/kusto/kusto_cluster_resource.go | 82 +- .../kusto/kusto_cluster_resource_test.go | 18 +- ...usto_eventgrid_data_connection_resource.go | 2 +- ...kusto_eventhub_data_connection_resource.go | 2 +- .../kusto/parse/managed_private_endpoints.go | 75 + .../parse/managed_private_endpoints_test.go | 128 + internal/services/kusto/registration.go | 21 +- internal/services/kusto/resourceids.go | 1 + .../validate/managed_private_endpoints_id.go | 23 + .../managed_private_endpoints_id_test.go | 88 + .../backend_address_pool_address_resource.go | 116 +- ...kend_address_pool_address_resource_test.go | 244 +- .../services/loganalytics/client/client.go | 64 +- .../loganalytics/log_analytics_cluster.go | 32 +- ...s_cluster_customer_managed_key_resource.go | 114 +- ...ster_customer_managed_key_resource_test.go | 14 +- .../log_analytics_cluster_resource.go | 173 +- .../log_analytics_cluster_resource_test.go | 12 +- .../log_analytics_data_export_resource.go | 121 +- ...log_analytics_data_export_resource_test.go | 55 +- .../log_analytics_datasource_import.go | 13 +- ...ytics_datasource_windows_event_resource.go | 63 +- ..._datasource_windows_event_resource_test.go | 8 +- ...ce_windows_performance_counter_resource.go | 67 +- ...ndows_performance_counter_resource_test.go | 8 +- .../log_analytics_linked_service.go | 21 +- .../log_analytics_linked_service_resource.go | 74 +- ..._analytics_linked_service_resource_test.go | 8 +- ...alytics_linked_storage_account_resource.go | 71 +- ...cs_linked_storage_account_resource_test.go | 10 +- ...log_analytics_query_pack_query_resource.go | 593 + ...nalytics_query_pack_query_resource_test.go | 262 + .../log_analytics_query_pack_resource.go | 205 + .../log_analytics_query_pack_resource_test.go | 138 + .../log_analytics_saved_search_resource.go | 83 +- ...og_analytics_saved_search_resource_test.go | 8 +- .../log_analytics_solution_resource.go | 128 +- .../log_analytics_solution_resource_test.go | 8 +- ...log_analytics_storage_insights_resource.go | 81 +- ...nalytics_storage_insights_resource_test.go | 8 +- .../log_analytics_workspace_data_source.go | 82 +- .../log_analytics_workspace_resource.go | 235 +- .../log_analytics_workspace_resource_test.go | 52 +- .../migration/ds_windows_event.go | 4 +- .../ds_windows_performance_counter.go | 4 +- .../migration/saved_search_v0_to_v1.go | 7 +- .../migration/workspace_v0_to_v1.go | 9 +- .../migration/workspace_v1_to_v2.go | 4 +- .../loganalytics/parse/data_source.go | 131 - .../loganalytics/parse/data_source_test.go | 264 - .../parse/log_analytics_cluster.go | 69 - .../parse/log_analytics_cluster_test.go | 112 - .../parse/log_analytics_data_export.go | 75 - .../parse/log_analytics_data_export_test.go | 128 - .../parse/log_analytics_linked_service.go | 75 - .../log_analytics_linked_service_test.go | 128 - .../log_analytics_linked_storage_account.go | 75 - ...g_analytics_linked_storage_account_test.go | 128 - .../parse/log_analytics_saved_search.go | 75 - .../parse/log_analytics_saved_search_test.go | 128 - .../parse/log_analytics_solution.go | 69 - .../parse/log_analytics_solution_test.go | 112 - .../parse/log_analytics_storage_insights.go | 75 - .../log_analytics_storage_insights_test.go | 128 - .../parse/log_analytics_workspace.go | 69 - .../parse/log_analytics_workspace_test.go | 112 - .../services/loganalytics/registration.go | 16 +- internal/services/loganalytics/resourceids.go | 12 - internal/services/loganalytics/transition.go | 23 + .../loganalytics/validate/data_source_id.go | 23 - .../validate/data_source_id_test.go | 88 - .../validate/log_analytics_cluster_id.go | 23 - .../validate/log_analytics_cluster_id_test.go | 76 - .../validate/log_analytics_data_export_id.go | 23 - .../log_analytics_data_export_id_test.go | 88 - .../log_analytics_linked_service_id.go | 23 - .../log_analytics_linked_service_id_test.go | 88 - ...log_analytics_linked_storage_account_id.go | 23 - ...nalytics_linked_storage_account_id_test.go | 88 - .../validate/log_analytics_saved_search_id.go | 23 - .../log_analytics_saved_search_id_test.go | 88 - .../validate/log_analytics_solution_id.go | 23 - .../log_analytics_solution_id_test.go | 76 - .../log_analytics_storage_insights_id.go | 23 - .../log_analytics_storage_insights_id_test.go | 88 - .../validate/log_analytics_workspace_id.go | 23 - .../log_analytics_workspace_id_test.go | 76 - ...ation_service_environment_resource_test.go | 8 +- internal/services/logz/client/client.go | 17 +- internal/services/logz/logz_common.go | 33 + .../logz_sub_account_tag_rule_resource.go | 154 + ...logz_sub_account_tag_rule_resource_test.go | 204 + .../services/logz/logz_tag_rule_resource.go | 34 +- .../logz/parse/logz_sub_account_tag_rule.go | 81 + .../parse/logz_sub_account_tag_rule_test.go | 144 + internal/services/logz/registration.go | 7 +- internal/services/logz/resourceids.go | 1 + .../validate/logz_sub_account_tag_rule_id.go | 23 + .../logz_sub_account_tag_rule_id_test.go | 100 + .../services/maintenance/client/client.go | 16 +- ...ance_assignment_dedicated_host_resource.go | 105 +- ...assignment_dedicated_host_resource_test.go | 9 +- ...nce_assignment_virtual_machine_resource.go | 99 +- ...ssignment_virtual_machine_resource_test.go | 13 +- ...ment_virtual_machine_scale_set_resource.go | 103 +- ...virtual_machine_scale_set_resource_test.go | 11 +- .../maintenance_configuration_data_source.go | 41 +- .../maintenance_configuration_resource.go | 112 +- ...maintenance_configuration_resource_test.go | 18 +- .../migration/configuration_v0_to_v1.go | 4 +- .../maintenance_assignment_dedicated_host.go | 8 +- ...ntenance_assignment_dedicated_host_test.go | 12 +- .../parse/maintenance_configuration.go | 113 - .../parse/maintenance_configuration_test.go | 229 - .../parse/public_maintenance_configuration.go | 61 - .../public_maintenance_configuration_test.go | 96 - ..._maintenance_configurations_data_source.go | 109 +- internal/services/maintenance/resourceids.go | 4 - internal/services/maintenance/transition.go | 23 + .../validate/maintenance_configuration_id.go | 23 - .../maintenance_configuration_id_test.go | 76 - .../public_maintenance_configuration_id.go | 23 - ...ublic_maintenance_configuration_id_test.go | 64 - .../management_group_data_source.go | 80 +- .../management_group_data_source_test.go | 43 + internal/services/mariadb/client/client.go | 26 +- .../mariadb/mariadb_configuration_resource.go | 70 +- .../mariadb_configuration_resource_test.go | 64 +- .../mariadb/mariadb_database_resource.go | 68 +- .../mariadb/mariadb_database_resource_test.go | 8 +- .../mariadb/mariadb_firewall_rule_resource.go | 58 +- .../mariadb_firewall_rule_resource_test.go | 8 +- .../mariadb/mariadb_server_data_source.go | 65 +- .../mariadb/mariadb_server_resource.go | 272 +- .../mariadb/mariadb_server_resource_test.go | 10 +- .../mariadb_virtual_network_rule_resource.go | 73 +- ...iadb_virtual_network_rule_resource_test.go | 8 +- .../mariadb/parse/maria_db_configuration.go | 75 - .../parse/maria_db_configuration_test.go | 128 - .../mariadb/parse/maria_db_database.go | 75 - .../mariadb/parse/maria_db_database_test.go | 128 - .../mariadb/parse/maria_db_firewall_rule.go | 75 - .../parse/maria_db_firewall_rule_test.go | 128 - .../parse/maria_db_virtual_network_rule.go | 75 - .../maria_db_virtual_network_rule_test.go | 128 - internal/services/mariadb/parse/server.go | 69 - .../services/mariadb/parse/server_test.go | 112 - internal/services/mariadb/resourceids.go | 7 - .../validate/maria_db_configuration_id.go | 23 - .../maria_db_configuration_id_test.go | 88 - .../mariadb/validate/maria_db_database_id.go | 23 - .../validate/maria_db_database_id_test.go | 88 - .../validate/maria_db_firewall_rule_id.go | 23 - .../maria_db_firewall_rule_id_test.go | 88 - .../maria_db_virtual_network_rule_id.go | 23 - .../maria_db_virtual_network_rule_id_test.go | 88 - .../services/mariadb/validate/server_id.go | 23 - .../mariadb/validate/server_id_test.go | 76 - internal/services/monitor/client/client.go | 28 +- ...monitor_aad_diagnostic_setting_resource.go | 9 +- .../monitor_action_group_data_source.go | 2 +- .../monitor/monitor_action_group_resource.go | 2 +- ...or_data_collection_endpoint_data_source.go | 135 + ...ta_collection_endpoint_data_source_test.go | 39 + ...nitor_data_collection_endpoint_resource.go | 319 + ..._data_collection_endpoint_resource_test.go | 158 + .../monitor_data_collection_rule_resource.go | 1016 ++ ...itor_data_collection_rule_resource_test.go | 387 + ...nitor_diagnostic_categories_data_source.go | 80 +- ..._diagnostic_categories_data_source_test.go | 4 + .../monitor_diagnostic_setting_resource.go | 290 +- ...onitor_diagnostic_setting_resource_test.go | 159 +- ...or_private_link_scoped_service_resource.go | 4 +- ...scheduled_query_rules_alert_v2_resource.go | 895 ++ ...uled_query_rules_alert_v2_resource_test.go | 296 + internal/services/monitor/registration.go | 19 +- internal/services/msi/client/client.go | 6 +- .../msi/user_assigned_identity_resource.go | 4 +- .../mssql/mssql_elasticpool_resource.go | 29 +- .../mssql/mssql_elasticpool_resource_test.go | 2 + .../mssql/mssql_managed_instance_resource.go | 12 +- .../mssql/mssql_server_dns_alias_resource.go | 7 +- .../services/mssql/mssql_server_resource.go | 13 +- .../mssql/mssql_server_resource_test.go | 42 + .../mssql/mssql_virtual_machine_resource.go | 73 +- .../netapp/netapp_snapshot_resource.go | 2 +- .../services/netapp/netapp_volume_resource.go | 4 +- .../network/application_gateway_resource.go | 117 +- .../application_gateway_resource_test.go | 237 + .../express_route_circuit_peering_resource.go | 113 +- .../network_connection_monitor_resource.go | 6 +- ...ual_machine_scale_set_public_ip_address.go | 93 + ...achine_scale_set_public_ip_address_test.go | 176 + .../network/private_endpoint_resource.go | 214 +- .../network/private_endpoint_resource_test.go | 80 +- internal/services/network/registration.go | 2 + internal/services/network/resourceids.go | 3 + .../route_server_bgp_connection_resource.go | 170 + ...ute_server_bgp_connection_resource_test.go | 83 + .../services/network/route_server_resource.go | 343 + .../network/route_server_resource_test.go | 183 + .../services/network/subnet_data_source.go | 33 +- internal/services/network/subnet_resource.go | 222 +- .../services/network/subnet_resource_test.go | 327 +- .../network/validate/route_server_name.go | 19 + ..._machine_scale_set_public_ip_address_id.go | 23 + ...ine_scale_set_public_ip_address_id_test.go | 124 + .../web_application_firewall_policy.go | 8 + ...eb_application_firewall_policy_resource.go | 158 +- ...plication_firewall_policy_resource_test.go | 244 + internal/services/policy/client/client.go | 10 +- .../policy/remediation_management_group.go | 91 +- .../remediation_management_group_test.go | 8 +- .../services/policy/remediation_resource.go | 124 +- .../policy/remediation_resource_group.go | 71 +- .../policy/remediation_resource_group_test.go | 11 +- .../policy/remediation_resource_test.go | 9 +- .../policy/remediation_subscription.go | 70 +- .../policy/remediation_subscription_test.go | 15 +- internal/services/postgres/client/client.go | 73 +- .../migration/postgresql_aad_administrator.go | 69 + .../postgres/migration/postgresql_database.go | 74 + .../postgres/migration/postgresql_server.go | 264 + .../services/postgres/parse/configuration.go | 75 - .../postgres/parse/configuration_test.go | 128 - internal/services/postgres/parse/database.go | 75 - .../services/postgres/parse/database_test.go | 128 - .../services/postgres/parse/firewall_rule.go | 75 - .../postgres/parse/firewall_rule_test.go | 128 - .../postgres/parse/flexible_server.go | 69 - .../parse/flexible_server_configuration.go | 75 - .../flexible_server_configuration_test.go | 128 - .../parse/flexible_server_database.go | 75 - .../parse/flexible_server_database_test.go | 128 - .../parse/flexible_server_firewall_rule.go | 75 - .../flexible_server_firewall_rule_test.go | 128 - .../postgres/parse/flexible_server_test.go | 112 - internal/services/postgres/parse/server.go | 69 - .../services/postgres/parse/server_key.go | 75 - .../postgres/parse/server_key_test.go | 128 - .../services/postgres/parse/server_test.go | 112 - .../postgres/parse/virtual_network_rule.go | 75 - .../parse/virtual_network_rule_test.go | 128 - .../postgresql_aad_administrator_resource.go | 77 +- ...tgresql_aad_administrator_resource_test.go | 13 +- .../postgresql_configuration_resource.go | 59 +- .../postgresql_configuration_resource_test.go | 47 +- .../postgres/postgresql_database_resource.go | 58 +- .../postgresql_database_resource_test.go | 10 +- .../postgresql_firewall_rule_resource.go | 55 +- .../postgresql_firewall_rule_resource_test.go | 8 +- ..._flexible_server_configuration_resource.go | 68 +- ...ible_server_configuration_resource_test.go | 34 +- .../postgresql_flexible_server_data_source.go | 74 +- ...resql_flexible_server_database_resource.go | 55 +- ..._flexible_server_database_resource_test.go | 8 +- ..._flexible_server_firewall_rule_resource.go | 58 +- ...ible_server_firewall_rule_resource_test.go | 10 +- .../postgresql_flexible_server_resource.go | 343 +- ...ostgresql_flexible_server_resource_test.go | 10 +- .../postgres/postgresql_server_data_source.go | 46 +- .../postgresql_server_key_resource.go | 65 +- .../postgresql_server_key_resource_test.go | 8 +- .../postgres/postgresql_server_resource.go | 566 +- .../postgresql_server_resource_test.go | 8 +- ...ostgresql_virtual_network_rule_resource.go | 76 +- ...esql_virtual_network_rule_resource_test.go | 21 +- internal/services/postgres/resourceids.go | 10 - .../postgres/validate/configuration_id.go | 23 - .../validate/configuration_id_test.go | 88 - .../services/postgres/validate/database_id.go | 23 - .../postgres/validate/database_id_test.go | 88 - .../postgres/validate/firewall_rule_id.go | 23 - .../validate/firewall_rule_id_test.go | 88 - .../flexible_server_configuration_id.go | 23 - .../flexible_server_configuration_id_test.go | 88 - .../validate/flexible_server_database_id.go | 23 - .../flexible_server_database_id_test.go | 88 - .../flexible_server_firewall_rule_id.go | 23 - .../flexible_server_firewall_rule_id_test.go | 88 - .../postgres/validate/flexible_server_id.go | 23 - .../validate/flexible_server_id_test.go | 76 - .../services/postgres/validate/server_id.go | 23 - .../postgres/validate/server_id_test.go | 76 - .../postgres/validate/server_key_id.go | 23 - .../postgres/validate/server_key_id_test.go | 88 - .../validate/virtual_network_rule_id.go | 23 - .../validate/virtual_network_rule_id_test.go | 88 - .../private_dns_a_record_data_source.go | 95 + .../private_dns_a_record_data_source_test.go | 43 + .../private_dns_a_record_resource.go | 6 +- .../private_dns_aaaa_record_data_source.go | 96 + ...rivate_dns_aaaa_record_data_source_test.go | 43 + .../private_dns_aaaa_record_resource.go | 6 +- .../private_dns_cname_record_data_source.go | 101 + ...ivate_dns_cname_record_data_source_test.go | 43 + .../private_dns_mx_record_data_source.go | 106 + .../private_dns_mx_record_data_source_test.go | 43 + .../private_dns_mx_record_resource.go | 12 + .../private_dns_ptr_record_data_source.go | 95 + ...private_dns_ptr_record_data_source_test.go | 43 + .../private_dns_soa_record_data_source.go | 129 + ...private_dns_soa_record_data_source_test.go | 71 + .../private_dns_srv_record_data_source.go | 116 + ...private_dns_srv_record_data_source_test.go | 43 + .../private_dns_srv_record_resource.go | 14 + .../private_dns_txt_record_data_source.go | 102 + ...private_dns_txt_record_data_source_test.go | 43 + .../private_dns_zone_data_source.go | 16 +- .../private_dns_zone_data_source_test.go | 63 +- internal/services/privatedns/registration.go | 10 +- .../backup_policy_vm_resource.go | 10 + .../backup_policy_vm_workload_resource.go | 1096 ++ ...backup_policy_vm_workload_resource_test.go | 319 + .../services/recoveryservices/registration.go | 15 +- .../site_recovery_replicated_vm_resource.go | 134 + ...te_recovery_replicated_vm_resource_test.go | 274 + .../validate/backup_policy_name.go | 16 + .../validate/backup_policy_name_test.go | 56 + .../services/redis/redis_cache_resource.go | 15 + .../redis/redis_cache_resource_test.go | 50 + ...group_template_deployment_resource_test.go | 94 + .../resource/template_deployment_common.go | 24 +- .../resource/template_deployment_resource.go | 7 +- internal/services/search/client/client.go | 18 +- internal/services/search/registration.go | 15 +- .../search/search_service_resource.go | 18 +- ...ch_shared_private_link_service_resource.go | 239 + ...ared_private_link_service_resource_test.go | 121 + .../iot_security_solution_resource.go | 6 +- ...erver_vulnerability_assessment_resource.go | 2 +- .../security_center_workspace_resource.go | 6 +- internal/services/sentinel/registration.go | 1 + .../services/sentinel/sentinel_alert_rule.go | 311 + .../sentinel_alert_rule_data_source.go | 11 +- .../sentinel_alert_rule_fusion_resource.go | 17 +- ...ule_machine_learning_behavior_analytics.go | 17 +- ...lert_rule_ms_security_incident_resource.go | 17 +- .../sentinel_alert_rule_nrt_resource.go | 470 + .../sentinel_alert_rule_nrt_resource_test.go | 284 + .../sentinel_alert_rule_scheduled_resource.go | 321 +- ...entinel_alert_rule_template_data_source.go | 101 +- ...el_alert_rule_template_data_source_test.go | 27 +- .../sentinel_automation_rule_resource.go | 11 +- ...sentinel_data_connector_aws_cloud_trail.go | 11 +- ...sentinel_data_connector_aws_s3_resource.go | 11 +- ...l_data_connector_azure_active_directory.go | 11 +- ...nector_azure_advanced_threat_protection.go | 11 +- ...el_data_connector_azure_security_center.go | 11 +- ..._connector_microsoft_cloud_app_security.go | 11 +- ...oft_defender_advanced_threat_protection.go | 11 +- .../sentinel_data_connector_office_365.go | 11 +- ...inel_data_connector_threat_intelligence.go | 11 +- .../sentinel/sentinel_watchlist_resource.go | 11 +- internal/services/servicebus/client/client.go | 2 +- internal/services/servicebus/internal.go | 2 +- .../migration/namespace_auth_rule.go | 98 + .../migration/namespace_network_rule_set.go | 2 +- ...amespace_authorization_rule_data_source.go | 2 +- ...s_namespace_authorization_rule_resource.go | 8 +- .../servicebus_namespace_data_source.go | 2 +- ...ce_disaster_recovery_config_data_source.go | 2 +- ...bus_namespace_network_rule_set_resource.go | 22 +- ...amespace_network_rule_set_resource_test.go | 2 +- .../servicebus_namespace_resource.go | 84 +- .../servicebus_namespace_resource_test.go | 88 +- ...cebus_queue_authorization_rule_resource.go | 2 +- .../servicebus_queue_data_source.go | 27 +- .../servicebus_queue_data_source_test.go | 39 + .../servicebus/servicebus_queue_resource.go | 2 +- .../servicebus_subscription_resource.go | 110 +- .../servicebus_subscription_resource_test.go | 48 + .../servicebus_subscription_rule_resource.go | 9 + ...cebus_topic_authorization_rule_resource.go | 2 +- .../servicebus_topic_data_source.go | 2 +- .../servicebus/servicebus_topic_resource.go | 4 +- .../servicebus_topic_resource_test.go | 2 +- .../serviceconnector/client/client.go | 25 + internal/services/serviceconnector/helper.go | 277 + .../services/serviceconnector/registration.go | 28 + .../service_connector_app_service_resource.go | 277 + ...ice_connector_app_service_resource_test.go | 220 + ...service_connector_spring_cloud_resource.go | 279 + ...ce_connector_spring_cloud_resource_test.go | 238 + ...service_fabric_managed_cluster_resource.go | 14 +- internal/services/signalr/client/client.go | 22 +- .../migration/web_pubsub_hub_v0_to_v1.go | 98 + .../signalr/migration/web_pubsub_v0_to_v1.go | 200 + internal/services/signalr/parse/web_pubsub.go | 48 +- .../services/signalr/parse/web_pubsub_hub.go | 60 +- .../signalr/parse/web_pubsub_hub_test.go | 146 +- ...web_pubsub_shared_private_link_resource.go | 75 + ...ubsub_shared_private_link_resource_test.go | 128 + .../services/signalr/parse/web_pubsub_test.go | 123 +- internal/services/signalr/registration.go | 17 +- internal/services/signalr/resourceids.go | 5 +- .../signalr/signalr_service_resource_test.go | 4 +- .../signalr_shared_private_link_resource.go | 177 + ...gnalr_shared_private_link_resource_test.go | 179 + .../validate/web_pubsub_hub_id_test.go | 8 +- .../signalr/validate/web_pubsub_id_test.go | 4 +- ..._pubsub_shared_private_link_resource_id.go | 23 + ...ub_shared_private_link_resource_id_test.go | 88 + .../signalr/web_pubsub_hub_resource.go | 6 + .../web_pubsub_network_acl_resource_test.go | 6 +- ...bsub_private_linked_service_data_source.go | 95 + ...private_linked_service_data_source_test.go | 51 + .../services/signalr/web_pubsub_resource.go | 6 + ...web_pubsub_shared_private_link_resource.go | 189 + ...ubsub_shared_private_link_resource_test.go | 138 + .../springcloud/spring_cloud_app_resource.go | 19 + .../spring_cloud_app_resource_test.go | 28 + ...ing_cloud_gateway_route_config_resource.go | 49 + ...loud_gateway_route_config_resource_test.go | 3 + .../spring_cloud_service_data_source.go | 15 +- .../spring_cloud_service_resource.go | 81 +- .../spring_cloud_service_resource_test.go | 8 +- .../sql/sql_managed_instance_resource.go | 2 +- internal/services/storage/client/client.go | 2 +- internal/services/storage/client/helpers.go | 2 +- ...e_account_customer_managed_key_resource.go | 2 +- ...ount_customer_managed_key_resource_test.go | 2 +- .../storage/storage_account_data_source.go | 2 +- .../storage_account_network_rules_resource.go | 2 +- .../storage/storage_account_resource.go | 110 +- .../storage/storage_account_resource_test.go | 174 +- .../storage_blob_inventory_policy_resource.go | 2 +- .../storage_encryption_scope_resource.go | 2 +- .../storage_encryption_scope_resource_test.go | 2 +- .../storage_management_policy_resource.go | 12 +- .../storage/storage_table_entity_resource.go | 53 +- .../storage_table_entity_resource_test.go | 42 + ...ream_analytics_output_cosmosdb_resource.go | 13 + ...analytics_output_cosmosdb_resource_test.go | 1 + ...ream_analytics_output_eventhub_resource.go | 12 + ...analytics_output_eventhub_resource_test.go | 39 + .../stream_analytics_output_mssql_resource.go | 26 +- ...am_analytics_output_mssql_resource_test.go | 35 + ...tream_analytics_output_powerbi_resource.go | 48 +- ..._analytics_output_powerbi_resource_test.go | 32 + ...lytics_output_servicebus_topic_resource.go | 12 + ...s_output_servicebus_topic_resource_test.go | 39 + ...analytics_reference_input_blob_resource.go | 13 + ...tics_reference_input_blob_resource_test.go | 40 + ...nalytics_stream_input_eventhub_resource.go | 12 + ...ics_stream_input_eventhub_resource_test.go | 40 + .../services/videoanalyzer/client/client.go | 15 +- .../video_analyzer_edge_module_resource.go | 18 +- ...ideo_analyzer_edge_module_resource_test.go | 6 +- .../videoanalyzer/video_analyzer_resource.go | 32 +- .../video_analyzer_resource_test.go | 4 +- .../services/web/function_app_resource.go | 5 +- .../tf/pluginsdk/explicitly_null_config.go | 18 + internal/tools/website-scaffold/main.go | 2 +- scripts/run-gradually-deprecated.sh | 40 + .../mgmt/2019-10-01/consumption/_meta.json | 11 - .../2019-10-01/consumption/aggregatedcost.go | 188 - .../mgmt/2019-10-01/consumption/balances.go | 182 - .../mgmt/2019-10-01/consumption/budgets.go | 462 - .../mgmt/2019-10-01/consumption/charges.go | 140 - .../mgmt/2019-10-01/consumption/client.go | 41 - .../mgmt/2019-10-01/consumption/credits.go | 109 - .../mgmt/2019-10-01/consumption/enums.go | 362 - .../mgmt/2019-10-01/consumption/events.go | 155 - .../mgmt/2019-10-01/consumption/forecasts.go | 112 - .../mgmt/2019-10-01/consumption/lots.go | 151 - .../2019-10-01/consumption/marketplaces.go | 182 - .../mgmt/2019-10-01/consumption/models.go | 6081 ---------- .../mgmt/2019-10-01/consumption/operations.go | 141 - .../mgmt/2019-10-01/consumption/pricesheet.go | 229 - .../reservationrecommendationdetails.go | 122 - .../consumption/reservationrecommendations.go | 162 - .../consumption/reservationsdetails.go | 412 - .../consumption/reservationssummaries.go | 422 - .../consumption/reservationtransactions.go | 275 - .../mgmt/2019-10-01/consumption/tags.go | 112 - .../2019-10-01/consumption/usagedetails.go | 202 - .../mgmt/2019-10-01/consumption/version.go | 19 - .../mgmt/2020-06-01/costmanagement/_meta.json | 11 - .../mgmt/2020-06-01/costmanagement/alerts.go | 374 - .../mgmt/2020-06-01/costmanagement/client.go | 41 - .../2020-06-01/costmanagement/dimensions.go | 254 - .../mgmt/2020-06-01/costmanagement/enums.go | 546 - .../mgmt/2020-06-01/costmanagement/exports.go | 581 - .../2020-06-01/costmanagement/forecast.go | 274 - .../mgmt/2020-06-01/costmanagement/models.go | 1773 --- .../2020-06-01/costmanagement/operations.go | 140 - .../mgmt/2020-06-01/costmanagement/query.go | 267 - .../mgmt/2020-06-01/costmanagement/version.go | 19 - .../mgmt/2020-06-01/costmanagement/views.go | 832 -- .../mgmt/2021-03-01/datadog}/CHANGELOG.md | 0 .../mgmt/2021-03-01/datadog/_meta.json | 11 + .../datadog/mgmt/2021-03-01/datadog/client.go | 41 + .../datadog/mgmt/2021-03-01/datadog/enums.go | 153 + .../datadog/marketplaceagreements.go | 238 + .../datadog/mgmt/2021-03-01/datadog/models.go | 2115 ++++ .../mgmt/2021-03-01/datadog/monitors.go | 1436 +++ .../mgmt/2021-03-01/datadog/operations.go | 140 + .../datadog/singlesignonconfigurations.go | 349 + .../mgmt/2021-03-01/datadog/tagrules.go | 345 + .../mgmt/2021-03-01/datadog/version.go | 19 + .../dns/mgmt/2018-05-01/dns/_meta.json | 11 - .../dns/mgmt/2018-05-01/dns/client.go | 41 - .../services/dns/mgmt/2018-05-01/dns/enums.go | 53 - .../dns/mgmt/2018-05-01/dns/models.go | 961 -- .../dns/mgmt/2018-05-01/dns/recordsets.go | 774 -- .../mgmt/2018-05-01/dns/resourcereference.go | 107 - .../dns/mgmt/2018-05-01/dns/version.go | 19 - .../services/dns/mgmt/2018-05-01/dns/zones.go | 606 - .../mgmt/2020-01-01/aad/CHANGELOG.md | 2 - .../mgmt/2020-01-01/aad/_meta.json | 11 - .../mgmt/2020-01-01/aad/client.go | 41 - .../2020-01-01/aad/domainserviceoperations.go | 141 - .../mgmt/2020-01-01/aad/domainservices.go | 629 - .../mgmt/2020-01-01/aad/enums.go | 157 - .../mgmt/2020-01-01/aad/models.go | 1334 -- .../mgmt/2020-01-01/aad/oucontainer.go | 521 - .../2020-01-01/aad/oucontaineroperations.go | 141 - .../mgmt/2020-01-01/aad/version.go | 19 - .../mgmt/2021-05-01/maintenance/CHANGELOG.md | 2 - .../mgmt/2021-05-01/maintenance/_meta.json | 11 - .../applyupdateforresourcegroup.go | 106 - .../2021-05-01/maintenance/applyupdates.go | 434 - .../mgmt/2021-05-01/maintenance/client.go | 41 - .../maintenance/configurationassignments.go | 538 - .../2021-05-01/maintenance/configurations.go | 412 - .../configurationsforresourcegroup.go | 106 - .../mgmt/2021-05-01/maintenance/enums.go | 106 - .../mgmt/2021-05-01/maintenance/models.go | 661 - .../mgmt/2021-05-01/maintenance/operations.go | 98 - .../publicmaintenanceconfigurations.go | 177 - .../mgmt/2021-05-01/maintenance/updates.go | 195 - .../mgmt/2021-05-01/maintenance/version.go | 19 - .../mgmt/2018-06-01/mariadb/CHANGELOG.md | 2 - .../mgmt/2018-06-01/mariadb/_meta.json | 11 - .../mgmt/2018-06-01/mariadb/advisors.go | 250 - .../mariadb/checknameavailability.go | 118 - .../mariadb/mgmt/2018-06-01/mariadb/client.go | 140 - .../mgmt/2018-06-01/mariadb/configurations.go | 302 - .../mgmt/2018-06-01/mariadb/databases.go | 392 - .../mariadb/mgmt/2018-06-01/mariadb/enums.go | 245 - .../mgmt/2018-06-01/mariadb/firewallrules.go | 399 - .../mariadb/locationbasedperformancetier.go | 115 - ...ecommendedactionsessionsoperationstatus.go | 118 - ...ionbasedrecommendedactionsessionsresult.go | 160 - .../mgmt/2018-06-01/mariadb/logfiles.go | 120 - .../mariadb/mgmt/2018-06-01/mariadb/models.go | 4337 ------- .../mgmt/2018-06-01/mariadb/operations.go | 100 - .../mariadb/privateendpointconnections.go | 532 - .../mariadb/privatelinkresources.go | 251 - .../mgmt/2018-06-01/mariadb/querytexts.go | 254 - .../2018-06-01/mariadb/recommendedactions.go | 259 - .../mgmt/2018-06-01/mariadb/replicas.go | 120 - .../mgmt/2018-06-01/mariadb/servers.go | 649 - .../mariadb/serversecurityalertpolicies.go | 215 - .../2018-06-01/mariadb/topquerystatistics.go | 263 - .../mgmt/2018-06-01/mariadb/version.go | 19 - .../2018-06-01/mariadb/virtualnetworkrules.go | 438 - .../mgmt/2018-06-01/mariadb/waitstatistics.go | 259 - .../operationalinsights/CHANGELOG.md | 2 - .../2020-08-01/operationalinsights/_meta.json | 11 - .../availableservicetiers.go | 123 - .../2020-08-01/operationalinsights/client.go | 41 - .../operationalinsights/clusters.go | 636 - .../operationalinsights/dataexports.go | 409 - .../operationalinsights/datasources.go | 450 - .../operationalinsights/deletedworkspaces.go | 194 - .../2020-08-01/operationalinsights/enums.go | 348 - .../operationalinsights/gateways.go | 123 - .../operationalinsights/intelligencepacks.go | 305 - .../operationalinsights/linkedservices.go | 409 - .../linkedstorageaccounts.go | 405 - .../operationalinsights/managementgroups.go | 123 - .../2020-08-01/operationalinsights/models.go | 2787 ----- .../operationalinsights/operations.go | 140 - .../operationalinsights/operationstatuses.go | 115 - .../operationalinsights/savedsearches.go | 406 - .../2020-08-01/operationalinsights/schema.go | 122 - .../operationalinsights/sharedkeys.go | 213 - .../storageinsightconfigs.go | 450 - .../2020-08-01/operationalinsights/tables.go | 309 - .../2020-08-01/operationalinsights/usages.go | 122 - .../2020-08-01/operationalinsights/version.go | 19 - .../operationalinsights/workspacepurge.go | 225 - .../operationalinsights/workspaces.go | 578 - .../mgmt/2020-01-01/postgresql/CHANGELOG.md | 2 - .../mgmt/2020-01-01/postgresql/_meta.json | 11 - .../postgresql/checknameavailability.go | 118 - .../mgmt/2020-01-01/postgresql/client.go | 43 - .../2020-01-01/postgresql/configurations.go | 299 - .../mgmt/2020-01-01/postgresql/databases.go | 388 - .../mgmt/2020-01-01/postgresql/enums.go | 302 - .../2020-01-01/postgresql/firewallrules.go | 395 - .../locationbasedperformancetier.go | 115 - .../mgmt/2020-01-01/postgresql/logfiles.go | 119 - .../mgmt/2020-01-01/postgresql/models.go | 3909 ------ .../mgmt/2020-01-01/postgresql/operations.go | 100 - .../postgresql/privateendpointconnections.go | 527 - .../postgresql/privatelinkresources.go | 249 - .../postgresql/recoverableservers.go | 120 - .../mgmt/2020-01-01/postgresql/replicas.go | 119 - .../postgresql/serveradministrators.go | 391 - .../postgresql/serverbasedperformancetier.go | 120 - .../mgmt/2020-01-01/postgresql/serverkeys.go | 434 - .../2020-01-01/postgresql/serverparameters.go | 126 - .../mgmt/2020-01-01/postgresql/servers.go | 643 - .../postgresql/serversecurityalertpolicies.go | 340 - .../mgmt/2020-01-01/postgresql/version.go | 19 - .../postgresql/virtualnetworkrules.go | 434 - .../postgresqlflexibleservers/CHANGELOG.md | 2 - .../postgresqlflexibleservers/_meta.json | 11 - .../checknameavailability.go | 118 - .../postgresqlflexibleservers/client.go | 43 - .../configurations.go | 436 - .../postgresqlflexibleservers/databases.go | 431 - .../postgresqlflexibleservers/enums.go | 242 - .../firewallrules.go | 438 - .../getprivatednszonesuffix.go | 101 - .../locationbasedcapabilities.go | 157 - .../postgresqlflexibleservers/models.go | 2393 ---- .../postgresqlflexibleservers/operations.go | 100 - .../postgresqlflexibleservers/servers.go | 904 -- .../postgresqlflexibleservers/version.go | 19 - .../virtualnetworksubnetusage.go | 118 - .../containerregistry/CHANGELOG.md | 2 - .../containerregistry/_meta.json | 11 - .../containerregistry/enums.go | 615 - .../containerregistry/models.go | 7436 ------------ .../containerregistry/operations.go | 140 - .../containerregistry/registries.go | 1347 -- .../containerregistry/replications.go | 542 - .../containerregistry/scopemaps.go | 545 - .../containerregistry/tokens.go | 542 - .../containerregistry/version.go | 19 - .../containerregistry/webhooks.go | 866 -- .../containerregistry/CHANGELOG.md | 2 - .../containerregistry/_meta.json | 11 - .../containerregistry/agentpools.go | 634 - .../containerregistry/client.go | 41 - .../containerregistry/enums.go | 899 -- .../containerregistry/models.go | 10082 --------------- .../containerregistry/operations.go | 140 - .../privateendpointconnections.go | 434 - .../containerregistry/registries.go | 1471 --- .../containerregistry/replications.go | 542 - .../containerregistry/runs.go | 529 - .../containerregistry/scopemaps.go | 545 - .../containerregistry/taskruns.go | 634 - .../containerregistry/tasks.go | 645 - .../containerregistry/tokens.go | 542 - .../containerregistry/version.go | 19 - .../containerregistry/webhooks.go | 866 -- .../containerregistry}/CHANGELOG.md | 0 .../containerregistry/_meta.json | 11 + .../containerregistry/agentpools.go | 0 .../containerregistry/client.go | 0 .../containerregistry/connectedregistries.go | 12 +- .../containerregistry/enums.go | 915 ++ .../containerregistry/exportpipelines.go | 8 +- .../containerregistry/importpipelines.go | 8 +- .../containerregistry/models.go | 10129 ++++++++++++++++ .../containerregistry/operations.go | 140 + .../containerregistry/pipelineruns.go | 8 +- .../privateendpointconnections.go | 434 + .../containerregistry/registries.go | 1559 +++ .../containerregistry/replications.go | 542 + .../containerregistry/runs.go | 0 .../containerregistry/scopemaps.go | 545 + .../containerregistry/taskruns.go | 0 .../containerregistry/tasks.go | 0 .../containerregistry/tokens.go | 542 + .../containerregistry/version.go | 19 + .../containerregistry/webhooks.go | 866 ++ .../operationsmanagement/CHANGELOG.md | 2 - .../operationsmanagement/_meta.json | 11 - .../operationsmanagement/client.go | 47 - .../managementassociations.go | 373 - .../managementconfigurations.go | 367 - .../operationsmanagement/models.go | 394 - .../operationsmanagement/operations.go | 98 - .../operationsmanagement/solutions.go | 541 - .../operationsmanagement/version.go | 19 - .../mgmt/2021-04-01/storage/CHANGELOG.md | 2 - .../mgmt/2021-04-01/storage/_meta.json | 11 - .../storage/mgmt/2021-04-01/storage/client.go | 41 - .../storage/mgmt/2021-04-01/storage/enums.go | 924 -- .../storage/mgmt/2021-04-01/storage/models.go | 5273 -------- .../mgmt/2021-04-01/storage/operations.go | 98 - .../storage/privateendpointconnections.go | 411 - .../storage/privatelinkresources.go | 124 - .../storage/mgmt/2021-04-01/storage/usages.go | 112 - .../mgmt/2021-04-01/storage/version.go | 19 - .../mgmt/2021-09-01/storage}/CHANGELOG.md | 0 .../mgmt/2021-09-01/storage/_meta.json | 11 + .../storage/accounts.go | 226 +- .../storage/blobcontainers.go | 28 +- .../storage/blobinventorypolicies.go | 8 +- .../storage/blobservices.go | 6 +- .../storage/mgmt/2021-09-01/storage/client.go | 41 + .../storage/deletedaccounts.go | 4 +- .../storage/encryptionscopes.go | 8 +- .../storage/mgmt/2021-09-01/storage/enums.go | 1018 ++ .../storage/fileservices.go | 6 +- .../storage/fileshares.go | 14 +- .../mgmt/2021-09-01/storage/localusers.go | 610 + .../storage/managementpolicies.go | 6 +- .../storage/mgmt/2021-09-01/storage/models.go | 5743 +++++++++ .../storage/objectreplicationpolicies.go | 23 +- .../mgmt/2021-09-01/storage/operations.go | 98 + .../storage/privateendpointconnections.go | 411 + .../storage/privatelinkresources.go | 124 + .../storage/queue.go | 10 +- .../storage/queueservices.go | 6 +- .../storage/skus.go | 2 +- .../storage/table.go | 34 +- .../storage/tableservices.go | 6 +- .../storage/mgmt/2021-09-01/storage/usages.go | 112 + .../mgmt/2021-09-01/storage/version.go | 19 + .../authentication/auth_method_oidc.go | 44 +- .../authentication/builder.go | 1 + .../authentication/environment.go | 2 +- .../cloud_services_ip_configuration.go | 163 + .../commonids/cloud_services_public_ip.go | 176 + .../express_route_circuit_peering.go | 137 + .../commonids/network_interface.go | 124 + .../network_interface_ip_configuration.go | 137 + .../commonids/provisioning_service.go | 124 + .../commonids/public_ip_address.go | 124 + .../commonids/virtual_hub_bgp_connection.go | 137 + .../commonids/virtual_hub_ip_configuration.go | 137 + ...tual_machine_scale_set_ip_configuration.go | 163 + ...ual_machine_scale_set_network_interface.go | 150 + ...ual_machine_scale_set_public_ip_address.go | 176 + .../commonids/virtual_router_peering.go | 137 + .../commonids/virtual_wan_p2s_vpn_gateway.go | 124 + .../commonids/vpn_connection.go | 137 + .../aad/2021-05-01/domainservices/README.md | 116 + .../aad/2021-05-01/domainservices/client.go | 18 + .../2021-05-01/domainservices/constants.go | 382 + .../domainservices/id_domainservice.go | 124 + .../method_createorupdate_autorest.go | 79 + .../domainservices/method_delete_autorest.go | 78 + .../domainservices/method_get_autorest.go | 68 + .../domainservices/method_list_autorest.go | 187 + .../method_listbyresourcegroup_autorest.go | 187 + .../domainservices/method_update_autorest.go | 79 + .../domainservices/model_configdiagnostics.go | 9 + .../model_configdiagnosticsvalidatorresult.go | 11 + ...l_configdiagnosticsvalidatorresultissue.go | 9 + .../model_domainsecuritysettings.go | 14 + .../domainservices/model_domainservice.go | 19 + .../model_domainserviceproperties.go | 23 + .../domainservices/model_foresttrust.go | 12 + .../domainservices/model_healthalert.go | 44 + .../domainservices/model_healthmonitor.go | 10 + .../domainservices/model_ldapssettings.go | 32 + .../domainservices/model_migrationprogress.go | 9 + .../model_migrationproperties.go | 10 + .../model_notificationsettings.go | 10 + .../domainservices/model_replicaset.go | 17 + .../model_resourceforestsettings.go | 9 + .../2021-05-01/domainservices/predicates.go | 34 + .../aad/2021-05-01/domainservices/version.go | 12 + .../method_checknameavailability_autorest.go | 1 + .../tenants/method_get_autorest.go | 1 + .../method_listbyresourcegroup_autorest.go | 88 +- .../method_listbysubscription_autorest.go | 88 +- .../tenants/method_update_autorest.go | 1 + .../2017-08-01/servers/README.md | 4 +- .../method_checknameavailability_autorest.go | 1 + .../method_dissociategateway_autorest.go | 1 + .../servers/method_getdetails_autorest.go | 1 + .../servers/method_list_autorest.go | 1 + .../method_listbyresourcegroup_autorest.go | 1 + .../method_listgatewaystatus_autorest.go | 1 + .../method_listskusforexisting_autorest.go | 1 + ...analysisservicesservermutableproperties.go | 2 +- .../model_analysisservicesserverproperties.go | 2 +- .../2022-05-01/configurationstores/README.md | 4 +- .../method_get_autorest.go | 1 + .../method_list_autorest.go | 88 +- .../method_listbyresourcegroup_autorest.go | 88 +- .../method_listkeys_autorest.go | 88 +- .../method_regeneratekey_autorest.go | 1 + .../2020-11-20/applicationinsights/README.md | 110 - .../2020-11-20/applicationinsights/client.go | 18 - ...orkbooktemplatescreateorupdate_autorest.go | 68 - ...method_workbooktemplatesdelete_autorest.go | 65 - .../method_workbooktemplatesget_autorest.go | 67 - ...oktemplateslistbyresourcegroup_autorest.go | 69 - ...method_workbooktemplatesupdate_autorest.go | 68 - .../2020-11-20/applicationinsights/version.go | 12 - .../workbooktemplatesapis/README.md | 110 + .../workbooktemplatesapis/client.go | 18 + .../id_workbooktemplate.go | 2 +- ...orkbooktemplatescreateorupdate_autorest.go | 69 + ...method_workbooktemplatesdelete_autorest.go | 66 + .../method_workbooktemplatesget_autorest.go | 68 + ...oktemplateslistbyresourcegroup_autorest.go | 70 + ...method_workbooktemplatesupdate_autorest.go | 69 + .../model_workbooktemplate.go | 2 +- .../model_workbooktemplategallery.go | 2 +- .../model_workbooktemplatelocalizedgallery.go | 2 +- .../model_workbooktemplateproperties.go | 2 +- .../model_workbooktemplateslistresult.go | 2 +- .../model_workbooktemplateupdateparameters.go | 2 +- .../workbooktemplatesapis/version.go | 12 + .../2022-04-01/workbooksapis/README.md | 161 + .../2022-04-01/workbooksapis/client.go | 18 + .../2022-04-01/workbooksapis/constants.go | 90 + .../2022-04-01/workbooksapis/id_revision.go | 137 + .../2022-04-01/workbooksapis/id_workbook.go | 124 + ...method_workbookscreateorupdate_autorest.go | 98 + .../method_workbooksdelete_autorest.go | 66 + .../method_workbooksget_autorest.go | 97 + ...d_workbookslistbyresourcegroup_autorest.go | 231 + ...od_workbookslistbysubscription_autorest.go | 226 + .../method_workbooksrevisionget_autorest.go | 68 + .../method_workbooksrevisionslist_autorest.go | 186 + .../method_workbooksupdate_autorest.go | 98 + .../workbooksapis/model_workbook.go | 22 + .../workbooksapis/model_workbookproperties.go | 36 + ...odel_workbookpropertiesupdateparameters.go | 13 + .../model_workbookupdateparameters.go | 10 + .../2022-04-01/workbooksapis/predicates.go | 34 + .../2022-04-01/workbooksapis/version.go | 12 + .../2020-10-01/attestationproviders/README.md | 6 +- .../method_create_autorest.go | 1 + .../method_delete_autorest.go | 1 + .../method_get_autorest.go | 1 + .../method_getdefaultbylocation_autorest.go | 1 + .../method_list_autorest.go | 1 + .../method_listbyresourcegroup_autorest.go | 1 + .../method_listdefault_autorest.go | 1 + .../method_update_autorest.go | 1 + .../2021-06-22/automationaccount/README.md | 128 + .../2021-06-22/automationaccount/client.go | 18 + .../2021-06-22/automationaccount/constants.go | 93 + .../automationaccount/id_automationaccount.go | 124 + .../method_createorupdate_autorest.go | 69 + .../method_delete_autorest.go | 66 + .../automationaccount/method_get_autorest.go | 68 + .../automationaccount/method_list_autorest.go | 187 + .../method_listbyresourcegroup_autorest.go | 187 + .../method_update_autorest.go | 69 + .../model_automationaccount.go | 21 + ...tomationaccountcreateorupdateparameters.go | 16 + ...tomationaccountcreateorupdateproperties.go | 11 + .../model_automationaccountproperties.go | 48 + ...model_automationaccountupdateparameters.go | 16 + ...model_automationaccountupdateproperties.go | 11 + .../model_encryptionproperties.go | 10 + .../model_encryptionpropertiesidentity.go | 8 + .../model_keyvaultproperties.go | 10 + .../model_privateendpointconnection.go | 11 + ...del_privateendpointconnectionproperties.go | 10 + .../model_privateendpointproperty.go | 8 + ...ivatelinkserviceconnectionstateproperty.go | 10 + .../2021-06-22/automationaccount/model_sku.go | 10 + .../automationaccount/predicates.go | 34 + .../2021-06-22/automationaccount/version.go | 12 + .../hybridrunbookworkergroup/README.md | 111 + .../hybridrunbookworkergroup/client.go | 18 + .../hybridrunbookworkergroup/constants.go | 34 + .../id_automationaccount.go | 124 + .../id_hybridrunbookworkergroup.go | 137 + .../method_create_autorest.go | 69 + .../method_delete_autorest.go | 66 + .../method_get_autorest.go | 68 + ...method_listbyautomationaccount_autorest.go | 215 + .../method_update_autorest.go | 69 + .../model_hybridrunbookworkergroup.go | 18 + ...bookworkergroupcreateorupdateparameters.go | 8 + .../model_hybridrunbookworkerlegacy.go | 41 + ...odel_runascredentialassociationproperty.go | 8 + .../hybridrunbookworkergroup/predicates.go | 24 + .../hybridrunbookworkergroup/version.go | 12 + .../2020-10-01/clusters/README.md | 4 +- .../clusters/method_create_autorest.go | 1 + .../clusters/method_delete_autorest.go | 1 + .../clusters/method_get_autorest.go | 1 + .../method_listbyresourcegroup_autorest.go | 88 +- .../method_listbysubscription_autorest.go | 88 +- .../clusters/method_update_autorest.go | 1 + .../cognitiveservicesaccounts/README.md | 10 +- .../method_accountsget_autorest.go | 1 + .../method_accountslist_autorest.go | 88 +- ...od_accountslistbyresourcegroup_autorest.go | 88 +- .../method_accountslistkeys_autorest.go | 1 + .../method_accountslistskus_autorest.go | 1 + .../method_accountslistusages_autorest.go | 1 + .../method_accountsregeneratekey_autorest.go | 1 + ...method_checkdomainavailability_autorest.go | 1 + .../method_checkskuavailability_autorest.go | 1 + .../method_deletedaccountsget_autorest.go | 1 + .../method_deletedaccountslist_autorest.go | 88 +- .../method_resourceskuslist_autorest.go | 88 +- .../cognitiveservicesaccounts/model_iprule.go | 2 +- .../model_networkruleset.go | 2 +- .../2020-08-20/communicationservice/README.md | 6 +- .../method_checknameavailability_autorest.go | 1 + .../method_get_autorest.go | 1 + .../method_linknotificationhub_autorest.go | 1 + .../method_listbyresourcegroup_autorest.go | 88 +- .../method_listbysubscription_autorest.go | 88 +- .../method_listkeys_autorest.go | 1 + .../method_regeneratekey_autorest.go | 1 + .../method_update_autorest.go | 1 + .../2021-11-01/availabilitysets/README.md | 4 +- .../method_createorupdate_autorest.go | 1 + .../method_delete_autorest.go | 1 + .../availabilitysets/method_get_autorest.go | 1 + .../availabilitysets/method_list_autorest.go | 88 +- .../method_listavailablesizes_autorest.go | 1 + .../method_listbysubscription_autorest.go | 88 +- .../method_update_autorest.go | 1 + .../2021-11-01/dedicatedhostgroups/README.md | 128 + .../2021-11-01/dedicatedhostgroups/client.go | 18 + .../dedicatedhostgroups/constants.go | 65 + .../dedicatedhostgroups/id_hostgroup.go | 124 + .../method_createorupdate_autorest.go | 69 + .../method_delete_autorest.go | 66 + .../method_get_autorest.go | 97 + .../method_listbyresourcegroup_autorest.go | 187 + .../method_listbysubscription_autorest.go | 187 + .../method_update_autorest.go | 69 + .../model_dedicatedhostallocatablevm.go | 9 + .../model_dedicatedhostavailablecapacity.go | 8 + .../model_dedicatedhostgroup.go | 14 + .../model_dedicatedhostgroupinstanceview.go | 8 + .../model_dedicatedhostgroupproperties.go | 11 + .../model_dedicatedhostgroupupdate.go | 10 + ...model_dedicatedhostinstanceviewwithname.go | 11 + .../model_instanceviewstatus.go | 30 + .../model_subresourcereadonly.go | 8 + .../dedicatedhostgroups/predicates.go | 29 + .../2021-11-01/dedicatedhostgroups/version.go | 12 + .../2021-11-01/dedicatedhosts/README.md | 82 + .../2021-11-01/dedicatedhosts/client.go | 18 + .../2021-11-01/dedicatedhosts/constants.go | 96 + .../2021-11-01/dedicatedhosts/id_host.go | 137 + .../method_createorupdate_autorest.go | 79 + .../dedicatedhosts/method_delete_autorest.go | 78 + .../dedicatedhosts/method_get_autorest.go | 97 + .../dedicatedhosts/method_update_autorest.go | 79 + .../dedicatedhosts/model_dedicatedhost.go | 14 + .../model_dedicatedhostallocatablevm.go | 9 + .../model_dedicatedhostavailablecapacity.go | 8 + .../model_dedicatedhostinstanceview.go | 10 + .../model_dedicatedhostproperties.go | 46 + .../model_dedicatedhostupdate.go | 9 + .../model_instanceviewstatus.go | 30 + .../2021-11-01/dedicatedhosts/model_sku.go | 10 + .../model_subresourcereadonly.go | 8 + .../2021-11-01/dedicatedhosts/version.go | 12 + .../proximityplacementgroups/README.md | 128 + .../proximityplacementgroups/client.go | 18 + .../proximityplacementgroups/constants.go | 65 + .../id_proximityplacementgroup.go | 124 + .../method_createorupdate_autorest.go | 69 + .../method_delete_autorest.go | 66 + .../method_get_autorest.go | 97 + .../method_listbyresourcegroup_autorest.go | 187 + .../method_listbysubscription_autorest.go | 187 + .../method_update_autorest.go | 69 + .../model_instanceviewstatus.go | 30 + .../model_proximityplacementgroup.go | 13 + ...model_proximityplacementgroupproperties.go | 12 + .../model_subresourcewithcolocationstatus.go | 9 + .../model_updateresource.go | 8 + .../proximityplacementgroups/predicates.go | 29 + .../proximityplacementgroups/version.go | 12 + .../2021-11-01/sshpublickeys/README.md | 4 +- .../sshpublickeys/method_create_autorest.go | 1 + .../sshpublickeys/method_delete_autorest.go | 1 + .../method_generatekeypair_autorest.go | 1 + .../sshpublickeys/method_get_autorest.go | 1 + .../method_listbyresourcegroup_autorest.go | 88 +- .../method_listbysubscription_autorest.go | 88 +- .../sshpublickeys/method_update_autorest.go | 1 + .../2022-05-13/confidentialledger/README.md | 4 +- .../method_ledgerget_autorest.go | 1 + ...thod_ledgerlistbyresourcegroup_autorest.go | 88 +- ...ethod_ledgerlistbysubscription_autorest.go | 88 +- .../consumption/2019-10-01/budgets/README.md | 90 + .../consumption/2019-10-01/budgets/client.go | 18 + .../2019-10-01/budgets/constants.go | 237 + .../2019-10-01/budgets/id_scopedbudget.go | 110 + .../budgets/method_createorupdate_autorest.go | 69 + .../budgets/method_delete_autorest.go | 66 + .../2019-10-01/budgets/method_get_autorest.go | 68 + .../budgets/method_list_autorest.go | 187 + .../2019-10-01/budgets/model_budget.go | 12 + .../model_budgetcomparisonexpression.go | 10 + .../2019-10-01/budgets/model_budgetfilter.go | 11 + .../budgets/model_budgetfilterproperties.go | 9 + .../budgets/model_budgetproperties.go | 15 + .../budgets/model_budgettimeperiod.go | 36 + .../2019-10-01/budgets/model_currentspend.go | 9 + .../2019-10-01/budgets/model_forecastspend.go | 9 + .../2019-10-01/budgets/model_notification.go | 15 + .../2019-10-01/budgets/predicates.go | 29 + .../consumption/2019-10-01/budgets/version.go | 12 + .../2021-03-01/containerinstance/README.md | 4 +- .../2021-03-01/containerinstance/constants.go | 34 +- .../method_containergroupsget_autorest.go | 1 + .../method_containergroupslist_autorest.go | 88 +- ...ainergroupslistbyresourcegroup_autorest.go | 88 +- .../method_containergroupsstop_autorest.go | 1 + .../method_containergroupsupdate_autorest.go | 1 + .../method_containersattach_autorest.go | 1 + ...ethod_containersexecutecommand_autorest.go | 1 + .../method_containerslistlogs_autorest.go | 1 + ...ethod_locationlistcachedimages_autorest.go | 88 +- ...ethod_locationlistcapabilities_autorest.go | 88 +- .../method_locationlistusage_autorest.go | 1 + .../containerinstance/model_capabilities.go | 2 +- .../model_containergroupproperties.go | 2 +- .../model_containerhttpget.go | 4 +- .../containerinstance/model_containerprobe.go | 2 +- .../containerinstance/model_httpheader.go | 2 +- .../containerinstance/model_ipaddress.go | 6 +- .../containerinstance/predicates.go | 4 +- .../cosmosdb/2022-05-15/cosmosdb/README.md | 1843 +++ .../cosmosdb/2022-05-15/cosmosdb/client.go | 18 + .../cosmosdb/2022-05-15/cosmosdb/constants.go | 793 ++ .../cosmosdb/id_cassandrakeyspace.go | 137 + .../cosmosdb/id_cassandrakeyspacetable.go | 150 + .../2022-05-15/cosmosdb/id_collection.go | 150 + .../id_collectionpartitionkeyrangeid.go | 176 + .../2022-05-15/cosmosdb/id_container.go | 150 + .../2022-05-15/cosmosdb/id_database.go | 137 + .../2022-05-15/cosmosdb/id_databaseaccount.go | 124 + .../cosmosdb/id_databaseaccountname.go | 98 + .../cosmosdb/id_databasecollection.go | 163 + .../cosmosdb/2022-05-15/cosmosdb/id_graph.go | 150 + .../2022-05-15/cosmosdb/id_gremlindatabase.go | 137 + .../2022-05-15/cosmosdb/id_location.go | 111 + .../2022-05-15/cosmosdb/id_mongodbdatabase.go | 137 + .../cosmosdb/id_mongodbdatabasecollection.go | 150 + .../cosmosdb/id_partitionkeyrangeid.go | 163 + .../cosmosdb/2022-05-15/cosmosdb/id_region.go | 137 + .../cosmosdb/id_sourceregiontargetregion.go | 150 + .../2022-05-15/cosmosdb/id_sqldatabase.go | 137 + .../2022-05-15/cosmosdb/id_storedprocedure.go | 163 + .../cosmosdb/2022-05-15/cosmosdb/id_table.go | 137 + .../2022-05-15/cosmosdb/id_targetregion.go | 137 + .../2022-05-15/cosmosdb/id_trigger.go | 163 + .../cosmosdb/id_userdefinedfunction.go | 163 + ...screateupdatecassandrakeyspace_autorest.go | 79 + ...rcescreateupdatecassandratable_autorest.go | 79 + ...sourcesdeletecassandrakeyspace_autorest.go | 78 + ...aresourcesdeletecassandratable_autorest.go | 78 + ...aresourcesgetcassandrakeyspace_autorest.go | 68 + ...getcassandrakeyspacethroughput_autorest.go | 69 + ...ndraresourcesgetcassandratable_autorest.go | 68 + ...cesgetcassandratablethroughput_autorest.go | 69 + ...esourceslistcassandrakeyspaces_autorest.go | 69 + ...raresourceslistcassandratables_autorest.go | 69 + ...tecassandrakeyspacetoautoscale_autorest.go | 78 + ...ndrakeyspacetomanualthroughput_autorest.go | 78 + ...gratecassandratabletoautoscale_autorest.go | 78 + ...ssandratabletomanualthroughput_autorest.go | 78 + ...atecassandrakeyspacethroughput_autorest.go | 79 + ...updatecassandratablethroughput_autorest.go | 79 + ...ollectionlistmetricdefinitions_autorest.go | 69 + .../method_collectionlistmetrics_autorest.go | 98 + .../method_collectionlistusages_autorest.go | 98 + ...collectionpartitionlistmetrics_autorest.go | 98 + ..._collectionpartitionlistusages_autorest.go | 98 + ...tionpartitionregionlistmetrics_autorest.go | 98 + ...od_collectionregionlistmetrics_autorest.go | 98 + ...tabaseaccountregionlistmetrics_autorest.go | 98 + ...atabaseaccountschecknameexists_autorest.go | 66 + ...databaseaccountscreateorupdate_autorest.go | 79 + .../method_databaseaccountsdelete_autorest.go | 78 + ...accountsfailoverprioritychange_autorest.go | 79 + .../method_databaseaccountsget_autorest.go | 68 + ...atabaseaccountsgetreadonlykeys_autorest.go | 69 + .../method_databaseaccountslist_autorest.go | 70 + ...aseaccountslistbyresourcegroup_autorest.go | 70 + ...eaccountslistconnectionstrings_autorest.go | 69 + ...ethod_databaseaccountslistkeys_autorest.go | 69 + ...eaccountslistmetricdefinitions_autorest.go | 69 + ...od_databaseaccountslistmetrics_autorest.go | 98 + ...tabaseaccountslistreadonlykeys_autorest.go | 69 + ...hod_databaseaccountslistusages_autorest.go | 98 + ..._databaseaccountsofflineregion_autorest.go | 79 + ...d_databaseaccountsonlineregion_autorest.go | 79 + ..._databaseaccountsregeneratekey_autorest.go | 79 + .../method_databaseaccountsupdate_autorest.go | 79 + ..._databaselistmetricdefinitions_autorest.go | 69 + .../method_databaselistmetrics_autorest.go | 98 + .../method_databaselistusages_autorest.go | 98 + ...cescreateupdategremlindatabase_autorest.go | 79 + ...ourcescreateupdategremlingraph_autorest.go | 79 + ...resourcesdeletegremlindatabase_autorest.go | 78 + ...linresourcesdeletegremlingraph_autorest.go | 78 + ...linresourcesgetgremlindatabase_autorest.go | 68 + ...esgetgremlindatabasethroughput_autorest.go | 69 + ...remlinresourcesgetgremlingraph_autorest.go | 68 + ...urcesgetgremlingraphthroughput_autorest.go | 69 + ...nresourceslistgremlindatabases_autorest.go | 69 + ...mlinresourceslistgremlingraphs_autorest.go | 69 + ...rategremlindatabasetoautoscale_autorest.go | 78 + ...mlindatabasetomanualthroughput_autorest.go | 78 + ...migrategremlingraphtoautoscale_autorest.go | 78 + ...gremlingraphtomanualthroughput_autorest.go | 78 + ...pdategremlindatabasethroughput_autorest.go | 79 + ...esupdategremlingraphthroughput_autorest.go | 79 + .../cosmosdb/method_locationsget_autorest.go | 68 + .../cosmosdb/method_locationslist_autorest.go | 70 + ...screateupdatemongodbcollection_autorest.go | 79 + ...cescreateupdatemongodbdatabase_autorest.go | 79 + ...sourcesdeletemongodbcollection_autorest.go | 78 + ...resourcesdeletemongodbdatabase_autorest.go | 78 + ...bresourcesgetmongodbcollection_autorest.go | 68 + ...getmongodbcollectionthroughput_autorest.go | 69 + ...odbresourcesgetmongodbdatabase_autorest.go | 68 + ...esgetmongodbdatabasethroughput_autorest.go | 69 + ...esourceslistmongodbcollections_autorest.go | 69 + ...bresourceslistmongodbdatabases_autorest.go | 69 + ...temongodbcollectiontoautoscale_autorest.go | 78 + ...dbcollectiontomanualthroughput_autorest.go | 78 + ...ratemongodbdatabasetoautoscale_autorest.go | 78 + ...godbdatabasetomanualthroughput_autorest.go | 78 + ...atemongodbcollectionthroughput_autorest.go | 79 + ...pdatemongodbdatabasethroughput_autorest.go | 79 + ...partitionkeyrangeidlistmetrics_autorest.go | 98 + ...ionkeyrangeidregionlistmetrics_autorest.go | 98 + .../method_percentilelistmetrics_autorest.go | 98 + ...centilesourcetargetlistmetrics_autorest.go | 98 + ...od_percentiletargetlistmetrics_autorest.go | 98 + ...ourcescreateupdatesqlcontainer_autorest.go | 79 + ...sourcescreateupdatesqldatabase_autorest.go | 79 + ...createupdatesqlstoredprocedure_autorest.go | 79 + ...esourcescreateupdatesqltrigger_autorest.go | 79 + ...teupdatesqluserdefinedfunction_autorest.go | 79 + ...sqlresourcesdeletesqlcontainer_autorest.go | 78 + ..._sqlresourcesdeletesqldatabase_autorest.go | 78 + ...ourcesdeletesqlstoredprocedure_autorest.go | 78 + ...d_sqlresourcesdeletesqltrigger_autorest.go | 78 + ...esdeletesqluserdefinedfunction_autorest.go | 78 + ...od_sqlresourcesgetsqlcontainer_autorest.go | 68 + ...urcesgetsqlcontainerthroughput_autorest.go | 69 + ...hod_sqlresourcesgetsqldatabase_autorest.go | 68 + ...ourcesgetsqldatabasethroughput_autorest.go | 69 + ...resourcesgetsqlstoredprocedure_autorest.go | 68 + ...thod_sqlresourcesgetsqltrigger_autorest.go | 68 + ...urcesgetsqluserdefinedfunction_autorest.go | 68 + ..._sqlresourceslistsqlcontainers_autorest.go | 69 + ...d_sqlresourceslistsqldatabases_autorest.go | 69 + ...sourceslistsqlstoredprocedures_autorest.go | 69 + ...od_sqlresourceslistsqltriggers_autorest.go | 69 + ...ceslistsqluserdefinedfunctions_autorest.go | 69 + ...migratesqlcontainertoautoscale_autorest.go | 78 + ...sqlcontainertomanualthroughput_autorest.go | 78 + ...smigratesqldatabasetoautoscale_autorest.go | 78 + ...esqldatabasetomanualthroughput_autorest.go | 78 + ...esupdatesqlcontainerthroughput_autorest.go | 79 + ...cesupdatesqldatabasethroughput_autorest.go | 79 + ...ableresourcescreateupdatetable_autorest.go | 79 + ...thod_tableresourcesdeletetable_autorest.go | 78 + .../method_tableresourcesgettable_autorest.go | 68 + ...bleresourcesgettablethroughput_autorest.go | 69 + ...ethod_tableresourceslisttables_autorest.go | 69 + ...sourcesmigratetabletoautoscale_autorest.go | 78 + ...migratetabletomanualthroughput_autorest.go | 78 + ...resourcesupdatetablethroughput_autorest.go | 79 + .../model_analyticalstorageconfiguration.go | 8 + .../cosmosdb/model_apiproperties.go | 8 + .../cosmosdb/model_autoscalesettings.go | 8 + .../model_autoscalesettingsresource.go | 10 + .../model_autoupgradepolicyresource.go | 8 + .../2022-05-15/cosmosdb/model_backuppolicy.go | 56 + .../model_backuppolicymigrationstate.go | 28 + .../2022-05-15/cosmosdb/model_capability.go | 8 + .../2022-05-15/cosmosdb/model_capacity.go | 8 + ...cassandrakeyspacecreateupdateparameters.go | 13 + ...cassandrakeyspacecreateupdateproperties.go | 9 + .../model_cassandrakeyspacegetproperties.go | 9 + .../model_cassandrakeyspacegetresults.go | 13 + .../model_cassandrakeyspacelistresult.go | 8 + .../model_cassandrakeyspaceresource.go | 8 + .../cosmosdb/model_cassandrapartitionkey.go | 8 + .../cosmosdb/model_cassandraschema.go | 10 + ...el_cassandratablecreateupdateparameters.go | 13 + ...el_cassandratablecreateupdateproperties.go | 9 + .../model_cassandratablegetproperties.go | 9 + .../model_cassandratablegetresults.go | 13 + .../model_cassandratablelistresult.go | 8 + .../cosmosdb/model_cassandratableresource.go | 11 + .../2022-05-15/cosmosdb/model_clusterkey.go | 9 + .../2022-05-15/cosmosdb/model_column.go | 9 + .../cosmosdb/model_compositepath.go | 9 + .../model_conflictresolutionpolicy.go | 10 + .../cosmosdb/model_consistencypolicy.go | 10 + .../cosmosdb/model_containerpartitionkey.go | 11 + .../model_continuousmodebackuppolicy.go | 41 + .../2022-05-15/cosmosdb/model_corspolicy.go | 12 + .../cosmosdb/model_createupdateoptions.go | 9 + .../model_databaseaccountconnectionstring.go | 9 + ...l_databaseaccountcreateupdateparameters.go | 19 + ...l_databaseaccountcreateupdateproperties.go | 90 + .../model_databaseaccountgetproperties.go | 104 + .../model_databaseaccountgetresults.go | 21 + ...abaseaccountlistconnectionstringsresult.go | 8 + .../model_databaseaccountlistkeysresult.go | 11 + ...l_databaseaccountlistreadonlykeysresult.go | 9 + ..._databaseaccountregeneratekeyparameters.go | 8 + .../model_databaseaccountslistresult.go | 8 + .../model_databaseaccountupdateparameters.go | 15 + .../model_databaseaccountupdateproperties.go | 84 + .../cosmosdb/model_databaserestoreresource.go | 9 + .../2022-05-15/cosmosdb/model_excludedpath.go | 8 + .../cosmosdb/model_failoverpolicies.go | 8 + .../cosmosdb/model_failoverpolicy.go | 10 + ...l_gremlindatabasecreateupdateparameters.go | 13 + ...l_gremlindatabasecreateupdateproperties.go | 9 + .../model_gremlindatabasegetproperties.go | 9 + .../model_gremlindatabasegetresults.go | 13 + .../model_gremlindatabaselistresult.go | 8 + .../cosmosdb/model_gremlindatabaseresource.go | 8 + ...odel_gremlingraphcreateupdateparameters.go | 13 + ...odel_gremlingraphcreateupdateproperties.go | 9 + .../model_gremlingraphgetproperties.go | 9 + .../cosmosdb/model_gremlingraphgetresults.go | 13 + .../cosmosdb/model_gremlingraphlistresult.go | 8 + .../cosmosdb/model_gremlingraphresource.go | 14 + .../2022-05-15/cosmosdb/model_includedpath.go | 9 + .../2022-05-15/cosmosdb/model_indexes.go | 10 + .../cosmosdb/model_indexingpolicy.go | 13 + .../cosmosdb/model_ipaddressorrange.go | 8 + .../2022-05-15/cosmosdb/model_location.go | 13 + .../cosmosdb/model_locationgetresult.go | 11 + .../cosmosdb/model_locationlistresult.go | 8 + .../cosmosdb/model_locationproperties.go | 10 + .../2022-05-15/cosmosdb/model_metric.go | 43 + .../cosmosdb/model_metricavailability.go | 9 + .../cosmosdb/model_metricdefinition.go | 12 + .../model_metricdefinitionslistresult.go | 8 + .../cosmosdb/model_metriclistresult.go | 8 + .../2022-05-15/cosmosdb/model_metricname.go | 9 + .../2022-05-15/cosmosdb/model_metricvalue.go | 31 + ...mongodbcollectioncreateupdateparameters.go | 13 + ...mongodbcollectioncreateupdateproperties.go | 9 + .../model_mongodbcollectiongetproperties.go | 9 + .../model_mongodbcollectiongetresults.go | 13 + .../model_mongodbcollectionlistresult.go | 8 + .../model_mongodbcollectionresource.go | 11 + ...l_mongodbdatabasecreateupdateparameters.go | 13 + ...l_mongodbdatabasecreateupdateproperties.go | 9 + .../model_mongodbdatabasegetproperties.go | 9 + .../model_mongodbdatabasegetresults.go | 13 + .../model_mongodbdatabaselistresult.go | 8 + .../cosmosdb/model_mongodbdatabaseresource.go | 8 + .../2022-05-15/cosmosdb/model_mongoindex.go | 9 + .../cosmosdb/model_mongoindexkeys.go | 8 + .../cosmosdb/model_mongoindexoptions.go | 9 + .../cosmosdb/model_optionsresource.go | 9 + .../cosmosdb/model_partitionmetric.go | 45 + .../model_partitionmetriclistresult.go | 8 + .../cosmosdb/model_partitionusage.go | 14 + .../cosmosdb/model_partitionusagesresult.go | 8 + .../cosmosdb/model_percentilemetric.go | 43 + .../model_percentilemetriclistresult.go | 8 + .../cosmosdb/model_percentilemetricvalue.go | 38 + .../model_periodicmodebackuppolicy.go | 42 + .../cosmosdb/model_periodicmodeproperties.go | 10 + .../model_privateendpointconnection.go | 11 + ...del_privateendpointconnectionproperties.go | 11 + .../cosmosdb/model_privateendpointproperty.go | 8 + ...ivatelinkserviceconnectionstateproperty.go | 10 + .../cosmosdb/model_regionforonlineoffline.go | 8 + .../cosmosdb/model_restoreparameters.go | 29 + .../2022-05-15/cosmosdb/model_spatialspec.go | 9 + ...odel_sqlcontainercreateupdateparameters.go | 13 + ...odel_sqlcontainercreateupdateproperties.go | 9 + .../model_sqlcontainergetproperties.go | 9 + .../cosmosdb/model_sqlcontainergetresults.go | 13 + .../cosmosdb/model_sqlcontainerlistresult.go | 8 + .../cosmosdb/model_sqlcontainerresource.go | 14 + ...model_sqldatabasecreateupdateparameters.go | 13 + ...model_sqldatabasecreateupdateproperties.go | 9 + .../model_sqldatabasegetproperties.go | 9 + .../model_sqldatabasegetpropertiesresource.go | 9 + .../cosmosdb/model_sqldatabasegetresults.go | 13 + .../cosmosdb/model_sqldatabaselistresult.go | 8 + .../cosmosdb/model_sqldatabaseresource.go | 8 + ...qlstoredprocedurecreateupdateparameters.go | 13 + ...qlstoredprocedurecreateupdateproperties.go | 9 + .../model_sqlstoredproceduregetproperties.go | 8 + .../model_sqlstoredproceduregetresults.go | 13 + .../model_sqlstoredprocedurelistresult.go | 8 + .../model_sqlstoredprocedureresource.go | 9 + .../model_sqltriggercreateupdateparameters.go | 13 + .../model_sqltriggercreateupdateproperties.go | 9 + .../cosmosdb/model_sqltriggergetproperties.go | 8 + .../cosmosdb/model_sqltriggergetresults.go | 13 + .../cosmosdb/model_sqltriggerlistresult.go | 8 + .../cosmosdb/model_sqltriggerresource.go | 11 + ...erdefinedfunctioncreateupdateparameters.go | 13 + ...erdefinedfunctioncreateupdateproperties.go | 9 + ...del_sqluserdefinedfunctiongetproperties.go | 8 + .../model_sqluserdefinedfunctiongetresults.go | 13 + .../model_sqluserdefinedfunctionlistresult.go | 8 + .../model_sqluserdefinedfunctionresource.go | 9 + .../model_tablecreateupdateparameters.go | 13 + .../model_tablecreateupdateproperties.go | 9 + .../cosmosdb/model_tablegetproperties.go | 9 + .../cosmosdb/model_tablegetresults.go | 13 + .../cosmosdb/model_tablelistresult.go | 8 + .../cosmosdb/model_tableresource.go | 8 + .../model_throughputpolicyresource.go | 9 + .../model_throughputsettingsgetproperties.go | 8 + .../model_throughputsettingsgetresults.go | 13 + .../model_throughputsettingsresource.go | 11 + ...odel_throughputsettingsupdateparameters.go | 13 + ...odel_throughputsettingsupdateproperties.go | 8 + .../2022-05-15/cosmosdb/model_uniquekey.go | 8 + .../cosmosdb/model_uniquekeypolicy.go | 8 + .../2022-05-15/cosmosdb/model_usage.go | 12 + .../2022-05-15/cosmosdb/model_usagesresult.go | 8 + .../cosmosdb/model_virtualnetworkrule.go | 9 + .../cosmosdb/2022-05-15/cosmosdb/version.go | 12 + .../2022-05-15/sqldedicatedgateway/README.md | 65 + .../2022-05-15/sqldedicatedgateway/client.go | 18 + .../sqldedicatedgateway/constants.go | 111 + .../sqldedicatedgateway/id_service.go | 137 + .../method_servicecreate_autorest.go | 79 + .../method_servicedelete_autorest.go | 78 + .../method_serviceget_autorest.go | 68 + ...l_datatransferserviceresourceproperties.go | 60 + ..._graphapicomputeregionalserviceresource.go | 11 + ...raphapicomputeserviceresourceproperties.go | 61 + ...edviewsbuilderserviceresourceproperties.go | 60 + .../model_regionalserviceresource.go | 10 + .../model_serviceresource.go | 44 + ...l_serviceresourcecreateupdateparameters.go | 8 + ...l_serviceresourcecreateupdateproperties.go | 10 + .../model_serviceresourceproperties.go | 72 + ...dedicatedgatewayregionalserviceresource.go | 11 + ...dicatedgatewayserviceresourceproperties.go | 61 + .../2022-05-15/sqldedicatedgateway/version.go | 12 + .../2021-10-01/exports/README.md | 121 + .../2021-10-01/exports/client.go | 18 + .../2021-10-01/exports/constants.go | 260 + .../2021-10-01/exports/id_scopedexport.go | 110 + .../exports/method_createorupdate_autorest.go | 69 + .../exports/method_delete_autorest.go | 66 + .../exports/method_execute_autorest.go | 67 + .../2021-10-01/exports/method_get_autorest.go | 97 + .../method_getexecutionhistory_autorest.go | 69 + .../exports/method_list_autorest.go | 99 + .../exports/model_commonexportproperties.go | 31 + .../2021-10-01/exports/model_errordetails.go | 9 + .../2021-10-01/exports/model_export.go | 12 + .../2021-10-01/exports/model_exportdataset.go | 9 + .../model_exportdatasetconfiguration.go | 8 + .../exports/model_exportdefinition.go | 11 + .../model_exportdeliverydestination.go | 12 + .../exports/model_exportdeliveryinfo.go | 8 + .../exports/model_exportexecution.go | 12 + .../model_exportexecutionlistresult.go | 8 + .../model_exportexecutionproperties.go | 58 + .../exports/model_exportlistresult.go | 8 + .../exports/model_exportproperties.go | 32 + .../exports/model_exportrecurrenceperiod.go | 36 + .../exports/model_exportschedule.go | 10 + .../exports/model_exporttimeperiod.go | 33 + .../2021-10-01/exports/version.go | 12 + .../2022-08-01/grafanaresource/README.md | 120 + .../2022-08-01/grafanaresource/client.go | 18 + .../2022-08-01/grafanaresource/constants.go | 257 + .../2022-08-01/grafanaresource/id_grafana.go | 124 + .../method_grafanacreate_autorest.go | 79 + .../method_grafanadelete_autorest.go | 78 + .../method_grafanaget_autorest.go | 68 + .../method_grafanalist_autorest.go | 187 + ...hod_grafanalistbyresourcegroup_autorest.go | 187 + .../method_grafanaupdate_autorest.go | 69 + .../model_azuremonitorworkspaceintegration.go | 8 + .../model_grafanaintegrations.go | 8 + .../grafanaresource/model_managedgrafana.go | 21 + .../model_managedgrafanaproperties.go | 18 + ...anagedgrafanapropertiesupdateparameters.go | 12 + .../model_managedgrafanaupdateparameters.go | 14 + .../grafanaresource/model_privateendpoint.go | 8 + .../model_privateendpointconnection.go | 16 + ...del_privateendpointconnectionproperties.go | 11 + ...model_privatelinkserviceconnectionstate.go | 10 + .../grafanaresource/model_resourcesku.go | 8 + .../2022-08-01/grafanaresource/predicates.go | 29 + .../2022-08-01/grafanaresource/version.go | 12 + .../2021-04-01-preview/workspaces/README.md | 4 +- .../workspaces/method_get_autorest.go | 1 + .../method_listbyresourcegroup_autorest.go | 88 +- .../method_listbysubscription_autorest.go | 88 +- .../model_workspacecustomparameters.go | 4 +- .../2022-04-01/backupinstances/README.md | 232 + .../2022-04-01/backupinstances/client.go | 18 + .../2022-04-01/backupinstances/constants.go | 337 + .../backupinstances/id_backupinstance.go | 137 + .../backupinstances/id_backupvault.go | 124 + .../method_adhocbackup_autorest.go | 79 + .../method_createorupdate_autorest.go | 79 + .../backupinstances/method_delete_autorest.go | 78 + .../backupinstances/method_get_autorest.go | 68 + .../backupinstances/method_list_autorest.go | 186 + .../method_resumebackups_autorest.go | 78 + .../method_resumeprotection_autorest.go | 78 + .../method_stopprotection_autorest.go | 78 + .../method_suspendbackups_autorest.go | 78 + .../method_syncbackupinstance_autorest.go | 79 + .../method_triggerrehydrate_autorest.go | 79 + .../method_triggerrestore_autorest.go | 79 + .../method_validateforbackup_autorest.go | 79 + .../method_validateforrestore_autorest.go | 79 + .../model_adhocbackupruleoptions.go | 9 + .../model_adhocbackuptriggeroption.go | 8 + .../backupinstances/model_authcredentials.go | 48 + ...ebackuprecoverypointbasedrestorerequest.go | 72 + ...rebackuprecoverytimebasedrestorerequest.go | 72 + .../model_azurebackuprehydrationrequest.go | 10 + .../model_azurebackuprestorerequest.go | 56 + .../model_azureoperationalstoreparameters.go | 42 + .../backupinstances/model_backupinstance.go | 58 + .../model_backupinstanceresource.go | 16 + .../backupinstances/model_datasource.go | 14 + .../backupinstances/model_datasourceset.go | 14 + .../model_datastoreparameters.go | 48 + .../backupinstances/model_innererror.go | 10 + .../model_itemlevelrestorecriteria.go | 64 + .../model_itemlevelrestoretargetinfo.go | 92 + .../model_kubernetespvrestorecriteria.go | 42 + ...l_kubernetesstorageclassrestorecriteria.go | 42 + .../model_operationextendedinfo.go | 48 + .../model_operationjobextendedinfo.go | 41 + .../backupinstances/model_policyinfo.go | 10 + .../backupinstances/model_policyparameters.go | 41 + .../model_protectionstatusdetails.go | 9 + ...odel_rangebaseditemlevelrestorecriteria.go | 42 + .../model_restorefilestargetinfo.go | 43 + .../model_restoretargetinfo.go | 74 + .../model_restoretargetinfobase.go | 64 + .../model_secretstorebasedauthcredentials.go | 41 + .../model_secretstoreresource.go | 10 + .../model_syncbackupinstancerequest.go | 8 + .../backupinstances/model_targetdetails.go | 10 + .../model_triggerbackuprequest.go | 8 + .../backupinstances/model_userfacingerror.go | 16 + .../model_validateforbackuprequest.go | 8 + .../model_validaterestorerequestobject.go | 32 + .../2022-04-01/backupinstances/predicates.go | 24 + .../2022-04-01/backupinstances/version.go | 12 + .../2022-04-01/backuppolicies/README.md | 90 + .../2022-04-01/backuppolicies/client.go | 18 + .../2022-04-01/backuppolicies/constants.go | 212 + .../backuppolicies/id_backuppolicies.go | 137 + .../backuppolicies/id_backupvault.go | 124 + .../method_createorupdate_autorest.go | 69 + .../backuppolicies/method_delete_autorest.go | 66 + .../backuppolicies/method_get_autorest.go | 68 + .../backuppolicies/method_list_autorest.go | 186 + .../model_absolutedeleteoption.go | 41 + .../model_adhocbasedtaggingcriteria.go | 8 + .../model_adhocbasedtriggercontext.go | 41 + .../backuppolicies/model_azurebackupparams.go | 41 + .../backuppolicies/model_azurebackuprule.go | 79 + .../model_azureretentionrule.go | 43 + .../backuppolicies/model_backupcriteria.go | 48 + .../backuppolicies/model_backupparameters.go | 48 + .../backuppolicies/model_backuppolicy.go | 77 + .../backuppolicies/model_backupschedule.go | 9 + .../backuppolicies/model_basebackuppolicy.go | 48 + .../model_basebackuppolicyresource.go | 48 + .../backuppolicies/model_basepolicyrule.go | 56 + .../model_copyonexpiryoption.go | 40 + .../backuppolicies/model_copyoption.go | 64 + .../backuppolicies/model_customcopyoption.go | 41 + .../backuppolicies/model_datastoreinfobase.go | 9 + .../2022-04-01/backuppolicies/model_day.go | 9 + .../backuppolicies/model_deleteoption.go | 48 + .../model_immediatecopyoption.go | 40 + .../backuppolicies/model_retentiontag.go | 10 + .../model_schedulebasedbackupcriteria.go | 46 + .../model_schedulebasedtriggercontext.go | 42 + .../backuppolicies/model_sourcelifecycle.go | 42 + .../backuppolicies/model_taggingcriteria.go | 53 + .../backuppolicies/model_targetcopysetting.go | 40 + .../backuppolicies/model_triggercontext.go | 56 + .../2022-04-01/backuppolicies/predicates.go | 24 + .../2022-04-01/backuppolicies/version.go | 12 + .../2022-04-01/backupvaults/README.md | 141 + .../2022-04-01/backupvaults/client.go | 18 + .../2022-04-01/backupvaults/constants.go | 182 + .../2022-04-01/backupvaults/id_backupvault.go | 124 + .../backupvaults/id_providerlocation.go | 124 + .../method_checknameavailability_autorest.go | 70 + .../method_createorupdate_autorest.go | 79 + .../backupvaults/method_delete_autorest.go | 66 + .../backupvaults/method_get_autorest.go | 68 + .../method_getinresourcegroup_autorest.go | 187 + .../method_getinsubscription_autorest.go | 187 + .../backupvaults/method_update_autorest.go | 79 + .../model_azuremonitoralertsettings.go | 8 + .../backupvaults/model_backupvault.go | 12 + .../backupvaults/model_backupvaultresource.go | 20 + .../model_checknameavailabilityrequest.go | 9 + .../model_checknameavailabilityresult.go | 10 + .../backupvaults/model_dppidentitydetails.go | 10 + .../backupvaults/model_monitoringsettings.go | 8 + .../model_patchbackupvaultinput.go | 8 + .../model_patchresourcerequestinput.go | 10 + .../backupvaults/model_resourcemovedetails.go | 12 + .../backupvaults/model_storagesetting.go | 9 + .../2022-04-01/backupvaults/predicates.go | 34 + .../2022-04-01/backupvaults/version.go | 12 + .../2022-04-01/resourceguards/README.md | 4 +- .../resourceguards/method_delete_autorest.go | 1 + .../resourceguards/method_get_autorest.go | 1 + ...ckupsecuritypinrequestsobjects_autorest.go | 88 +- ...ackupsecuritypinrequestsobject_autorest.go | 1 + ...eteprotecteditemrequestsobject_autorest.go | 1 + ...sourceguardproxyrequestsobject_autorest.go | 1 + ...isablesoftdeleterequestsobject_autorest.go | 1 + ...ateprotecteditemrequestsobject_autorest.go | 1 + ...protectionpolicyrequestsobject_autorest.go | 1 + ...teprotecteditemrequestsobjects_autorest.go | 88 +- ...ourceguardproxyrequestsobjects_autorest.go | 88 +- ...sablesoftdeleterequestsobjects_autorest.go | 88 +- ...od_getresourcesinresourcegroup_autorest.go | 88 +- ...hod_getresourcesinsubscription_autorest.go | 88 +- ...teprotecteditemrequestsobjects_autorest.go | 88 +- ...rotectionpolicyrequestsobjects_autorest.go | 88 +- .../resourceguards/method_patch_autorest.go | 1 + .../resourceguards/method_put_autorest.go | 1 + .../applicationgroup/README.md | 4 +- .../method_createorupdate_autorest.go | 1 + .../method_delete_autorest.go | 1 + .../applicationgroup/method_get_autorest.go | 1 + .../method_listbyresourcegroup_autorest.go | 88 +- .../method_listbysubscription_autorest.go | 88 +- .../method_update_autorest.go | 1 + .../2021-09-03-preview/hostpool/README.md | 4 +- .../method_createorupdate_autorest.go | 1 + .../hostpool/method_delete_autorest.go | 1 + .../hostpool/method_get_autorest.go | 1 + .../hostpool/method_list_autorest.go | 88 +- .../method_listbyresourcegroup_autorest.go | 88 +- ...thod_retrieveregistrationtoken_autorest.go | 1 + .../hostpool/method_update_autorest.go | 1 + .../2021-09-03-preview/workspace/README.md | 4 +- .../method_createorupdate_autorest.go | 1 + .../workspace/method_delete_autorest.go | 1 + .../workspace/method_get_autorest.go | 1 + .../method_listbyresourcegroup_autorest.go | 88 +- .../method_listbysubscription_autorest.go | 88 +- .../workspace/method_update_autorest.go | 1 + .../method_createorupdate_autorest.go | 1 + .../application/method_delete_autorest.go | 1 + .../application/method_get_autorest.go | 1 + .../application/method_list_autorest.go | 88 +- .../application/method_update_autorest.go | 1 + .../desktop/method_get_autorest.go | 1 + .../desktop/method_list_autorest.go | 88 +- .../desktop/method_update_autorest.go | 1 + .../2022-02-10-preview/scalingplan/README.md | 4 +- .../scalingplan/method_create_autorest.go | 1 + .../scalingplan/method_delete_autorest.go | 1 + .../scalingplan/method_get_autorest.go | 1 + .../method_listbyhostpool_autorest.go | 88 +- .../method_listbyresourcegroup_autorest.go | 88 +- .../method_listbysubscription_autorest.go | 88 +- .../scalingplan/method_update_autorest.go | 1 + .../sessionhost/method_delete_autorest.go | 1 + .../sessionhost/method_get_autorest.go | 1 + .../sessionhost/method_list_autorest.go | 88 +- .../sessionhost/method_update_autorest.go | 1 + .../resource-manager/dns/2018-05-01/client.go | 32 + .../dns/2018-05-01/dns/README.md | 41 + .../dns/2018-05-01/dns/client.go | 18 + ...ereferencegetbytargetresources_autorest.go | 71 + .../dns/model_dnsresourcereference.go | 9 + .../dns/model_dnsresourcereferencerequest.go | 8 + ...l_dnsresourcereferencerequestproperties.go | 8 + .../dns/model_dnsresourcereferenceresult.go | 8 + ...el_dnsresourcereferenceresultproperties.go | 8 + .../dns/2018-05-01/dns/model_subresource.go | 8 + .../dns/2018-05-01/dns/version.go | 12 + .../dns/2018-05-01/recordsets/README.md | 145 + .../dns/2018-05-01/recordsets/client.go | 18 + .../dns/2018-05-01/recordsets/constants.go | 58 + .../dns/2018-05-01/recordsets/id_dnszone.go | 124 + .../2018-05-01/recordsets/id_recordtype.go | 164 + .../dns/2018-05-01/recordsets/id_zone.go | 152 + .../method_createorupdate_autorest.go | 103 + .../recordsets/method_delete_autorest.go | 95 + .../recordsets/method_get_autorest.go | 68 + .../method_listallbydnszone_autorest.go | 220 + .../method_listbydnszone_autorest.go | 220 + .../recordsets/method_listbytype_autorest.go | 220 + .../recordsets/method_update_autorest.go | 98 + .../2018-05-01/recordsets/model_aaaarecord.go | 8 + .../2018-05-01/recordsets/model_arecord.go | 8 + .../2018-05-01/recordsets/model_caarecord.go | 10 + .../recordsets/model_cnamerecord.go | 8 + .../2018-05-01/recordsets/model_mxrecord.go | 9 + .../2018-05-01/recordsets/model_nsrecord.go | 8 + .../2018-05-01/recordsets/model_ptrrecord.go | 8 + .../2018-05-01/recordsets/model_recordset.go | 12 + .../recordsets/model_recordsetproperties.go | 22 + .../2018-05-01/recordsets/model_soarecord.go | 14 + .../2018-05-01/recordsets/model_srvrecord.go | 11 + .../recordsets/model_subresource.go | 8 + .../2018-05-01/recordsets/model_txtrecord.go | 8 + .../dns/2018-05-01/recordsets/predicates.go | 29 + .../dns/2018-05-01/recordsets/version.go | 12 + .../dns/2018-05-01/zones/README.md | 124 + .../dns/2018-05-01/zones/client.go | 18 + .../dns/2018-05-01/zones/constants.go | 34 + .../dns/2018-05-01/zones/id_dnszone.go | 124 + .../zones/method_createorupdate_autorest.go | 103 + .../zones/method_delete_autorest.go | 107 + .../2018-05-01/zones/method_get_autorest.go | 68 + .../2018-05-01/zones/method_list_autorest.go | 216 + .../method_listbyresourcegroup_autorest.go | 216 + .../zones/method_update_autorest.go | 98 + .../dns/2018-05-01/zones/model_subresource.go | 8 + .../dns/2018-05-01/zones/model_zone.go | 14 + .../2018-05-01/zones/model_zoneproperties.go | 14 + .../dns/2018-05-01/zones/model_zoneupdate.go | 8 + .../dns/2018-05-01/zones/predicates.go | 34 + .../dns/2018-05-01/zones/version.go | 12 + .../2020-07-01/monitorsresource/README.md | 4 +- .../method_monitorsget_autorest.go | 1 + .../method_monitorslist_autorest.go | 88 +- ...od_monitorslistbyresourcegroup_autorest.go | 88 +- .../method_monitorsupdate_autorest.go | 1 + .../method_tagrulescreateorupdate_autorest.go | 1 + .../rules/method_tagrulesget_autorest.go | 1 + .../rules/method_tagruleslist_autorest.go | 88 +- .../authorizationruleseventhubs/README.md | 95 - .../model_authorizationrule.go | 11 - .../authorizationruleseventhubs/predicates.go | 24 - .../authorizationruleseventhubs/version.go | 12 - .../authorizationrulesnamespaces/README.md | 127 - .../model_authorizationrule.go | 11 - .../predicates.go | 24 - .../authorizationrulesnamespaces/version.go | 12 - .../README.md | 41 - .../version.go | 12 - .../2017-04-01/consumergroups/README.md | 90 - .../method_createorupdate_autorest.go | 68 - .../consumergroups/method_delete_autorest.go | 65 - .../consumergroups/method_get_autorest.go | 67 - .../consumergroups/model_consumergroup.go | 11 - .../2017-04-01/consumergroups/predicates.go | 24 - .../2017-04-01/consumergroups/version.go | 12 - .../disasterrecoveryconfigs/README.md | 122 - .../method_createorupdate_autorest.go | 68 - .../method_delete_autorest.go | 65 - .../method_get_autorest.go | 67 - .../method_list_autorest.go | 186 - .../model_armdisasterrecovery.go | 11 - .../disasterrecoveryconfigs/predicates.go | 24 - .../disasterrecoveryconfigs/version.go | 12 - .../eventhub/2017-04-01/eventhubs/README.md | 122 - .../method_createorupdate_autorest.go | 68 - .../eventhubs/method_delete_autorest.go | 65 - .../eventhubs/method_get_autorest.go | 67 - .../method_listbynamespace_autorest.go | 220 - .../eventhubs/model_authorizationrule.go | 11 - .../eventhubs/model_destinationproperties.go | 10 - .../2017-04-01/eventhubs/model_eventhub.go | 11 - .../2017-04-01/eventhubs/predicates.go | 24 - .../eventhub/2017-04-01/eventhubs/version.go | 12 - .../eventhubsclusters/README.md | 99 - .../eventhubsclusters/model_cluster.go | 14 - .../eventhubsclusters/version.go | 12 - .../networkrulesets/README.md | 57 - .../networkrulesets/constants.go | 59 - .../networkrulesets/model_networkruleset.go | 11 - .../model_networkrulesetproperties.go | 11 - .../networkrulesets/model_nwrulesetiprules.go | 9 - .../networkrulesets/version.go | 12 - .../2021-01-01-preview/namespaces/README.md | 120 - .../namespaces/method_get_autorest.go | 67 - .../namespaces/method_list_autorest.go | 187 - .../method_listbyresourcegroup_autorest.go | 187 - .../namespaces/method_update_autorest.go | 68 - .../namespaces/model_ehnamespaceproperties.go | 50 - .../model_privateendpointconnection.go | 16 - .../2021-01-01-preview/namespaces/version.go | 12 - .../authorizationruleseventhubs/README.md | 95 + .../authorizationruleseventhubs/client.go | 0 .../authorizationruleseventhubs/constants.go | 0 .../id_eventhub.go | 0 .../id_eventhubauthorizationrule.go | 0 ...reateorupdateauthorizationrule_autorest.go | 1 + ...venthubslistauthorizationrules_autorest.go | 88 +- .../method_eventhubslistkeys_autorest.go | 1 + ...method_eventhubsregeneratekeys_autorest.go | 1 + .../model_accesskeys.go | 0 .../model_authorizationrule.go | 17 + .../model_authorizationruleproperties.go | 0 .../model_regenerateaccesskeyparameters.go | 0 .../authorizationruleseventhubs/predicates.go | 29 + .../authorizationruleseventhubs/version.go | 12 + .../authorizationrulesnamespaces/README.md | 127 + .../authorizationrulesnamespaces/client.go | 0 .../authorizationrulesnamespaces/constants.go | 0 .../id_authorizationrule.go | 0 .../id_namespace.go | 0 ...reateorupdateauthorizationrule_autorest.go | 1 + ...espacesdeleteauthorizationrule_autorest.go | 1 + ...namespacesgetauthorizationrule_autorest.go | 1 + ...mespaceslistauthorizationrules_autorest.go | 88 +- .../method_namespaceslistkeys_autorest.go | 1 + ...ethod_namespacesregeneratekeys_autorest.go | 1 + .../model_accesskeys.go | 0 .../model_authorizationrule.go | 17 + .../model_authorizationruleproperties.go | 0 .../model_regenerateaccesskeyparameters.go | 0 .../predicates.go | 29 + .../authorizationrulesnamespaces/version.go | 12 + .../README.md | 41 + .../client.go | 0 .../constants.go | 0 .../id_namespace.go | 0 ...ryconfigschecknameavailability_autorest.go | 1 + .../model_checknameavailabilityparameter.go | 0 .../model_checknameavailabilityresult.go | 0 .../version.go | 12 + .../2021-11-01/consumergroups/README.md | 90 + .../consumergroups/client.go | 0 .../consumergroups/id_consumergroup.go | 0 .../consumergroups/id_eventhub.go | 0 .../method_createorupdate_autorest.go | 69 + .../consumergroups/method_delete_autorest.go | 66 + .../consumergroups/method_get_autorest.go | 68 + .../method_listbyeventhub_autorest.go | 88 +- .../consumergroups/model_consumergroup.go | 17 + .../model_consumergroupproperties.go | 0 .../2021-11-01/consumergroups/predicates.go | 29 + .../2021-11-01/consumergroups/version.go | 12 + .../disasterrecoveryconfigs/README.md | 122 + .../disasterrecoveryconfigs/client.go | 0 .../disasterrecoveryconfigs/constants.go | 0 .../id_disasterrecoveryconfig.go | 0 .../disasterrecoveryconfigs/id_namespace.go | 0 .../method_breakpairing_autorest.go | 1 + .../method_createorupdate_autorest.go | 69 + .../method_delete_autorest.go | 66 + .../method_failover_autorest.go | 1 + .../method_get_autorest.go | 68 + .../method_list_autorest.go | 186 + .../model_armdisasterrecovery.go | 17 + .../model_armdisasterrecoveryproperties.go | 0 .../disasterrecoveryconfigs/predicates.go | 29 + .../disasterrecoveryconfigs/version.go | 12 + .../eventhub/2021-11-01/eventhubs/README.md | 122 + .../eventhubs/client.go | 0 .../eventhubs/constants.go | 0 .../eventhubs/id_eventhub.go | 0 .../eventhubs/id_eventhubauthorizationrule.go | 0 .../eventhubs/id_namespace.go | 0 .../method_createorupdate_autorest.go | 69 + .../eventhubs/method_delete_autorest.go | 66 + ...method_deleteauthorizationrule_autorest.go | 1 + .../eventhubs/method_get_autorest.go | 68 + .../method_getauthorizationrule_autorest.go | 1 + .../method_listbynamespace_autorest.go | 220 + .../eventhubs/model_authorizationrule.go | 17 + .../model_authorizationruleproperties.go | 0 .../eventhubs/model_capturedescription.go | 0 .../eventhubs/model_destination.go | 0 .../eventhubs/model_destinationproperties.go | 13 + .../2021-11-01/eventhubs/model_eventhub.go | 17 + .../eventhubs/model_eventhubproperties.go | 0 .../2021-11-01/eventhubs/predicates.go | 29 + .../eventhub/2021-11-01/eventhubs/version.go | 12 + .../2021-11-01/eventhubsclusters/README.md | 116 + .../eventhubsclusters/client.go | 0 .../eventhubsclusters/constants.go | 0 .../eventhubsclusters/id_cluster.go | 0 .../method_clusterscreateorupdate_autorest.go | 0 .../method_clustersdelete_autorest.go | 0 .../method_clustersget_autorest.go | 1 + ...od_clusterslistbyresourcegroup_autorest.go | 88 +- ...hod_clusterslistbysubscription_autorest.go | 187 + .../method_clustersupdate_autorest.go | 0 .../eventhubsclusters/model_cluster.go | 19 + .../model_clusterproperties.go | 0 .../eventhubsclusters/model_clustersku.go | 0 .../eventhubsclusters/predicates.go | 0 .../2021-11-01/eventhubsclusters/version.go | 12 + .../eventhub/2021-11-01/namespaces/README.md | 120 + .../namespaces/client.go | 0 .../namespaces/constants.go | 0 .../namespaces/id_namespace.go | 0 .../method_createorupdate_autorest.go | 0 .../namespaces/method_delete_autorest.go | 0 .../namespaces/method_get_autorest.go | 68 + .../namespaces/method_list_autorest.go | 187 + .../method_listbyresourcegroup_autorest.go | 187 + .../namespaces/method_update_autorest.go | 69 + .../namespaces/model_connectionstate.go | 0 .../namespaces/model_ehnamespace.go | 0 .../namespaces/model_ehnamespaceproperties.go | 52 + .../namespaces/model_encryption.go | 0 .../namespaces/model_keyvaultproperties.go | 0 .../namespaces/model_privateendpoint.go | 0 .../model_privateendpointconnection.go | 17 + ...del_privateendpointconnectionproperties.go | 0 .../namespaces/model_sku.go | 0 .../model_userassignedidentityproperties.go | 0 .../namespaces/predicates.go | 0 .../eventhub/2021-11-01/namespaces/version.go | 12 + .../2021-11-01/networkrulesets/README.md | 73 + .../networkrulesets/client.go | 0 .../2021-11-01/networkrulesets/constants.go | 87 + .../networkrulesets/id_namespace.go | 0 ...escreateorupdatenetworkruleset_autorest.go | 1 + ...od_namespacesgetnetworkruleset_autorest.go | 1 + ...d_namespaceslistnetworkruleset_autorest.go | 69 + .../networkrulesets/model_networkruleset.go | 17 + .../model_networkrulesetlistresult.go | 9 + .../model_networkrulesetproperties.go | 12 + .../networkrulesets/model_nwrulesetiprules.go | 9 + .../model_nwrulesetvirtualnetworkrules.go | 0 .../networkrulesets/model_subnet.go | 0 .../2021-11-01/networkrulesets/version.go | 12 + .../2021-11-01/schemaregistry/README.md | 90 + .../2021-11-01/schemaregistry/client.go | 18 + .../2021-11-01/schemaregistry/constants.go | 65 + .../2021-11-01/schemaregistry/id_namespace.go | 124 + .../schemaregistry/id_schemagroup.go | 137 + .../method_createorupdate_autorest.go | 69 + .../schemaregistry/method_delete_autorest.go | 66 + .../schemaregistry/method_get_autorest.go | 68 + .../method_listbynamespace_autorest.go | 220 + .../schemaregistry/model_schemagroup.go | 17 + .../model_schemagroupproperties.go | 43 + .../2021-11-01/schemaregistry/predicates.go | 29 + .../2021-11-01/schemaregistry/version.go | 12 + .../2022-01-01-preview/namespaces/README.md | 120 + .../2022-01-01-preview}/namespaces/client.go | 0 .../namespaces/constants.go | 229 + .../namespaces/id_namespace.go | 124 + .../method_createorupdate_autorest.go | 79 + .../namespaces/method_delete_autorest.go | 0 .../namespaces/method_get_autorest.go | 68 + .../namespaces/method_list_autorest.go | 187 + .../method_listbyresourcegroup_autorest.go | 187 + .../namespaces/method_update_autorest.go | 69 + .../namespaces/model_connectionstate.go | 0 .../namespaces/model_ehnamespace.go | 21 + .../namespaces/model_ehnamespaceproperties.go | 54 + .../namespaces/model_encryption.go | 0 .../namespaces/model_keyvaultproperties.go | 0 .../namespaces/model_privateendpoint.go | 0 .../model_privateendpointconnection.go | 17 + ...del_privateendpointconnectionproperties.go | 0 .../namespaces/model_sku.go | 10 + .../model_userassignedidentityproperties.go | 0 .../namespaces/predicates.go | 29 + .../2022-01-01-preview/namespaces/version.go | 12 + .../2022-05-26/fluidrelayservers/README.md | 4 +- .../method_createorupdate_autorest.go | 1 + .../method_delete_autorest.go | 1 + .../fluidrelayservers/method_get_autorest.go | 1 + .../method_getkeys_autorest.go | 1 + .../method_listbyresourcegroup_autorest.go | 88 +- .../method_listbysubscription_autorest.go | 88 +- .../method_listkeys_autorest.go | 1 + .../method_regeneratekey_autorest.go | 1 + .../method_update_autorest.go | 1 + .../2021-11-30/dedicatedhsms/README.md | 4 +- .../method_dedicatedhsmget_autorest.go | 1 + ...edicatedhsmlistbyresourcegroup_autorest.go | 88 +- ...dedicatedhsmlistbysubscription_autorest.go | 88 +- ...ndnetworkdependenciesendpoints_autorest.go | 88 +- .../dedicatedhsms/model_endpointdetail.go | 2 +- .../dedicatedhsms/model_networkinterface.go | 2 +- .../datacollectionendpoints/README.md | 128 + .../datacollectionendpoints/client.go | 18 + .../datacollectionendpoints/constants.go | 99 + .../id_datacollectionendpoint.go | 124 + .../method_create_autorest.go | 69 + .../method_delete_autorest.go | 66 + .../method_get_autorest.go | 68 + .../method_listbyresourcegroup_autorest.go | 187 + .../method_listbysubscription_autorest.go | 187 + .../method_update_autorest.go | 69 + .../model_configurationaccessendpointspec.go | 8 + .../model_datacollectionendpoint.go | 13 + .../model_datacollectionendpointresource.go | 20 + .../model_logsingestionendpointspec.go | 8 + .../model_networkruleset.go | 8 + .../model_resourceforupdate.go | 8 + .../datacollectionendpoints/predicates.go | 34 + .../datacollectionendpoints/version.go | 12 + .../2021-04-01/datacollectionrules/README.md | 128 + .../2021-04-01/datacollectionrules/client.go | 18 + .../datacollectionrules/constants.go | 360 + .../id_datacollectionrule.go | 124 + .../method_create_autorest.go | 69 + .../method_delete_autorest.go | 66 + .../method_get_autorest.go | 68 + .../method_listbyresourcegroup_autorest.go | 187 + .../method_listbysubscription_autorest.go | 187 + .../method_update_autorest.go | 69 + .../model_azuremonitormetricsdestination.go | 8 + .../model_datacollectionrule.go | 13 + .../model_datacollectionruleresource.go | 20 + .../datacollectionrules/model_dataflow.go | 9 + .../model_datasourcesspec.go | 11 + .../model_destinationsspec.go | 9 + .../model_extensiondatasource.go | 12 + .../model_loganalyticsdestination.go | 10 + .../model_perfcounterdatasource.go | 11 + .../model_resourceforupdate.go | 8 + .../model_syslogdatasource.go | 11 + .../model_windowseventlogdatasource.go | 10 + .../datacollectionrules/predicates.go | 34 + .../2021-04-01/datacollectionrules/version.go | 12 + .../diagnosticsettings/README.md | 89 + .../diagnosticsettings/client.go | 18 + .../id_scopeddiagnosticsetting.go | 110 + .../method_createorupdate_autorest.go | 69 + .../method_delete_autorest.go | 66 + .../diagnosticsettings/method_get_autorest.go | 68 + .../method_list_autorest.go | 70 + .../model_diagnosticsettings.go | 16 + .../model_diagnosticsettingsresource.go | 16 + ...el_diagnosticsettingsresourcecollection.go | 8 + .../diagnosticsettings/model_logsettings.go | 11 + .../model_metricsettings.go | 11 + .../model_retentionpolicy.go | 9 + .../diagnosticsettings/version.go | 12 + .../diagnosticsettingscategories/README.md | 52 + .../diagnosticsettingscategories/client.go | 18 + .../diagnosticsettingscategories/constants.go | 34 + .../id_scopeddiagnosticsettingscategories.go | 110 + ..._diagnosticsettingscategoryget_autorest.go | 68 + ...diagnosticsettingscategorylist_autorest.go | 70 + .../model_diagnosticsettingscategory.go | 9 + ...odel_diagnosticsettingscategoryresource.go | 16 + ...osticsettingscategoryresourcecollection.go | 8 + .../diagnosticsettingscategories/version.go | 12 + .../2021-08-01/scheduledqueryrules/README.md | 128 + .../2021-08-01/scheduledqueryrules/client.go | 18 + .../scheduledqueryrules/constants.go | 173 + .../id_scheduledqueryrule.go | 124 + .../method_createorupdate_autorest.go | 69 + .../method_delete_autorest.go | 66 + .../method_get_autorest.go | 68 + .../method_listbyresourcegroup_autorest.go | 187 + .../method_listbysubscription_autorest.go | 187 + .../method_update_autorest.go | 69 + .../scheduledqueryrules/model_actions.go | 9 + .../scheduledqueryrules/model_condition.go | 16 + .../model_conditionfailingperiods.go | 9 + .../scheduledqueryrules/model_dimension.go | 10 + .../model_scheduledqueryrulecriteria.go | 8 + .../model_scheduledqueryruleproperties.go | 25 + .../model_scheduledqueryruleresource.go | 20 + .../model_scheduledqueryruleresourcepatch.go | 9 + .../scheduledqueryrules/predicates.go | 34 + .../2021-08-01/scheduledqueryrules/version.go | 12 + .../2021-11-01-preview/apps/README.md | 10 +- .../2021-11-01-preview/apps/constants.go | 16 +- .../method_checknameavailability_autorest.go | 1 + ...hod_checksubdomainavailability_autorest.go | 1 + .../apps/method_get_autorest.go | 1 + .../method_listbyresourcegroup_autorest.go | 88 +- .../method_listbysubscription_autorest.go | 88 +- .../apps/method_listtemplates_autorest.go | 88 +- .../apps/model_networkrulesetiprule.go | 6 +- .../apps/model_networkrulesets.go | 2 +- .../2021-12-01-preview/loadtests/README.md | 4 +- .../method_createorupdate_autorest.go | 1 + .../loadtests/method_get_autorest.go | 1 + .../method_listbyresourcegroup_autorest.go | 88 +- .../method_listbysubscription_autorest.go | 88 +- .../loadtests/method_update_autorest.go | 1 + .../configurationassignments/README.md | 126 + .../configurationassignments/client.go | 18 + .../id_configurationassignment.go | 161 + .../configurationassignments/id_provider.go | 146 + .../id_providers2configurationassignment.go | 185 + .../id_resourcegroupprovider.go | 170 + .../method_createorupdate_autorest.go | 69 + .../method_createorupdateparent_autorest.go | 69 + .../method_delete_autorest.go | 68 + .../method_deleteparent_autorest.go | 68 + .../method_list_autorest.go | 69 + .../method_listparent_autorest.go | 69 + .../model_configurationassignment.go | 17 + ...model_configurationassignmentproperties.go | 9 + ...odel_listconfigurationassignmentsresult.go | 8 + .../configurationassignments/version.go | 12 + .../maintenanceconfigurations/README.md | 126 + .../maintenanceconfigurations/client.go | 18 + .../maintenanceconfigurations/constants.go | 74 + .../id_maintenanceconfiguration.go | 124 + .../method_createorupdate_autorest.go | 69 + .../method_delete_autorest.go | 68 + .../method_forresourcegrouplist_autorest.go | 70 + .../method_get_autorest.go | 68 + .../method_list_autorest.go | 70 + .../method_update_autorest.go | 69 + ...del_listmaintenanceconfigurationsresult.go | 8 + .../model_maintenanceconfiguration.go | 18 + ...odel_maintenanceconfigurationproperties.go | 12 + .../model_maintenancewindow.go | 12 + .../maintenanceconfigurations/version.go | 12 + .../publicmaintenanceconfigurations/README.md | 52 + .../publicmaintenanceconfigurations/client.go | 18 + .../constants.go | 74 + .../id_publicmaintenanceconfiguration.go | 111 + .../method_get_autorest.go | 68 + .../method_list_autorest.go | 70 + ...del_listmaintenanceconfigurationsresult.go | 8 + .../model_maintenanceconfiguration.go | 18 + ...odel_maintenanceconfigurationproperties.go | 12 + .../model_maintenancewindow.go | 12 + .../version.go | 12 + .../2018-11-30/managedidentities/README.md | 144 + .../2018-11-30/managedidentities/client.go | 18 + ...emassignedidentitiesgetbyscope_autorest.go | 70 + ...signedidentitiescreateorupdate_autorest.go | 70 + ...d_userassignedidentitiesdelete_autorest.go | 67 + ...thod_userassignedidentitiesget_autorest.go | 69 + ...didentitieslistbyresourcegroup_autorest.go | 187 + ...edidentitieslistbysubscription_autorest.go | 187 + ...d_userassignedidentitiesupdate_autorest.go | 70 + .../model_identity.go | 2 +- .../model_identityupdate.go | 2 +- .../model_systemassignedidentity.go | 2 +- .../model_systemassignedidentityproperties.go | 2 +- .../model_userassignedidentityproperties.go | 10 + .../managedidentities/predicates.go | 29 + .../2018-11-30/managedidentities/version.go | 12 + .../2018-11-30/managedidentity/README.md | 144 - .../2018-11-30/managedidentity/client.go | 18 - ...emassignedidentitiesgetbyscope_autorest.go | 69 - ...signedidentitiescreateorupdate_autorest.go | 69 - ...d_userassignedidentitiesdelete_autorest.go | 66 - ...thod_userassignedidentitiesget_autorest.go | 68 - ...didentitieslistbyresourcegroup_autorest.go | 187 - ...edidentitieslistbysubscription_autorest.go | 187 - ...d_userassignedidentitiesupdate_autorest.go | 69 - .../model_userassignedidentityproperties.go | 10 - .../2018-11-30/managedidentity/predicates.go | 29 - .../2018-11-30/managedidentity/version.go | 12 - .../registrationassignments/README.md | 2 +- .../method_get_autorest.go | 1 + .../method_list_autorest.go | 88 +- .../registrationdefinitions/README.md | 2 +- .../method_delete_autorest.go | 1 + .../method_get_autorest.go | 1 + .../method_list_autorest.go | 88 +- .../maps/2021-02-01/accounts/README.md | 4 +- .../method_createorupdate_autorest.go | 1 + .../accounts/method_delete_autorest.go | 1 + .../accounts/method_get_autorest.go | 1 + .../method_listbyresourcegroup_autorest.go | 88 +- .../method_listbysubscription_autorest.go | 88 +- .../accounts/method_listkeys_autorest.go | 1 + .../method_regeneratekeys_autorest.go | 1 + .../accounts/method_update_autorest.go | 1 + .../method_createorupdate_autorest.go | 1 + .../creators/method_delete_autorest.go | 1 + .../creators/method_get_autorest.go | 1 + .../creators/method_listbyaccount_autorest.go | 88 +- .../creators/method_update_autorest.go | 1 + .../2018-06-01/configurations/README.md | 69 + .../2018-06-01/configurations/client.go | 18 + .../configurations/id_configuration.go | 137 + .../2018-06-01/configurations/id_server.go | 124 + .../method_createorupdate_autorest.go | 79 + .../configurations/method_get_autorest.go | 68 + .../method_listbyserver_autorest.go | 69 + .../configurations/model_configuration.go | 11 + .../model_configurationlistresult.go | 8 + .../model_configurationproperties.go | 13 + .../2018-06-01/configurations/version.go | 12 + .../mariadb/2018-06-01/databases/README.md | 81 + .../mariadb/2018-06-01/databases/client.go | 18 + .../2018-06-01/databases/id_database.go | 137 + .../mariadb/2018-06-01/databases/id_server.go | 124 + .../method_createorupdate_autorest.go | 79 + .../databases/method_delete_autorest.go | 78 + .../databases/method_get_autorest.go | 68 + .../databases/method_listbyserver_autorest.go | 69 + .../2018-06-01/databases/model_database.go | 11 + .../databases/model_databaselistresult.go | 8 + .../databases/model_databaseproperties.go | 9 + .../mariadb/2018-06-01/databases/version.go | 12 + .../2018-06-01/firewallrules/README.md | 81 + .../2018-06-01/firewallrules/client.go | 18 + .../firewallrules/id_firewallrule.go | 137 + .../2018-06-01/firewallrules/id_server.go | 124 + .../method_createorupdate_autorest.go | 79 + .../firewallrules/method_delete_autorest.go | 78 + .../firewallrules/method_get_autorest.go | 68 + .../method_listbyserver_autorest.go | 69 + .../firewallrules/model_firewallrule.go | 11 + .../model_firewallrulelistresult.go | 8 + .../model_firewallruleproperties.go | 9 + .../2018-06-01/firewallrules/version.go | 12 + .../mariadb/2018-06-01/servers/README.md | 114 + .../mariadb/2018-06-01/servers/client.go | 18 + .../mariadb/2018-06-01/servers/constants.go | 372 + .../mariadb/2018-06-01/servers/id_server.go | 124 + .../servers/method_create_autorest.go | 79 + .../servers/method_delete_autorest.go | 78 + .../2018-06-01/servers/method_get_autorest.go | 68 + .../servers/method_list_autorest.go | 70 + .../method_listbyresourcegroup_autorest.go | 70 + .../servers/method_update_autorest.go | 79 + .../servers/model_privateendpointproperty.go | 8 + .../2018-06-01/servers/model_server.go | 14 + .../servers/model_serverforcreate.go | 44 + .../servers/model_serverlistresult.go | 8 + .../model_serverprivateendpointconnection.go | 9 + ...rverprivateendpointconnectionproperties.go | 10 + ...ivatelinkserviceconnectionstateproperty.go | 10 + .../servers/model_serverproperties.go | 38 + .../model_serverpropertiesforcreate.go | 72 + .../model_serverpropertiesfordefaultcreate.go | 47 + .../model_serverpropertiesforgeorestore.go | 46 + .../model_serverpropertiesforreplica.go | 46 + .../model_serverpropertiesforrestore.go | 47 + .../servers/model_serverupdateparameters.go | 10 + .../model_serverupdateparametersproperties.go | 14 + .../mariadb/2018-06-01/servers/model_sku.go | 12 + .../servers/model_storageprofile.go | 11 + .../mariadb/2018-06-01/servers/version.go | 12 + .../2018-06-01/virtualnetworkrules/README.md | 82 + .../2018-06-01/virtualnetworkrules/client.go | 18 + .../virtualnetworkrules/constants.go | 43 + .../virtualnetworkrules/id_server.go | 124 + .../id_virtualnetworkrule.go | 137 + .../method_createorupdate_autorest.go | 79 + .../method_delete_autorest.go | 78 + .../method_get_autorest.go | 68 + .../method_listbyserver_autorest.go | 186 + .../model_virtualnetworkrule.go | 11 + .../model_virtualnetworkruleproperties.go | 10 + .../virtualnetworkrules/predicates.go | 24 + .../2018-06-01/virtualnetworkrules/version.go | 12 + .../2021-01-01/resource/README.md | 8 +- ..._remoterenderingaccountscreate_autorest.go | 1 + ..._remoterenderingaccountsdelete_autorest.go | 1 + ...hod_remoterenderingaccountsget_autorest.go | 1 + ...ingaccountslistbyresourcegroup_autorest.go | 88 +- ...ringaccountslistbysubscription_autorest.go | 88 +- ..._remoterenderingaccountsupdate_autorest.go | 1 + ...d_spatialanchorsaccountscreate_autorest.go | 1 + ...d_spatialanchorsaccountsdelete_autorest.go | 1 + ...thod_spatialanchorsaccountsget_autorest.go | 1 + ...orsaccountslistbyresourcegroup_autorest.go | 88 +- ...horsaccountslistbysubscription_autorest.go | 88 +- ...d_spatialanchorsaccountsupdate_autorest.go | 1 + .../capacitypools/method_poolsget_autorest.go | 1 + .../method_poolslist_autorest.go | 88 +- .../2021-10-01/netappaccounts/README.md | 4 +- .../method_accountsget_autorest.go | 1 + .../method_accountslist_autorest.go | 88 +- ...hod_accountslistbysubscription_autorest.go | 88 +- .../method_snapshotpoliciescreate_autorest.go | 1 + .../method_snapshotpoliciesget_autorest.go | 1 + .../method_snapshotpolicieslist_autorest.go | 1 + .../snapshots/method_get_autorest.go | 1 + .../snapshots/method_list_autorest.go | 1 + .../2021-10-01/volumes/method_get_autorest.go | 1 + .../volumes/method_list_autorest.go | 88 +- .../volumes/model_mounttargetproperties.go | 2 +- ...ethod_volumesreplicationstatus_autorest.go | 1 + .../2017-04-01/namespaces/README.md | 6 +- .../method_checkavailability_autorest.go | 1 + .../method_createorupdate_autorest.go | 1 + ...reateorupdateauthorizationrule_autorest.go | 1 + ...method_deleteauthorizationrule_autorest.go | 1 + .../namespaces/method_get_autorest.go | 1 + .../method_getauthorizationrule_autorest.go | 1 + .../namespaces/method_list_autorest.go | 88 +- .../namespaces/method_listall_autorest.go | 88 +- .../method_listauthorizationrules_autorest.go | 88 +- .../namespaces/method_listkeys_autorest.go | 1 + .../namespaces/method_patch_autorest.go | 1 + .../method_regeneratekeys_autorest.go | 1 + ...ecknotificationhubavailability_autorest.go | 1 + .../method_createorupdate_autorest.go | 1 + ...reateorupdateauthorizationrule_autorest.go | 1 + .../method_debugsend_autorest.go | 1 + .../method_delete_autorest.go | 1 + ...method_deleteauthorizationrule_autorest.go | 1 + .../notificationhubs/method_get_autorest.go | 1 + .../method_getauthorizationrule_autorest.go | 1 + .../method_getpnscredentials_autorest.go | 1 + .../notificationhubs/method_list_autorest.go | 88 +- .../method_listauthorizationrules_autorest.go | 88 +- .../method_listkeys_autorest.go | 1 + .../notificationhubs/method_patch_autorest.go | 1 + .../method_regeneratekeys_autorest.go | 1 + .../2019-09-01/querypackqueries/README.md | 133 + .../2019-09-01/querypackqueries/client.go | 18 + .../2019-09-01/querypackqueries/id_queries.go | 137 + .../querypackqueries/id_querypack.go | 124 + .../method_queriesdelete_autorest.go | 66 + .../method_queriesget_autorest.go | 68 + .../method_querieslist_autorest.go | 220 + .../method_queriesput_autorest.go | 69 + .../method_queriessearch_autorest.go | 221 + .../method_queriesupdate_autorest.go | 69 + .../model_loganalyticsquerypackquery.go | 16 + ...el_loganalyticsquerypackqueryproperties.go | 47 + ...nalyticsquerypackquerypropertiesrelated.go | 10 + ...analyticsquerypackquerysearchproperties.go | 9 + ...csquerypackquerysearchpropertiesrelated.go | 10 + .../2019-09-01/querypackqueries/predicates.go | 24 + .../2019-09-01/querypackqueries/version.go | 12 + .../2019-09-01/querypacks/README.md | 128 + .../2019-09-01/querypacks/client.go | 18 + .../2019-09-01/querypacks/id_querypack.go | 124 + ...ethod_querypackscreateorupdate_autorest.go | 69 + .../method_querypacksdelete_autorest.go | 66 + .../method_querypacksget_autorest.go | 68 + .../method_querypackslist_autorest.go | 187 + ..._querypackslistbyresourcegroup_autorest.go | 187 + .../method_querypacksupdatetags_autorest.go | 69 + .../querypacks/model_loganalyticsquerypack.go | 13 + .../model_loganalyticsquerypackproperties.go | 41 + .../querypacks/model_tagsresource.go | 8 + .../2019-09-01/querypacks/predicates.go | 29 + .../2019-09-01/querypacks/version.go | 12 + .../2020-08-01/clusters/README.md | 120 + .../2020-08-01/clusters/client.go | 18 + .../2020-08-01/clusters/constants.go | 74 + .../2020-08-01/clusters/id_cluster.go | 124 + .../method_createorupdate_autorest.go | 79 + .../clusters/method_delete_autorest.go | 78 + .../clusters/method_get_autorest.go | 68 + .../clusters/method_list_autorest.go | 187 + .../method_listbyresourcegroup_autorest.go | 187 + .../clusters/method_update_autorest.go | 69 + .../2020-08-01/clusters/model_cluster.go | 19 + .../2020-08-01/clusters/model_clusterpatch.go | 10 + .../clusters/model_clusterpatchproperties.go | 8 + .../clusters/model_clusterproperties.go | 11 + .../2020-08-01/clusters/model_clustersku.go | 9 + .../clusters/model_keyvaultproperties.go | 10 + .../2020-08-01/clusters/predicates.go | 29 + .../2020-08-01/clusters/version.go | 12 + .../2020-08-01/dataexport/README.md | 89 + .../2020-08-01/dataexport/client.go | 18 + .../2020-08-01/dataexport/constants.go | 34 + .../2020-08-01/dataexport/id_dataexport.go | 137 + .../2020-08-01/dataexport/id_workspace.go | 124 + .../method_createorupdate_autorest.go | 69 + .../dataexport/method_delete_autorest.go | 66 + .../dataexport/method_get_autorest.go | 68 + .../method_listbyworkspace_autorest.go | 69 + .../2020-08-01/dataexport/model_dataexport.go | 11 + .../dataexport/model_dataexportlistresult.go | 8 + .../dataexport/model_dataexportproperties.go | 13 + .../dataexport/model_destination.go | 10 + .../dataexport/model_destinationmetadata.go | 8 + .../2020-08-01/dataexport/version.go | 12 + .../2020-08-01/datasources/README.md | 90 + .../2020-08-01/datasources/client.go | 18 + .../2020-08-01/datasources/constants.go | 127 + .../2020-08-01/datasources/id_datasource.go | 137 + .../2020-08-01/datasources/id_workspace.go | 124 + .../method_createorupdate_autorest.go | 69 + .../datasources/method_delete_autorest.go | 66 + .../datasources/method_get_autorest.go | 68 + .../method_listbyworkspace_autorest.go | 215 + .../datasources/model_datasource.go | 14 + .../2020-08-01/datasources/predicates.go | 34 + .../2020-08-01/datasources/version.go | 12 + .../2020-08-01/linkedservices/README.md | 81 + .../2020-08-01/linkedservices/client.go | 18 + .../2020-08-01/linkedservices/constants.go | 40 + .../linkedservices/id_linkedservice.go | 137 + .../2020-08-01/linkedservices/id_workspace.go | 124 + .../method_createorupdate_autorest.go | 79 + .../linkedservices/method_delete_autorest.go | 78 + .../linkedservices/method_get_autorest.go | 68 + .../method_listbyworkspace_autorest.go | 69 + .../linkedservices/model_linkedservice.go | 12 + .../model_linkedservicelistresult.go | 8 + .../model_linkedserviceproperties.go | 10 + .../2020-08-01/linkedservices/version.go | 12 + .../linkedstorageaccounts/README.md | 89 + .../linkedstorageaccounts/client.go | 18 + .../linkedstorageaccounts/constants.go | 43 + .../id_datasourcetype.go | 153 + .../linkedstorageaccounts/id_workspace.go | 124 + .../method_createorupdate_autorest.go | 69 + .../method_delete_autorest.go | 66 + .../method_get_autorest.go | 68 + .../method_listbyworkspace_autorest.go | 69 + .../model_linkedstorageaccountslistresult.go | 8 + .../model_linkedstorageaccountsproperties.go | 9 + .../model_linkedstorageaccountsresource.go | 11 + .../linkedstorageaccounts/version.go | 12 + .../2020-08-01/savedsearches/README.md | 89 + .../2020-08-01/savedsearches/client.go | 18 + .../savedsearches/id_savedsearche.go | 137 + .../2020-08-01/savedsearches/id_workspace.go | 124 + .../method_createorupdate_autorest.go | 69 + .../savedsearches/method_delete_autorest.go | 66 + .../savedsearches/method_get_autorest.go | 68 + .../method_listbyworkspace_autorest.go | 69 + .../savedsearches/model_savedsearch.go | 12 + .../model_savedsearcheslistresult.go | 8 + .../model_savedsearchproperties.go | 14 + .../2020-08-01/savedsearches/model_tag.go | 9 + .../2020-08-01/savedsearches/version.go | 12 + .../2020-08-01/storageinsights/README.md | 90 + .../2020-08-01/storageinsights/client.go | 18 + .../2020-08-01/storageinsights/constants.go | 34 + .../id_storageinsightconfig.go | 137 + .../storageinsights/id_workspace.go | 124 + ...geinsightconfigscreateorupdate_autorest.go | 69 + ...od_storageinsightconfigsdelete_autorest.go | 66 + ...ethod_storageinsightconfigsget_autorest.go | 68 + ...einsightconfigslistbyworkspace_autorest.go | 186 + .../storageinsights/model_storageaccount.go | 9 + .../storageinsights/model_storageinsight.go | 13 + .../model_storageinsightproperties.go | 11 + .../model_storageinsightstatus.go | 9 + .../2020-08-01/storageinsights/predicates.go | 29 + .../2020-08-01/storageinsights/version.go | 12 + .../2020-08-01/workspaces/README.md | 299 + .../2020-08-01/workspaces/client.go | 18 + .../2020-08-01/workspaces/constants.go | 219 + .../2020-08-01/workspaces/id_gateway.go | 137 + .../workspaces/id_intelligencepack.go | 137 + .../2020-08-01/workspaces/id_operation.go | 137 + .../2020-08-01/workspaces/id_workspace.go | 124 + .../method_createorupdate_autorest.go | 79 + .../workspaces/method_delete_autorest.go | 107 + .../method_gatewaysdelete_autorest.go | 66 + .../workspaces/method_get_autorest.go | 68 + ...ethod_intelligencepacksdisable_autorest.go | 67 + ...method_intelligencepacksenable_autorest.go | 67 + .../method_intelligencepackslist_autorest.go | 69 + .../workspaces/method_list_autorest.go | 70 + .../method_listbyresourcegroup_autorest.go | 70 + .../method_managementgroupslist_autorest.go | 69 + .../workspaces/method_schemaget_autorest.go | 69 + ...method_sharedkeysgetsharedkeys_autorest.go | 69 + .../method_sharedkeysregenerate_autorest.go | 69 + .../workspaces/method_update_autorest.go | 69 + .../workspaces/method_usageslist_autorest.go | 69 + ...d_workspacepurgegetpurgestatus_autorest.go | 68 + .../method_workspacepurgepurge_autorest.go | 70 + .../workspaces/model_coresummary.go | 9 + .../workspaces/model_intelligencepack.go | 10 + .../workspaces/model_managementgroup.go | 8 + .../model_managementgroupproperties.go | 45 + .../2020-08-01/workspaces/model_metricname.go | 9 + .../model_privatelinkscopedresource.go | 9 + .../model_searchgetschemaresponse.go | 9 + .../workspaces/model_searchmetadata.go | 54 + .../workspaces/model_searchmetadataschema.go | 9 + .../workspaces/model_searchschemavalue.go | 14 + .../2020-08-01/workspaces/model_searchsort.go | 9 + .../2020-08-01/workspaces/model_sharedkeys.go | 9 + .../workspaces/model_usagemetric.go | 31 + .../2020-08-01/workspaces/model_workspace.go | 14 + .../workspaces/model_workspacecapping.go | 10 + ...del_workspacelistmanagementgroupsresult.go | 8 + .../workspaces/model_workspacelistresult.go | 8 + .../model_workspacelistusagesresult.go | 8 + .../workspaces/model_workspacepatch.go | 13 + .../workspaces/model_workspaceproperties.go | 19 + .../workspaces/model_workspacepurgebody.go | 9 + .../model_workspacepurgebodyfilters.go | 11 + .../model_workspacepurgeresponse.go | 8 + .../model_workspacepurgestatusresponse.go | 8 + .../workspaces/model_workspacesku.go | 11 + .../2020-08-01/workspaces/version.go | 12 + .../2015-11-01-preview/solution/README.md | 114 + .../2015-11-01-preview/solution/client.go | 18 + .../solution/id_solution.go | 124 + .../method_createorupdate_autorest.go | 79 + .../solution/method_delete_autorest.go | 78 + .../solution/method_get_autorest.go | 68 + .../method_listbyresourcegroup_autorest.go | 70 + .../method_listbysubscription_autorest.go | 70 + .../solution/method_update_autorest.go | 79 + .../solution/model_solution.go | 14 + .../solution/model_solutionpatch.go | 8 + .../solution/model_solutionplan.go | 11 + .../solution/model_solutionproperties.go | 11 + .../solution/model_solutionpropertieslist.go | 8 + .../2015-11-01-preview/solution/version.go | 12 + .../2021-10-01/policyinsights/README.md | 432 - .../2021-10-01/policyinsights/client.go | 18 - .../2021-10-01/policyinsights/constants.go | 34 - ...iationscancelatmanagementgroup_autorest.go | 68 - ...d_remediationscancelatresource_autorest.go | 68 - ...ediationscancelatresourcegroup_autorest.go | 68 - ...mediationscancelatsubscription_autorest.go | 68 - ...reateorupdateatmanagementgroup_autorest.go | 68 - ...ationscreateorupdateatresource_autorest.go | 68 - ...screateorupdateatresourcegroup_autorest.go | 68 - ...nscreateorupdateatsubscription_autorest.go | 68 - ...iationsdeleteatmanagementgroup_autorest.go | 67 - ...d_remediationsdeleteatresource_autorest.go | 67 - ...ediationsdeleteatresourcegroup_autorest.go | 67 - ...mediationsdeleteatsubscription_autorest.go | 67 - ...mediationsgetatmanagementgroup_autorest.go | 67 - ...thod_remediationsgetatresource_autorest.go | 67 - ...remediationsgetatresourcegroup_autorest.go | 67 - ..._remediationsgetatsubscription_autorest.go | 67 - ...stdeploymentsatmanagementgroup_autorest.go | 215 - ...tionslistdeploymentsatresource_autorest.go | 215 - ...listdeploymentsatresourcegroup_autorest.go | 215 - ...slistdeploymentsatsubscription_autorest.go | 215 - ...diationslistformanagementgroup_autorest.go | 220 - ...od_remediationslistforresource_autorest.go | 221 - ...mediationslistforresourcegroup_autorest.go | 221 - ...emediationslistforsubscription_autorest.go | 221 - .../2021-10-01/policyinsights/predicates.go | 62 - .../2021-10-01/policyinsights/version.go | 12 - .../2021-10-01/remediations/README.md | 432 + .../2021-10-01/remediations/client.go | 18 + .../2021-10-01/remediations/constants.go | 34 + .../id_managementgroup.go | 2 +- .../id_providerremediation.go | 2 +- .../id_providers2remediation.go | 2 +- .../id_remediation.go | 2 +- .../id_scopedremediation.go | 2 +- ...iationscancelatmanagementgroup_autorest.go | 69 + ...d_remediationscancelatresource_autorest.go | 69 + ...ediationscancelatresourcegroup_autorest.go | 69 + ...mediationscancelatsubscription_autorest.go | 69 + ...reateorupdateatmanagementgroup_autorest.go | 69 + ...ationscreateorupdateatresource_autorest.go | 69 + ...screateorupdateatresourcegroup_autorest.go | 69 + ...nscreateorupdateatsubscription_autorest.go | 69 + ...iationsdeleteatmanagementgroup_autorest.go | 68 + ...d_remediationsdeleteatresource_autorest.go | 68 + ...ediationsdeleteatresourcegroup_autorest.go | 68 + ...mediationsdeleteatsubscription_autorest.go | 68 + ...mediationsgetatmanagementgroup_autorest.go | 68 + ...thod_remediationsgetatresource_autorest.go | 68 + ...remediationsgetatresourcegroup_autorest.go | 68 + ..._remediationsgetatsubscription_autorest.go | 68 + ...stdeploymentsatmanagementgroup_autorest.go | 215 + ...tionslistdeploymentsatresource_autorest.go | 215 + ...listdeploymentsatresourcegroup_autorest.go | 215 + ...slistdeploymentsatsubscription_autorest.go | 215 + ...diationslistformanagementgroup_autorest.go | 220 + ...od_remediationslistforresource_autorest.go | 221 + ...mediationslistforresourcegroup_autorest.go | 221 + ...emediationslistforsubscription_autorest.go | 221 + .../model_errordefinition.go | 2 +- .../model_remediation.go | 2 +- .../model_remediationdeployment.go | 2 +- .../model_remediationdeploymentsummary.go | 2 +- .../model_remediationfilters.go | 2 +- .../model_remediationproperties.go | 2 +- ...l_remediationpropertiesfailurethreshold.go | 2 +- .../model_typederrorinfo.go | 2 +- .../2021-10-01/remediations/predicates.go | 62 + .../2021-10-01/remediations/version.go | 12 + .../2019-01-01-preview/dashboard/README.md | 4 +- .../method_createorupdate_autorest.go | 1 + .../dashboard/method_delete_autorest.go | 1 + .../dashboard/method_get_autorest.go | 1 + .../method_listbyresourcegroup_autorest.go | 88 +- .../method_listbysubscription_autorest.go | 88 +- .../dashboard/method_update_autorest.go | 1 + ...hod_tenantconfigurationscreate_autorest.go | 1 + ...hod_tenantconfigurationsdelete_autorest.go | 1 + ...method_tenantconfigurationsget_autorest.go | 1 + ...ethod_tenantconfigurationslist_autorest.go | 1 + .../2017-12-01/configurations/README.md | 69 + .../2017-12-01/configurations/client.go | 18 + .../configurations/id_configuration.go | 137 + .../2017-12-01/configurations/id_server.go | 124 + .../method_createorupdate_autorest.go | 79 + .../configurations/method_get_autorest.go | 68 + .../method_listbyserver_autorest.go | 69 + .../configurations/model_configuration.go | 11 + .../model_configurationlistresult.go | 8 + .../model_configurationproperties.go | 13 + .../2017-12-01/configurations/version.go | 12 + .../postgresql/2017-12-01/databases/README.md | 81 + .../postgresql/2017-12-01/databases/client.go | 18 + .../2017-12-01/databases/id_database.go | 137 + .../2017-12-01/databases/id_server.go | 124 + .../method_createorupdate_autorest.go | 79 + .../databases/method_delete_autorest.go | 78 + .../databases/method_get_autorest.go | 68 + .../databases/method_listbyserver_autorest.go | 69 + .../2017-12-01/databases/model_database.go | 11 + .../databases/model_databaselistresult.go | 8 + .../databases/model_databaseproperties.go | 9 + .../2017-12-01/databases/version.go | 12 + .../2017-12-01/firewallrules/README.md | 81 + .../2017-12-01/firewallrules/client.go | 18 + .../firewallrules/id_firewallrule.go | 137 + .../2017-12-01/firewallrules/id_server.go | 124 + .../method_createorupdate_autorest.go | 79 + .../firewallrules/method_delete_autorest.go | 78 + .../firewallrules/method_get_autorest.go | 68 + .../method_listbyserver_autorest.go | 69 + .../firewallrules/model_firewallrule.go | 11 + .../model_firewallrulelistresult.go | 8 + .../model_firewallruleproperties.go | 9 + .../2017-12-01/firewallrules/version.go | 12 + .../postgresql/2017-12-01/replicas/README.md | 36 + .../postgresql/2017-12-01/replicas/client.go | 18 + .../2017-12-01/replicas/constants.go | 381 + .../2017-12-01/replicas/id_server.go | 124 + .../replicas/method_listbyserver_autorest.go | 69 + .../replicas/model_privateendpointproperty.go | 8 + .../2017-12-01/replicas/model_server.go | 19 + .../replicas/model_serverlistresult.go | 8 + .../model_serverprivateendpointconnection.go | 9 + ...rverprivateendpointconnectionproperties.go | 10 + ...ivatelinkserviceconnectionstateproperty.go | 10 + .../replicas/model_serverproperties.go | 40 + .../2017-12-01/replicas/model_sku.go | 12 + .../replicas/model_storageprofile.go | 11 + .../postgresql/2017-12-01/replicas/version.go | 12 + .../2017-12-01/serveradministrators/README.md | 81 + .../2017-12-01/serveradministrators/client.go | 18 + .../serveradministrators/constants.go | 31 + .../serveradministrators/id_server.go | 124 + .../method_createorupdate_autorest.go | 79 + .../method_delete_autorest.go | 78 + .../method_get_autorest.go | 69 + .../method_list_autorest.go | 69 + .../model_serveradministratorproperties.go | 11 + .../model_serveradministratorresource.go | 11 + ...l_serveradministratorresourcelistresult.go | 8 + .../serveradministrators/version.go | 12 + .../postgresql/2017-12-01/servers/README.md | 114 + .../postgresql/2017-12-01/servers/client.go | 18 + .../2017-12-01/servers/constants.go | 415 + .../2017-12-01/servers/id_server.go | 124 + .../servers/method_create_autorest.go | 79 + .../servers/method_delete_autorest.go | 78 + .../2017-12-01/servers/method_get_autorest.go | 68 + .../servers/method_list_autorest.go | 70 + .../method_listbyresourcegroup_autorest.go | 70 + .../servers/method_update_autorest.go | 79 + .../servers/model_privateendpointproperty.go | 8 + .../2017-12-01/servers/model_server.go | 19 + .../servers/model_serverforcreate.go | 48 + .../servers/model_serverlistresult.go | 8 + .../model_serverprivateendpointconnection.go | 9 + ...rverprivateendpointconnectionproperties.go | 10 + ...ivatelinkserviceconnectionstateproperty.go | 10 + .../servers/model_serverproperties.go | 40 + .../model_serverpropertiesforcreate.go | 72 + .../model_serverpropertiesfordefaultcreate.go | 48 + .../model_serverpropertiesforgeorestore.go | 47 + .../model_serverpropertiesforreplica.go | 47 + .../model_serverpropertiesforrestore.go | 48 + .../servers/model_serverupdateparameters.go | 15 + .../model_serverupdateparametersproperties.go | 14 + .../2017-12-01/servers/model_sku.go | 12 + .../servers/model_storageprofile.go | 11 + .../postgresql/2017-12-01/servers/version.go | 12 + .../serversecurityalertpolicies/README.md | 70 + .../serversecurityalertpolicies/client.go | 18 + .../serversecurityalertpolicies/constants.go | 34 + .../serversecurityalertpolicies/id_server.go | 124 + .../method_createorupdate_autorest.go | 79 + .../method_get_autorest.go | 69 + .../method_listbyserver_autorest.go | 186 + .../model_securityalertpolicyproperties.go | 14 + .../model_serversecurityalertpolicy.go | 11 + .../serversecurityalertpolicies/predicates.go | 24 + .../serversecurityalertpolicies/version.go | 12 + .../2017-12-01/virtualnetworkrules/README.md | 82 + .../2017-12-01/virtualnetworkrules/client.go | 18 + .../virtualnetworkrules/constants.go | 43 + .../virtualnetworkrules/id_server.go | 124 + .../id_virtualnetworkrule.go | 137 + .../method_createorupdate_autorest.go | 79 + .../method_delete_autorest.go | 78 + .../method_get_autorest.go | 68 + .../method_listbyserver_autorest.go | 186 + .../model_virtualnetworkrule.go | 11 + .../model_virtualnetworkruleproperties.go | 10 + .../virtualnetworkrules/predicates.go | 24 + .../2017-12-01/virtualnetworkrules/version.go | 12 + .../2020-01-01/serverkeys/README.md | 82 + .../2020-01-01/serverkeys/client.go | 18 + .../2020-01-01/serverkeys/constants.go | 31 + .../2020-01-01/serverkeys/id_key.go | 137 + .../2020-01-01/serverkeys/id_server.go | 124 + .../method_createorupdate_autorest.go | 79 + .../serverkeys/method_delete_autorest.go | 78 + .../serverkeys/method_get_autorest.go | 68 + .../serverkeys/method_list_autorest.go | 186 + .../2020-01-01/serverkeys/model_serverkey.go | 12 + .../serverkeys/model_serverkeyproperties.go | 28 + .../2020-01-01/serverkeys/predicates.go | 29 + .../2020-01-01/serverkeys/version.go | 12 + .../2021-06-01/configurations/README.md | 87 + .../2021-06-01/configurations/client.go | 18 + .../2021-06-01/configurations/constants.go | 40 + .../configurations/id_configuration.go | 137 + .../configurations/id_flexibleserver.go | 124 + .../configurations/method_get_autorest.go | 68 + .../method_listbyserver_autorest.go | 186 + .../configurations/method_put_autorest.go | 79 + .../configurations/method_update_autorest.go | 79 + .../configurations/model_configuration.go | 16 + .../model_configurationproperties.go | 18 + .../2021-06-01/configurations/predicates.go | 24 + .../2021-06-01/configurations/version.go | 12 + .../postgresql/2021-06-01/databases/README.md | 82 + .../postgresql/2021-06-01/databases/client.go | 18 + .../2021-06-01/databases/id_database.go | 137 + .../2021-06-01/databases/id_flexibleserver.go | 124 + .../databases/method_create_autorest.go | 79 + .../databases/method_delete_autorest.go | 78 + .../databases/method_get_autorest.go | 68 + .../databases/method_listbyserver_autorest.go | 186 + .../2021-06-01/databases/model_database.go | 16 + .../databases/model_databaseproperties.go | 9 + .../2021-06-01/databases/predicates.go | 24 + .../2021-06-01/databases/version.go | 12 + .../2021-06-01/firewallrules/README.md | 82 + .../2021-06-01/firewallrules/client.go | 18 + .../firewallrules/id_firewallrule.go | 137 + .../firewallrules/id_flexibleserver.go | 124 + .../method_createorupdate_autorest.go | 79 + .../firewallrules/method_delete_autorest.go | 78 + .../firewallrules/method_get_autorest.go | 68 + .../method_listbyserver_autorest.go | 186 + .../firewallrules/model_firewallrule.go | 16 + .../model_firewallruleproperties.go | 9 + .../2021-06-01/firewallrules/predicates.go | 24 + .../2021-06-01/firewallrules/version.go | 12 + .../2021-06-01/serverrestart/README.md | 37 + .../2021-06-01/serverrestart/client.go | 18 + .../2021-06-01/serverrestart/constants.go | 40 + .../serverrestart/id_flexibleserver.go | 124 + .../method_serversrestart_autorest.go | 79 + .../serverrestart/model_restartparameter.go | 9 + .../2021-06-01/serverrestart/version.go | 12 + .../postgresql/2021-06-01/servers/README.md | 116 + .../postgresql/2021-06-01/servers/client.go | 18 + .../2021-06-01/servers/constants.go | 300 + .../2021-06-01/servers/id_flexibleserver.go | 124 + .../servers/method_create_autorest.go | 79 + .../servers/method_delete_autorest.go | 78 + .../2021-06-01/servers/method_get_autorest.go | 68 + .../servers/method_list_autorest.go | 187 + .../method_listbyresourcegroup_autorest.go | 187 + .../servers/method_update_autorest.go | 79 + .../2021-06-01/servers/model_backup.go | 28 + .../servers/model_highavailability.go | 10 + .../servers/model_maintenancewindow.go | 11 + .../2021-06-01/servers/model_network.go | 10 + .../2021-06-01/servers/model_server.go | 19 + .../servers/model_serverforupdate.go | 11 + .../servers/model_serverproperties.go | 40 + .../model_serverpropertiesforupdate.go | 13 + .../2021-06-01/servers/model_sku.go | 9 + .../2021-06-01/servers/model_storage.go | 8 + .../2021-06-01/servers/predicates.go | 29 + .../postgresql/2021-06-01/servers/version.go | 12 + .../2021-01-01/capacities/README.md | 4 +- .../method_checknameavailability_autorest.go | 1 + .../capacities/method_getdetails_autorest.go | 1 + .../capacities/method_list_autorest.go | 1 + .../method_listbyresourcegroup_autorest.go | 1 + .../method_listskusforcapacity_autorest.go | 1 + .../2018-09-01/privatezones/README.md | 4 +- .../privatezones/method_get_autorest.go | 1 + .../privatezones/method_list_autorest.go | 88 +- .../method_listbyresourcegroup_autorest.go | 88 +- .../method_createorupdate_autorest.go | 1 + .../recordsets/method_delete_autorest.go | 1 + .../recordsets/method_get_autorest.go | 1 + .../recordsets/method_list_autorest.go | 88 +- .../recordsets/method_listbytype_autorest.go | 88 +- .../recordsets/method_update_autorest.go | 1 + .../2018-09-01/recordsets/model_aaaarecord.go | 2 +- .../2018-09-01/recordsets/model_arecord.go | 2 +- .../method_get_autorest.go | 1 + .../method_list_autorest.go | 88 +- .../purview/2021-07-01/account/README.md | 4 +- .../method_addrootcollectionadmin_autorest.go | 1 + .../2021-07-01/account/method_get_autorest.go | 1 + .../method_listbyresourcegroup_autorest.go | 88 +- .../method_listbysubscription_autorest.go | 88 +- .../account/method_listkeys_autorest.go | 1 + .../databases/method_get_autorest.go | 1 + .../method_listbycluster_autorest.go | 88 +- .../databases/method_listkeys_autorest.go | 1 + .../2022-01-01/redisenterprise/README.md | 4 +- .../method_databasesget_autorest.go | 1 + .../method_databaseslistbycluster_autorest.go | 88 +- .../method_databaseslistkeys_autorest.go | 1 + .../redisenterprise/method_get_autorest.go | 1 + .../redisenterprise/method_list_autorest.go | 88 +- .../method_listbyresourcegroup_autorest.go | 88 +- .../method_createorupdate_autorest.go | 1 + ...reateorupdateauthorizationrule_autorest.go | 1 + .../method_delete_autorest.go | 1 + ...method_deleteauthorizationrule_autorest.go | 1 + .../hybridconnections/method_get_autorest.go | 1 + .../method_getauthorizationrule_autorest.go | 1 + .../method_listauthorizationrules_autorest.go | 88 +- .../method_listbynamespace_autorest.go | 88 +- .../method_listkeys_autorest.go | 1 + .../method_regeneratekeys_autorest.go | 1 + .../relay/2017-04-01/namespaces/README.md | 6 +- .../method_checknameavailability_autorest.go | 1 + ...reateorupdateauthorizationrule_autorest.go | 1 + ...method_deleteauthorizationrule_autorest.go | 1 + .../namespaces/method_get_autorest.go | 1 + .../method_getauthorizationrule_autorest.go | 1 + .../namespaces/method_list_autorest.go | 88 +- .../method_listauthorizationrules_autorest.go | 88 +- .../method_listbyresourcegroup_autorest.go | 88 +- .../namespaces/method_listkeys_autorest.go | 1 + .../method_regeneratekeys_autorest.go | 1 + .../namespaces/method_update_autorest.go | 1 + .../adminkeys/method_get_autorest.go | 1 + .../adminkeys/method_regenerate_autorest.go | 1 + .../querykeys/method_create_autorest.go | 1 + .../querykeys/method_delete_autorest.go | 1 + .../method_listbysearchservice_autorest.go | 88 +- .../search/2020-03-13/services/README.md | 6 +- .../method_checknameavailability_autorest.go | 1 + .../services/method_delete_autorest.go | 1 + .../services/method_get_autorest.go | 1 + .../method_listbyresourcegroup_autorest.go | 88 +- .../method_listbysubscription_autorest.go | 88 +- .../services/method_update_autorest.go | 1 + .../2020-03-13/services/model_iprule.go | 2 +- .../services/model_networkruleset.go | 2 +- .../sharedprivatelinkresources/README.md | 82 + .../sharedprivatelinkresources/client.go | 18 + .../sharedprivatelinkresources/constants.go | 77 + .../id_searchservice.go | 124 + .../id_sharedprivatelinkresource.go | 137 + .../method_createorupdate_autorest.go | 108 + .../method_delete_autorest.go | 107 + .../method_get_autorest.go | 97 + .../method_listbyservice_autorest.go | 215 + .../model_sharedprivatelinkresource.go | 11 + ...del_sharedprivatelinkresourceproperties.go | 13 + .../sharedprivatelinkresources/predicates.go | 24 + .../sharedprivatelinkresources/version.go | 12 + .../method_breakpairing_autorest.go | 1 + .../method_checknameavailability_autorest.go | 1 + .../method_createorupdate_autorest.go | 1 + .../method_delete_autorest.go | 1 + .../method_failover_autorest.go | 1 + .../method_get_autorest.go | 1 + .../method_getauthorizationrule_autorest.go | 1 + .../method_list_autorest.go | 88 +- .../method_listauthorizationrules_autorest.go | 88 +- .../method_listkeys_autorest.go | 1 + .../2021-06-01-preview/namespaces/README.md | 195 - .../namespaces/constants.go | 288 - .../method_checknameavailability_autorest.go | 70 - .../namespaces/method_get_autorest.go | 67 - .../namespaces/method_list_autorest.go | 187 - .../method_listbyresourcegroup_autorest.go | 187 - .../namespaces/method_update_autorest.go | 68 - .../namespaces/model_networkruleset.go | 16 - .../model_networkrulesetproperties.go | 12 - .../namespaces/model_nwrulesetiprules.go | 9 - .../model_privateendpointconnection.go | 16 - .../namespaces/predicates.go | 52 - .../2021-06-01-preview/namespaces/version.go | 12 - ...reateorupdateauthorizationrule_autorest.go | 1 + ...espacesdeleteauthorizationrule_autorest.go | 1 + ...namespacesgetauthorizationrule_autorest.go | 1 + ...mespaceslistauthorizationrules_autorest.go | 88 +- .../method_namespaceslistkeys_autorest.go | 1 + ...ethod_namespacesregeneratekeys_autorest.go | 1 + .../queues/method_createorupdate_autorest.go | 1 + .../queues/method_delete_autorest.go | 1 + .../queues/method_get_autorest.go | 1 + .../queues/method_listbynamespace_autorest.go | 88 +- ...reateorupdateauthorizationrule_autorest.go | 1 + ..._queuesdeleteauthorizationrule_autorest.go | 1 + ...hod_queuesgetauthorizationrule_autorest.go | 1 + ...d_queueslistauthorizationrules_autorest.go | 88 +- .../method_queueslistkeys_autorest.go | 1 + .../method_queuesregeneratekeys_autorest.go | 1 + .../rules/method_createorupdate_autorest.go | 1 + .../rules/method_delete_autorest.go | 1 + .../method_listbysubscriptions_autorest.go | 88 +- .../method_createorupdate_autorest.go | 1 + .../subscriptions/method_delete_autorest.go | 1 + .../subscriptions/method_get_autorest.go | 1 + .../method_listbytopic_autorest.go | 88 +- .../subscriptions/method_rulesget_autorest.go | 1 + .../topics/method_createorupdate_autorest.go | 1 + .../topics/method_delete_autorest.go | 1 + .../topics/method_get_autorest.go | 1 + .../topics/method_listbynamespace_autorest.go | 88 +- ...reateorupdateauthorizationrule_autorest.go | 1 + ..._topicsdeleteauthorizationrule_autorest.go | 1 + ...hod_topicsgetauthorizationrule_autorest.go | 1 + ...d_topicslistauthorizationrules_autorest.go | 88 +- .../method_topicslistkeys_autorest.go | 1 + .../method_topicsregeneratekeys_autorest.go | 1 + .../2022-01-01-preview/namespaces/README.md | 195 + .../2022-01-01-preview/namespaces/client.go | 18 + .../namespaces/constants.go | 350 + .../namespaces/id_namespace.go | 0 .../method_checknameavailability_autorest.go | 71 + .../method_createorupdate_autorest.go | 0 ...d_createorupdatenetworkruleset_autorest.go | 1 + .../namespaces/method_delete_autorest.go | 78 + .../namespaces/method_get_autorest.go | 68 + .../method_getnetworkruleset_autorest.go | 1 + .../namespaces/method_list_autorest.go | 187 + .../method_listbyresourcegroup_autorest.go | 187 + .../method_listnetworkrulesets_autorest.go | 88 +- .../namespaces/method_update_autorest.go | 69 + .../namespaces/model_checknameavailability.go | 0 .../model_checknameavailabilityresult.go | 0 .../namespaces/model_connectionstate.go | 9 + .../namespaces/model_encryption.go | 10 + .../namespaces/model_keyvaultproperties.go | 11 + .../namespaces/model_networkruleset.go | 17 + .../model_networkrulesetproperties.go | 12 + .../namespaces/model_nwrulesetiprules.go | 9 + .../model_nwrulesetvirtualnetworkrules.go | 0 .../namespaces/model_privateendpoint.go | 8 + .../model_privateendpointconnection.go | 17 + ...del_privateendpointconnectionproperties.go | 10 + .../namespaces/model_sbnamespace.go | 0 .../namespaces/model_sbnamespaceproperties.go | 3 + .../model_sbnamespaceupdateparameters.go | 2 +- .../model_sbnamespaceupdateproperties.go | 47 + .../namespaces/model_sbsku.go | 0 .../namespaces/model_subnet.go | 0 .../model_userassignedidentityproperties.go | 8 + .../namespaces/predicates.go | 57 + .../2022-01-01-preview/namespaces/version.go | 12 + .../2021-05-01/managedcluster/README.md | 4 +- .../2021-05-01/managedcluster/constants.go | 24 +- .../managedcluster/method_get_autorest.go | 1 + .../method_listbyresourcegroup_autorest.go | 88 +- .../method_listbysubscription_autorest.go | 88 +- .../managedcluster/method_update_autorest.go | 1 + .../model_managedclusterproperties.go | 4 +- .../nodetype/method_get_autorest.go | 1 + .../method_listbymanagedclusters_autorest.go | 88 +- .../nodetype/method_update_autorest.go | 1 + .../servicelinker/2022-05-01/links/README.md | 77 + .../servicelinker/2022-05-01/links/client.go | 18 + .../2022-05-01/links/constants.go | 244 + .../2022-05-01/links/id_scopedlinker.go | 110 + .../links/method_linkerdelete_autorest.go | 78 + ...ethod_linkerlistconfigurations_autorest.go | 69 + .../links/method_linkerupdate_autorest.go | 79 + .../links/method_linkervalidate_autorest.go | 78 + .../2022-05-01/links/model_authinfobase.go | 80 + .../links/model_azurekeyvaultproperties.go | 41 + .../2022-05-01/links/model_azureresource.go | 68 + .../model_azureresourcepropertiesbase.go | 48 + .../links/model_confluentbootstrapserver.go | 41 + .../links/model_confluentschemaregistry.go | 41 + ...model_keyvaultsecretreferencesecretinfo.go | 42 + .../model_keyvaultsecreturisecretinfo.go | 41 + .../2022-05-01/links/model_linkerpatch.go | 8 + .../links/model_linkerproperties.go | 57 + .../2022-05-01/links/model_linkerresource.go | 16 + .../2022-05-01/links/model_secretauthinfo.go | 68 + .../2022-05-01/links/model_secretinfobase.go | 64 + .../2022-05-01/links/model_secretstore.go | 8 + ...del_serviceprincipalcertificateauthinfo.go | 43 + .../model_serviceprincipalsecretauthinfo.go | 43 + .../links/model_sourceconfiguration.go | 9 + .../links/model_sourceconfigurationresult.go | 8 + .../model_systemassignedidentityauthinfo.go | 40 + .../links/model_targetservicebase.go | 64 + .../model_userassignedidentityauthinfo.go | 42 + .../links/model_validateoperationresult.go | 10 + .../2022-05-01/links/model_validateresult.go | 45 + .../links/model_validationresultitem.go | 12 + .../2022-05-01/links/model_valuesecretinfo.go | 41 + .../2022-05-01/links/model_vnetsolution.go | 8 + .../servicelinker/2022-05-01/links/version.go | 12 + .../2022-05-01/servicelinker/README.md | 70 + .../2022-05-01/servicelinker/client.go | 18 + .../2022-05-01/servicelinker/constants.go | 213 + .../servicelinker/id_scopedlinker.go | 110 + .../method_linkercreateorupdate_autorest.go | 79 + .../method_linkerget_autorest.go | 68 + .../method_linkerlist_autorest.go | 187 + .../servicelinker/model_authinfobase.go | 80 + .../model_azurekeyvaultproperties.go | 41 + .../servicelinker/model_azureresource.go | 68 + .../model_azureresourcepropertiesbase.go | 48 + .../model_confluentbootstrapserver.go | 41 + .../model_confluentschemaregistry.go | 41 + ...model_keyvaultsecretreferencesecretinfo.go | 42 + .../model_keyvaultsecreturisecretinfo.go | 41 + .../servicelinker/model_linkerproperties.go | 57 + .../servicelinker/model_linkerresource.go | 16 + .../servicelinker/model_secretauthinfo.go | 68 + .../servicelinker/model_secretinfobase.go | 64 + .../servicelinker/model_secretstore.go | 8 + ...del_serviceprincipalcertificateauthinfo.go | 43 + .../model_serviceprincipalsecretauthinfo.go | 43 + .../model_systemassignedidentityauthinfo.go | 40 + .../servicelinker/model_targetservicebase.go | 64 + .../model_userassignedidentityauthinfo.go | 42 + .../servicelinker/model_valuesecretinfo.go | 41 + .../servicelinker/model_vnetsolution.go | 8 + .../2022-05-01/servicelinker/predicates.go | 24 + .../2022-05-01/servicelinker/version.go | 12 + .../signalr/2022-02-01/signalr/README.md | 4 +- .../method_checknameavailability_autorest.go | 1 + ...ethod_customcertificatesdelete_autorest.go | 1 + .../method_customcertificatesget_autorest.go | 1 + .../method_customcertificateslist_autorest.go | 88 +- .../method_customdomainsget_autorest.go | 1 + .../method_customdomainslist_autorest.go | 88 +- .../2022-02-01/signalr/method_get_autorest.go | 1 + .../method_listbyresourcegroup_autorest.go | 88 +- .../method_listbysubscription_autorest.go | 88 +- .../signalr/method_listkeys_autorest.go | 1 + .../signalr/method_listskus_autorest.go | 1 + ..._privateendpointconnectionsget_autorest.go | 1 + ...privateendpointconnectionslist_autorest.go | 88 +- ...ivateendpointconnectionsupdate_autorest.go | 1 + ...ethod_privatelinkresourceslist_autorest.go | 88 +- ..._sharedprivatelinkresourcesget_autorest.go | 1 + ...sharedprivatelinkresourceslist_autorest.go | 88 +- .../signalr/method_usageslist_autorest.go | 88 +- .../2022-02-01/sqlvirtualmachines/README.md | 4 +- .../sqlvirtualmachines/method_get_autorest.go | 1 + .../method_list_autorest.go | 88 +- .../method_listbyresourcegroup_autorest.go | 88 +- .../method_listbysqlvmgroup_autorest.go | 88 +- .../model_sqlvirtualmachineproperties.go | 2 +- .../method_createorupdate_autorest.go | 1 + .../method_delete_autorest.go | 1 + .../method_get_autorest.go | 1 + .../method_list_autorest.go | 1 + .../method_createorupdate_autorest.go | 1 + .../endpoints/method_delete_autorest.go | 1 + .../endpoints/method_get_autorest.go | 1 + .../endpoints/method_update_autorest.go | 1 + .../method_getdefault_autorest.go | 1 + .../2018-08-01/profiles/README.md | 4 +- ...gerrelativednsnameavailability_autorest.go | 1 + .../method_createorupdate_autorest.go | 1 + .../profiles/method_delete_autorest.go | 1 + .../profiles/method_get_autorest.go | 1 + .../method_listbyresourcegroup_autorest.go | 1 + .../method_listbysubscription_autorest.go | 1 + .../profiles/method_update_autorest.go | 1 + .../2021-05-01-preview/edgemodules/README.md | 111 + .../2021-05-01-preview/edgemodules/client.go | 18 + .../id_edgemodule.go | 2 +- .../edgemodules/id_videoanalyzer.go | 124 + ...thod_edgemodulescreateorupdate_autorest.go | 69 + .../method_edgemodulesdelete_autorest.go | 66 + .../method_edgemodulesget_autorest.go | 68 + .../method_edgemoduleslist_autorest.go | 225 + ...gemoduleslistprovisioningtoken_autorest.go | 70 + .../model_edgemoduleentity.go | 2 +- .../model_edgemoduleproperties.go | 2 +- .../model_edgemoduleprovisioningtoken.go | 2 +- .../model_listprovisioningtokeninput.go | 2 +- .../edgemodules/predicates.go | 24 + .../2021-05-01-preview/edgemodules/version.go | 12 + .../videoanalyzer/README.md | 457 - .../videoanalyzer/client.go | 18 - .../videoanalyzer/constants.go | 199 - .../videoanalyzer/id_accesspolicies.go | 137 - .../videoanalyzer/id_location.go | 111 - .../videoanalyzer/id_video.go | 137 - .../videoanalyzer/id_videoanalyzer.go | 124 - ...d_accesspoliciescreateorupdate_autorest.go | 68 - .../method_accesspoliciesdelete_autorest.go | 65 - .../method_accesspoliciesget_autorest.go | 67 - .../method_accesspolicieslist_autorest.go | 215 - .../method_accesspoliciesupdate_autorest.go | 68 - ...thod_edgemodulescreateorupdate_autorest.go | 68 - .../method_edgemodulesdelete_autorest.go | 65 - .../method_edgemodulesget_autorest.go | 67 - .../method_edgemoduleslist_autorest.go | 225 - ...gemoduleslistprovisioningtoken_autorest.go | 69 - ...locationschecknameavailability_autorest.go | 69 - ...d_videoanalyzerscreateorupdate_autorest.go | 68 - .../method_videoanalyzersdelete_autorest.go | 65 - .../method_videoanalyzersget_autorest.go | 67 - .../method_videoanalyzerslist_autorest.go | 69 - ...deoanalyzerslistbysubscription_autorest.go | 69 - ..._videoanalyzerssyncstoragekeys_autorest.go | 67 - .../method_videoanalyzersupdate_autorest.go | 68 - .../method_videoscreateorupdate_autorest.go | 68 - .../method_videosdelete_autorest.go | 65 - .../method_videosget_autorest.go | 67 - .../method_videoslist_autorest.go | 215 - ...ethod_videosliststreamingtoken_autorest.go | 68 - .../method_videosupdate_autorest.go | 68 - .../videoanalyzer/model_accesspolicyentity.go | 16 - .../model_accesspolicyproperties.go | 40 - .../videoanalyzer/model_authenticationbase.go | 48 - .../model_checknameavailabilityrequest.go | 9 - .../videoanalyzer/model_ecctokenkey.go | 44 - .../videoanalyzer/model_jwtauthentication.go | 81 - .../videoanalyzer/model_keyvaultproperties.go | 9 - .../videoanalyzer/model_rsatokenkey.go | 44 - .../videoanalyzer/model_storageaccount.go | 10 - .../videoanalyzer/model_tokenclaim.go | 9 - .../videoanalyzer/model_tokenkey.go | 56 - .../videoanalyzer/model_videoentity.go | 16 - .../videoanalyzer/model_videoflags.go | 10 - .../videoanalyzer/model_videomediainfo.go | 8 - .../videoanalyzer/model_videoproperties.go | 13 - .../videoanalyzer/model_videostreaming.go | 8 - .../model_videostreamingtoken.go | 27 - .../videoanalyzer/predicates.go | 70 - .../videoanalyzer/version.go | 12 - .../videoanalyzers/README.md | 168 + .../videoanalyzers/client.go | 18 + .../videoanalyzers/constants.go | 87 + .../videoanalyzers/id_location.go | 111 + .../videoanalyzers/id_videoanalyzer.go | 124 + ...locationschecknameavailability_autorest.go | 70 + ...d_videoanalyzerscreateorupdate_autorest.go | 69 + .../method_videoanalyzersdelete_autorest.go | 66 + .../method_videoanalyzersget_autorest.go | 68 + .../method_videoanalyzerslist_autorest.go | 70 + ...deoanalyzerslistbysubscription_autorest.go | 70 + ..._videoanalyzerssyncstoragekeys_autorest.go | 68 + .../method_videoanalyzersupdate_autorest.go | 69 + .../model_accountencryption.go | 2 +- .../model_checknameavailabilityrequest.go | 9 + .../model_checknameavailabilityresponse.go | 2 +- .../model_endpoint.go | 2 +- .../model_keyvaultproperties.go | 9 + .../model_resourceidentity.go | 2 +- .../videoanalyzers/model_storageaccount.go | 10 + .../model_syncstoragekeysinput.go | 2 +- .../model_userassignedmanagedidentity.go | 2 +- .../model_videoanalyzer.go | 2 +- .../model_videoanalyzercollection.go | 2 +- .../model_videoanalyzeridentity.go | 2 +- .../model_videoanalyzerpropertiesupdate.go | 2 +- .../model_videoanalyzerupdate.go | 2 +- .../videoanalyzers/version.go | 12 + .../authorizations/method_get_autorest.go | 1 + .../authorizations/method_list_autorest.go | 88 +- .../clusters/method_get_autorest.go | 1 + .../clusters/method_list_autorest.go | 88 +- .../vmware/2020-03-20/privateclouds/README.md | 4 +- .../privateclouds/method_get_autorest.go | 1 + .../privateclouds/method_list_autorest.go | 88 +- .../method_listadmincredentials_autorest.go | 1 + .../method_listinsubscription_autorest.go | 88 +- .../web/2016-06-01/connections/README.md | 2 +- .../method_confirmconsentcode_autorest.go | 1 + .../method_createorupdate_autorest.go | 1 + .../connections/method_delete_autorest.go | 1 + .../connections/method_get_autorest.go | 1 + .../connections/method_list_autorest.go | 1 + .../method_listconsentlinks_autorest.go | 1 + .../connections/method_update_autorest.go | 1 + .../method_managedapisget_autorest.go | 1 + .../method_managedapislist_autorest.go | 1 + .../github.com/shopspring/decimal/.gitignore | 6 - .../github.com/shopspring/decimal/.travis.yml | 13 - .../shopspring/decimal/CHANGELOG.md | 19 - vendor/github.com/shopspring/decimal/LICENSE | 45 - .../github.com/shopspring/decimal/README.md | 130 - .../shopspring/decimal/decimal-go.go | 415 - .../github.com/shopspring/decimal/decimal.go | 1477 --- .../github.com/shopspring/decimal/rounding.go | 119 - vendor/modules.txt | 114 +- website/allowed-subcategories | 2 + website/docs/d/aadb2c_directory.html.markdown | 2 +- ...ive_directory_domain_service.html.markdown | 6 +- .../d/advisor_recommendations.html.markdown | 2 +- website/docs/d/api_management.html.markdown | 2 +- .../docs/d/api_management_api.html.markdown | 2 +- ...i_management_api_version_set.html.markdown | 2 +- .../d/api_management_gateway.html.markdown | 2 +- .../docs/d/api_management_group.html.markdown | 2 +- .../d/api_management_product.html.markdown | 2 +- .../docs/d/api_management_user.html.markdown | 2 +- .../docs/d/app_configuration.html.markdown | 4 +- .../d/app_configuration_key.html.markdown | 2 +- .../d/app_configuration_keys.html.markdown | 2 +- website/docs/d/app_service.html.markdown | 2 +- .../d/app_service_certificate.html.markdown | 2 +- ...pp_service_certificate_order.html.markdown | 2 +- .../d/app_service_environment.html.markdown | 2 +- .../app_service_environment_v3.html.markdown | 2 +- website/docs/d/app_service_plan.html.markdown | 2 +- .../docs/d/application_gateway.html.markdown | 2 +- .../docs/d/application_insights.html.markdown | 2 +- .../application_security_group.html.markdown | 2 +- website/docs/d/attestation.html.markdown | 2 +- .../docs/d/automation_account.html.markdown | 2 +- .../d/automation_variable_bool.html.markdown | 2 +- ...automation_variable_datetime.html.markdown | 2 +- .../d/automation_variable_int.html.markdown | 2 +- .../automation_variable_string.html.markdown | 2 +- website/docs/d/availability_set.html.markdown | 2 +- .../d/backup_policy_file_share.html.markdown | 2 +- website/docs/d/backup_policy_vm.html.markdown | 2 +- website/docs/d/batch_account.html.markdown | 2 +- .../docs/d/batch_application.html.markdown | 2 +- .../docs/d/batch_certificate.html.markdown | 2 +- website/docs/d/batch_pool.html.markdown | 4 +- ...ing_enrollment_account_scope.html.markdown | 2 +- .../d/billing_mca_account_scope.html.markdown | 2 +- .../d/billing_mpa_account_scope.html.markdown | 2 +- .../docs/d/blueprint_definition.html.markdown | 2 +- .../blueprint_published_version.html.markdown | 2 +- .../d/cdn_frontdoor_endpoint.html.markdown | 2 +- .../cdn_frontdoor_origin_group.html.markdown | 75 + .../d/cdn_frontdoor_profile.html.markdown | 2 +- .../d/cdn_frontdoor_rule_set.html.markdown | 3 +- website/docs/d/cdn_profile.html.markdown | 2 +- website/docs/d/client_config.html.markdown | 2 +- .../docs/d/cognitive_account.html.markdown | 2 +- .../docs/d/confidential_ledger.html.markdown | 2 +- ...mption_budget_resource_group.html.markdown | 2 +- ...sumption_budget_subscription.html.markdown | 2 +- website/docs/d/container_group.html.markdown | 2 +- .../docs/d/container_registry.html.markdown | 2 +- ...container_registry_scope_map.html.markdown | 2 +- .../d/container_registry_token.html.markdown | 2 +- website/docs/d/cosmosdb_account.html.markdown | 2 +- .../d/cosmosdb_mongo_database.html.markdown | 2 +- ...restorable_database_accounts.html.markdown | 2 +- website/docs/d/data_factory.html.markdown | 2 +- ...data_protection_backup_vault.html.markdown | 2 +- website/docs/d/data_share.html.markdown | 2 +- .../docs/d/data_share_account.html.markdown | 2 +- ...a_share_dataset_blob_storage.html.markdown | 2 +- ...share_dataset_data_lake_gen2.html.markdown | 2 +- ..._share_dataset_kusto_cluster.html.markdown | 2 +- ...share_dataset_kusto_database.html.markdown | 2 +- .../database_migration_project.html.markdown | 2 +- .../database_migration_service.html.markdown | 2 +- .../docs/d/databricks_workspace.html.markdown | 2 +- ..._private_endpoint_connection.html.markdown | 2 +- website/docs/d/dedicated_host.html.markdown | 2 +- .../docs/d/dedicated_host_group.html.markdown | 2 +- website/docs/d/dev_test_lab.html.markdown | 2 +- .../d/dev_test_virtual_network.html.markdown | 2 +- .../d/digital_twins_instance.html.markdown | 2 +- website/docs/d/disk_access.html.markdown | 2 +- .../docs/d/disk_encryption_set.html.markdown | 2 +- website/docs/d/dns_a_record.html.markdown | 55 + website/docs/d/dns_aaaa_record.html.markdown | 55 + website/docs/d/dns_caa_record.html.markdown | 63 + website/docs/d/dns_cname_record.html.markdown | 55 + website/docs/d/dns_mx_record.html.markdown | 61 + website/docs/d/dns_ns_record.html.markdown | 53 + website/docs/d/dns_ptr_record.html.markdown | 53 + website/docs/d/dns_soa_record.html.markdown | 64 + website/docs/d/dns_srv_record.html.markdown | 65 + website/docs/d/dns_txt_record.html.markdown | 59 + website/docs/d/dns_zone.html.markdown | 8 +- .../elastic_cloud_elasticsearch.html.markdown | 2 +- website/docs/d/eventgrid_domain.html.markdown | 2 +- .../d/eventgrid_domain_topic.html.markdown | 2 +- .../d/eventgrid_system_topic.html.markdown | 2 +- website/docs/d/eventgrid_topic.html.markdown | 2 +- website/docs/d/eventhub.html.markdown | 2 +- .../eventhub_authorization_rule.html.markdown | 2 +- website/docs/d/eventhub_cluster.html.markdown | 2 +- .../d/eventhub_consumer_group.html.markdown | 2 +- .../docs/d/eventhub_namespace.html.markdown | 4 +- ...namespace_authorization_rule.html.markdown | 2 +- .../d/express_route_circuit.html.markdown | 2 +- .../docs/d/extended_locations.html.markdown | 2 +- website/docs/d/firewall.html.markdown | 2 +- website/docs/d/firewall_policy.html.markdown | 2 +- website/docs/d/function_app.html.markdown | 2 +- .../docs/d/hdinsight_cluster.html.markdown | 2 +- website/docs/d/healthcare_dicom.html.markdown | 2 +- .../d/healthcare_fhir_service.html.markdown | 2 +- .../healthcare_medtech_service.html.markdown | 60 + .../docs/d/healthcare_service.html.markdown | 2 +- .../docs/d/healthcare_workspace.html.markdown | 2 +- website/docs/d/image.html.markdown | 2 +- website/docs/d/images.html.markdown | 2 +- website/docs/d/iothub.html.markdown | 2 +- website/docs/d/iothub_dps.html.markdown | 2 +- ...hub_dps_shared_access_policy.html.markdown | 2 +- .../iothub_shared_access_policy.html.markdown | 2 +- website/docs/d/ip_group.html.markdown | 2 +- website/docs/d/key_vault.html.markdown | 4 +- .../d/key_vault_access_policy.html.markdown | 2 +- .../d/key_vault_certificate.html.markdown | 4 +- .../key_vault_certificate_data.html.markdown | 2 +- ...key_vault_certificate_issuer.html.markdown | 2 +- .../d/key_vault_encrypted_value.html.markdown | 2 +- website/docs/d/key_vault_key.html.markdown | 4 +- ...ged_hardware_security_module.html.markdown | 2 +- website/docs/d/key_vault_secret.html.markdown | 4 +- .../docs/d/key_vault_secrets.html.markdown | 2 +- .../docs/d/kubernetes_cluster.html.markdown | 2 +- ...kubernetes_cluster_node_pool.html.markdown | 2 +- .../kubernetes_service_versions.html.markdown | 2 +- website/docs/d/kusto_cluster.html.markdown | 2 +- website/docs/d/kusto_database.html.markdown | 2 +- website/docs/d/lb.html.markdown | 4 +- .../d/lb_backend_address_pool.html.markdown | 4 +- website/docs/d/lb_rule.html.markdown | 2 +- .../docs/d/linux_function_app.html.markdown | 46 +- website/docs/d/linux_web_app.html.markdown | 4 +- .../d/local_network_gateway.html.markdown | 2 +- .../d/log_analytics_workspace.html.markdown | 2 +- ...ogic_app_integration_account.html.markdown | 2 +- .../docs/d/logic_app_standard.html.markdown | 2 +- .../docs/d/logic_app_workflow.html.markdown | 10 +- .../machine_learning_workspace.html.markdown | 2 +- .../d/maintenance_configuration.html.markdown | 2 +- website/docs/d/managed_api.html.markdown | 2 +- ...naged_application_definition.html.markdown | 2 +- website/docs/d/managed_disk.html.markdown | 28 +- website/docs/d/management_group.html.markdown | 10 +- ...nt_group_template_deployment.html.markdown | 2 +- website/docs/d/maps_account.html.markdown | 2 +- website/docs/d/mariadb_server.html.markdown | 2 +- .../docs/d/monitor_action_group.html.markdown | 2 +- ...tor_data_collection_endpoint.html.markdown | 55 + ...onitor_diagnostic_categories.html.markdown | 10 +- .../docs/d/monitor_log_profile.html.markdown | 2 +- ..._scheduled_query_rules_alert.html.markdown | 2 +- ...or_scheduled_query_rules_log.html.markdown | 2 +- website/docs/d/mssql_database.html.markdown | 2 +- .../docs/d/mssql_elasticpool.html.markdown | 2 +- .../d/mssql_managed_instance.html.markdown | 2 +- website/docs/d/mssql_server.html.markdown | 2 +- .../d/mysql_flexible_server.html.markdown | 2 +- website/docs/d/mysql_server.html.markdown | 2 +- website/docs/d/nat_gateway.html.markdown | 2 +- website/docs/d/netapp_account.html.markdown | 2 +- website/docs/d/netapp_pool.html.markdown | 2 +- website/docs/d/netapp_snapshot.html.markdown | 2 +- .../d/netapp_snapshot_policy.html.markdown | 2 +- website/docs/d/netapp_volume.html.markdown | 2 +- ...network_ddos_protection_plan.html.markdown | 2 +- .../docs/d/network_interface.html.markdown | 2 +- .../d/network_security_group.html.markdown | 2 +- .../docs/d/network_service_tags.html.markdown | 2 +- website/docs/d/network_watcher.html.markdown | 2 +- website/docs/d/notification_hub.html.markdown | 2 +- .../notification_hub_namespace.html.markdown | 2 +- website/docs/d/platform_image.html.markdown | 2 +- .../docs/d/policy_assignment.html.markdown | 2 +- .../docs/d/policy_definition.html.markdown | 2 +- .../d/policy_set_definition.html.markdown | 2 +- ...ine_configuration_assignment.html.markdown | 2 +- website/docs/d/portal_dashboard.html.markdown | 2 +- .../postgresql_flexible_server.html.markdown | 2 +- .../docs/d/postgresql_server.html.markdown | 2 +- .../docs/d/private_dns_a_record.html.markdown | 53 + .../d/private_dns_aaaa_record.html.markdown | 53 + .../d/private_dns_cname_record.html.markdown | 53 + .../d/private_dns_mx_record.html.markdown | 61 + .../d/private_dns_ptr_record.html.markdown | 53 + .../d/private_dns_soa_record.html.markdown | 64 + .../d/private_dns_srv_record.html.markdown | 65 + .../d/private_dns_txt_record.html.markdown | 59 + website/docs/d/private_dns_zone.html.markdown | 7 +- .../private_endpoint_connection.html.markdown | 2 +- .../docs/d/private_link_service.html.markdown | 2 +- ...service_endpoint_connections.html.markdown | 2 +- .../d/proximity_placement_group.html.markdown | 2 +- website/docs/d/public_ip.html.markdown | 2 +- website/docs/d/public_ip_prefix.html.markdown | 2 +- website/docs/d/public_ips.html.markdown | 2 +- ...c_maintenance_configurations.html.markdown | 4 +- .../d/recovery_services_vault.html.markdown | 2 +- website/docs/d/redis_cache.html.markdown | 4 +- .../d/redis_enterprise_database.html.markdown | 2 +- website/docs/d/resource_group.html.markdown | 2 +- ...ce_group_template_deployment.html.markdown | 2 +- website/docs/d/resources.html.markdown | 2 +- website/docs/d/role_definition.html.markdown | 2 +- website/docs/d/route_filter.html.markdown | 2 +- website/docs/d/route_table.html.markdown | 2 +- website/docs/d/search_service.html.markdown | 2 +- .../docs/d/sentinel_alert_rule.html.markdown | 2 +- ...sentinel_alert_rule_template.html.markdown | 16 +- website/docs/d/service_plan.html.markdown | 2 +- .../docs/d/servicebus_namespace.html.markdown | 2 +- ...namespace_authorization_rule.html.markdown | 2 +- website/docs/d/servicebus_queue.html.markdown | 2 +- ...bus_queue_authorization_rule.html.markdown | 2 +- .../d/servicebus_subscription.html.markdown | 14 +- website/docs/d/servicebus_topic.html.markdown | 2 +- ...bus_topic_authorization_rule.html.markdown | 2 +- website/docs/d/shared_image.html.markdown | 2 +- .../docs/d/shared_image_gallery.html.markdown | 2 +- .../docs/d/shared_image_version.html.markdown | 2 +- .../d/shared_image_versions.html.markdown | 2 +- website/docs/d/signalr_service.html.markdown | 2 +- .../docs/d/site_recovery_fabric.html.markdown | 2 +- ...ecovery_protection_container.html.markdown | 2 +- ..._recovery_replication_policy.html.markdown | 2 +- website/docs/d/snapshot.html.markdown | 2 +- .../docs/d/source_control_token.html.markdown | 2 +- .../d/spatial_anchors_account.html.markdown | 2 +- website/docs/d/spring_cloud_app.html.markdown | 2 +- .../docs/d/spring_cloud_service.html.markdown | 2 +- website/docs/d/sql_database.html.markdown | 2 +- .../docs/d/sql_managed_instance.html.markdown | 2 +- website/docs/d/sql_server.html.markdown | 2 +- website/docs/d/ssh_public_key.html.markdown | 2 +- website/docs/d/storage_account.html.markdown | 2 +- ...e_account_blob_container_sas.html.markdown | 2 +- .../docs/d/storage_account_sas.html.markdown | 2 +- website/docs/d/storage_blob.html.markdown | 2 +- .../docs/d/storage_container.html.markdown | 2 +- .../d/storage_encryption_scope.html.markdown | 2 +- .../d/storage_management_policy.html.markdown | 2 +- website/docs/d/storage_share.html.markdown | 2 +- website/docs/d/storage_sync.html.markdown | 2 +- .../docs/d/storage_sync_group.html.markdown | 2 +- .../docs/d/storage_table_entity.html.markdown | 2 +- .../docs/d/stream_analytics_job.html.markdown | 2 +- website/docs/d/subnet.html.markdown | 8 +- website/docs/d/subscription.html.markdown | 2 +- ...cription_template_deployment.html.markdown | 2 +- website/docs/d/subscriptions.html.markdown | 2 +- .../docs/d/synapse_workspace.html.markdown | 2 +- .../d/template_spec_version.html.markdown | 2 +- .../tenant_template_deployment.html.markdown | 2 +- ...anager_geographical_location.html.markdown | 2 +- .../d/traffic_manager_profile.html.markdown | 2 +- .../d/user_assigned_identity.html.markdown | 2 +- website/docs/d/virtual_hub.html.markdown | 2 +- website/docs/d/virtual_machine.html.markdown | 2 +- .../d/virtual_machine_scale_set.html.markdown | 22 +- website/docs/d/virtual_network.html.markdown | 2 +- .../d/virtual_network_gateway.html.markdown | 2 +- ...l_network_gateway_connection.html.markdown | 2 +- website/docs/d/virtual_wan.html.markdown | 2 +- .../docs/d/vmware_private_cloud.html.markdown | 2 +- website/docs/d/vpn_gateway.html.markdown | 2 +- ..._application_firewall_policy.html.markdown | 2 +- website/docs/d/web_pubsub.html.markdown | 2 +- ...pubsub_private_link_resource.html.markdown | 58 + .../docs/d/windows_function_app.html.markdown | 4 +- website/docs/d/windows_web_app.html.markdown | 10 +- .../guides/3.0-upgrade-guide.html.markdown | 4 +- .../docs/guides/features-block.html.markdown | 6 +- .../managed_service_identity.html.markdown | 2 +- .../service_principal_oidc.html.markdown | 30 +- website/docs/index.html.markdown | 4 +- website/docs/r/aadb2c_directory.html.markdown | 2 +- ...ive_directory_domain_service.html.markdown | 6 +- ...y_domain_service_replica_set.html.markdown | 2 +- ...rectory_domain_service_trust.html.markdown | 2 +- .../advanced_threat_protection.html.markdown | 2 +- .../r/analysis_services_server.html.markdown | 2 +- website/docs/r/api_connection.html.markdown | 2 +- website/docs/r/api_management.html.markdown | 4 +- .../docs/r/api_management_api.html.markdown | 2 +- ...pi_management_api_diagnostic.html.markdown | 2 +- ...api_management_api_operation.html.markdown | 2 +- ...agement_api_operation_policy.html.markdown | 4 +- ...management_api_operation_tag.html.markdown | 2 +- .../r/api_management_api_policy.html.markdown | 2 +- .../api_management_api_release.html.markdown | 2 +- .../r/api_management_api_schema.html.markdown | 2 +- .../r/api_management_api_tag.html.markdown | 2 +- ...i_management_api_version_set.html.markdown | 2 +- ...agement_authorization_server.html.markdown | 4 +- .../r/api_management_backend.html.markdown | 2 +- .../api_management_certificate.html.markdown | 2 +- ...api_management_custom_domain.html.markdown | 2 +- .../r/api_management_diagnostic.html.markdown | 2 +- ...pi_management_email_template.html.markdown | 2 +- .../r/api_management_gateway.html.markdown | 2 +- .../api_management_gateway_api.html.markdown | 2 +- ...ateway_certificate_authority.html.markdown | 91 + .../docs/r/api_management_group.html.markdown | 2 +- .../r/api_management_group_user.html.markdown | 2 +- ...gement_identity_provider_aad.html.markdown | 2 +- ...ent_identity_provider_aadb2c.html.markdown | 2 +- ...t_identity_provider_facebook.html.markdown | 2 +- ...ent_identity_provider_google.html.markdown | 2 +- ..._identity_provider_microsoft.html.markdown | 2 +- ...nt_identity_provider_twitter.html.markdown | 2 +- .../r/api_management_logger.html.markdown | 2 +- .../api_management_named_value.html.markdown | 2 +- ...notification_recipient_email.html.markdown | 2 +- ..._notification_recipient_user.html.markdown | 2 +- ...ment_openid_connect_provider.html.markdown | 2 +- .../r/api_management_policy.html.markdown | 2 +- .../r/api_management_product.html.markdown | 2 +- .../api_management_product_api.html.markdown | 2 +- ...api_management_product_group.html.markdown | 2 +- ...pi_management_product_policy.html.markdown | 2 +- .../api_management_product_tag.html.markdown | 89 + .../api_management_redis_cache.html.markdown | 2 +- .../api_management_subscription.html.markdown | 2 +- .../docs/r/api_management_tag.html.markdown | 2 +- .../docs/r/api_management_user.html.markdown | 2 +- .../docs/r/app_configuration.html.markdown | 8 +- .../r/app_configuration_feature.html.markdown | 2 +- .../r/app_configuration_key.html.markdown | 2 +- website/docs/r/app_service.html.markdown | 2 +- .../r/app_service_active_slot.html.markdown | 2 +- .../r/app_service_certificate.html.markdown | 2 +- ...pp_service_certificate_order.html.markdown | 2 +- ...vice_custom_hostname_binding.html.markdown | 2 +- .../r/app_service_environment.html.markdown | 2 +- .../app_service_environment_v3.html.markdown | 11 +- ..._service_managed_certificate.html.markdown | 2 +- website/docs/r/app_service_plan.html.markdown | 2 +- ...p_service_public_certificate.html.markdown | 2 +- website/docs/r/app_service_slot.html.markdown | 2 +- ...slot_custom_hostname_binding.html.markdown | 2 +- ...ual_network_swift_connection.html.markdown | 2 +- .../app_service_source_control.html.markdown | 2 +- ..._service_source_control_slot.html.markdown | 2 +- ...service_source_control_token.html.markdown | 2 +- ...ual_network_swift_connection.html.markdown | 24 +- .../docs/r/application_gateway.html.markdown | 20 +- .../docs/r/application_insights.html.markdown | 2 +- ...tion_insights_analytics_item.html.markdown | 2 +- ...application_insights_api_key.html.markdown | 2 +- ...nsights_smart_detection_rule.html.markdown | 2 +- ...pplication_insights_web_test.html.markdown | 2 +- ...pplication_insights_workbook.html.markdown | 110 + ...n_insights_workbook_template.html.markdown | 2 +- .../application_security_group.html.markdown | 2 +- website/docs/r/attestation.html.markdown | 2 +- .../docs/r/automation_account.html.markdown | 16 +- .../r/automation_certificate.html.markdown | 2 +- .../r/automation_connection.html.markdown | 2 +- ...ation_connection_certificate.html.markdown | 2 +- ...nnection_classic_certificate.html.markdown | 2 +- ...connection_service_principal.html.markdown | 2 +- .../automation_connection_type.html.markdown | 94 + .../r/automation_credential.html.markdown | 2 +- ...automation_dsc_configuration.html.markdown | 2 +- ...mation_dsc_nodeconfiguration.html.markdown | 2 +- ..._hybrid_runbook_worker_group.html.markdown | 58 + .../r/automation_job_schedule.html.markdown | 2 +- .../docs/r/automation_module.html.markdown | 2 +- .../docs/r/automation_runbook.html.markdown | 2 +- .../docs/r/automation_schedule.html.markdown | 4 +- .../r/automation_variable_bool.html.markdown | 2 +- ...automation_variable_datetime.html.markdown | 2 +- .../r/automation_variable_int.html.markdown | 2 +- .../automation_variable_string.html.markdown | 2 +- .../docs/r/automation_webhook.html.markdown | 2 +- website/docs/r/availability_set.html.markdown | 2 +- ...ver_vulnerability_assessment.html.markdown | 4 +- ..._learning_behavior_analytics.html.markdown | 2 +- ...up_container_storage_account.html.markdown | 2 +- .../r/backup_policy_file_share.html.markdown | 2 +- website/docs/r/backup_policy_vm.html.markdown | 2 +- .../r/backup_policy_vm_workload.html.markdown | 194 + .../backup_protected_file_share.html.markdown | 2 +- .../docs/r/backup_protected_vm.html.markdown | 2 +- website/docs/r/bastion_host.html.markdown | 2 +- website/docs/r/batch_account.html.markdown | 12 +- .../docs/r/batch_application.html.markdown | 2 +- .../docs/r/batch_certificate.html.markdown | 2 +- website/docs/r/batch_job.html.markdown | 2 +- website/docs/r/batch_pool.html.markdown | 3 +- .../docs/r/blueprint_assignment.html.markdown | 2 +- .../docs/r/bot_channel_alexa.html.markdown | 2 +- ...t_channel_direct_line_speech.html.markdown | 2 +- .../r/bot_channel_directline.html.markdown | 2 +- .../docs/r/bot_channel_email.html.markdown | 2 +- .../docs/r/bot_channel_facebook.html.markdown | 2 +- website/docs/r/bot_channel_line.html.markdown | 2 +- .../docs/r/bot_channel_ms_teams.html.markdown | 2 +- .../docs/r/bot_channel_slack.html.markdown | 2 +- website/docs/r/bot_channel_sms.html.markdown | 2 +- .../docs/r/bot_channel_web_chat.html.markdown | 2 +- .../r/bot_channels_registration.html.markdown | 2 +- website/docs/r/bot_connection.html.markdown | 2 +- website/docs/r/bot_healthbot.html.markdown | 2 +- .../r/bot_service_azure_bot.html.markdown | 4 +- website/docs/r/bot_web_app.html.markdown | 2 +- .../docs/r/capacity_reservation.html.markdown | 2 +- .../capacity_reservation_group.html.markdown | 2 +- website/docs/r/cdn_endpoint.html.markdown | 2 +- .../cdn_endpoint_custom_domain.html.markdown | 8 +- .../r/cdn_frontdoor_endpoint.html.markdown | 3 +- ...dn_frontdoor_firewall_policy.html.markdown | 267 + .../docs/r/cdn_frontdoor_origin.html.markdown | 193 + .../cdn_frontdoor_origin_group.html.markdown | 110 + .../r/cdn_frontdoor_profile.html.markdown | 2 +- .../r/cdn_frontdoor_rule_set.html.markdown | 3 +- ...dn_frontdoor_security_policy.html.markdown | 136 + website/docs/r/cdn_profile.html.markdown | 2 +- .../docs/r/cognitive_account.html.markdown | 8 +- ...account_customer_managed_key.html.markdown | 2 +- .../r/communication_service.html.markdown | 2 +- .../docs/r/confidential_ledger.html.markdown | 2 +- ...tion_budget_management_group.html.markdown | 2 +- ...mption_budget_resource_group.html.markdown | 2 +- ...sumption_budget_subscription.html.markdown | 2 +- ...container_connected_registry.html.markdown | 2 +- website/docs/r/container_group.html.markdown | 17 +- .../docs/r/container_registry.html.markdown | 22 +- ...ontainer_registry_agent_pool.html.markdown | 2 +- ...container_registry_scope_map.html.markdown | 2 +- .../r/container_registry_task.html.markdown | 2 +- ...gistry_task_schedule_run_now.html.markdown | 66 + .../r/container_registry_token.html.markdown | 2 +- .../container_registry_webhook.html.markdown | 4 +- website/docs/r/cosmosdb_account.html.markdown | 2 +- .../cosmosdb_cassandra_cluster.html.markdown | 2 +- ...osmosdb_cassandra_datacenter.html.markdown | 2 +- .../cosmosdb_cassandra_keyspace.html.markdown | 2 +- .../r/cosmosdb_cassandra_table.html.markdown | 2 +- .../r/cosmosdb_gremlin_database.html.markdown | 2 +- .../r/cosmosdb_gremlin_graph.html.markdown | 2 +- .../r/cosmosdb_mongo_collection.html.markdown | 2 +- .../r/cosmosdb_mongo_database.html.markdown | 2 +- .../cosmosdb_notebook_workspace.html.markdown | 2 +- .../r/cosmosdb_sql_container.html.markdown | 2 +- .../r/cosmosdb_sql_database.html.markdown | 4 +- ...smosdb_sql_dedicated_gateway.html.markdown | 76 + .../r/cosmosdb_sql_function.html.markdown | 2 +- ...cosmosdb_sql_role_assignment.html.markdown | 2 +- ...cosmosdb_sql_role_definition.html.markdown | 2 +- ...osmosdb_sql_stored_procedure.html.markdown | 2 +- .../docs/r/cosmosdb_sql_trigger.html.markdown | 2 +- website/docs/r/cosmosdb_table.html.markdown | 2 +- website/docs/r/custom_provider.html.markdown | 2 +- website/docs/r/dashboard.html.markdown | 2 +- .../docs/r/dashboard_grafana.html.markdown | 108 + website/docs/r/data_factory.html.markdown | 2 +- .../data_factory_custom_dataset.html.markdown | 2 +- .../r/data_factory_data_flow.html.markdown | 100 +- ...a_factory_dataset_azure_blob.html.markdown | 2 +- .../data_factory_dataset_binary.html.markdown | 2 +- ...tory_dataset_cosmosdb_sqlapi.html.markdown | 2 +- ...ctory_dataset_delimited_text.html.markdown | 2 +- .../r/data_factory_dataset_http.html.markdown | 2 +- .../r/data_factory_dataset_json.html.markdown | 2 +- .../data_factory_dataset_mysql.html.markdown | 2 +- ...data_factory_dataset_parquet.html.markdown | 2 +- ...a_factory_dataset_postgresql.html.markdown | 2 +- ...ta_factory_dataset_snowflake.html.markdown | 2 +- ...ory_dataset_sql_server_table.html.markdown | 2 +- ...ta_factory_flowlet_data_flow.html.markdown | 310 + ...tegration_runtime_azure_ssis.html.markdown | 10 +- ..._integration_runtime_managed.html.markdown | 2 +- ...egration_runtime_self_hosted.html.markdown | 2 +- ...actory_linked_custom_service.html.markdown | 2 +- ...d_service_azure_blob_storage.html.markdown | 2 +- ...ked_service_azure_databricks.html.markdown | 2 +- ...d_service_azure_file_storage.html.markdown | 2 +- ...inked_service_azure_function.html.markdown | 2 +- ..._linked_service_azure_search.html.markdown | 2 +- ...d_service_azure_sql_database.html.markdown | 2 +- ..._service_azure_table_storage.html.markdown | 2 +- ...tory_linked_service_cosmosdb.html.markdown | 2 +- ...ed_service_cosmosdb_mongoapi.html.markdown | 2 +- ...rvice_data_lake_storage_gen2.html.markdown | 2 +- ...ory_linked_service_key_vault.html.markdown | 2 +- ...factory_linked_service_kusto.html.markdown | 2 +- ...factory_linked_service_mysql.html.markdown | 2 +- ...factory_linked_service_odata.html.markdown | 2 +- ..._factory_linked_service_odbc.html.markdown | 2 +- ...ry_linked_service_postgresql.html.markdown | 2 +- ..._factory_linked_service_sftp.html.markdown | 2 +- ...ory_linked_service_snowflake.html.markdown | 2 +- ...ry_linked_service_sql_server.html.markdown | 2 +- ...ctory_linked_service_synapse.html.markdown | 2 +- ...a_factory_linked_service_web.html.markdown | 2 +- ...ory_managed_private_endpoint.html.markdown | 2 +- .../r/data_factory_pipeline.html.markdown | 2 +- ...a_factory_trigger_blob_event.html.markdown | 2 +- ...factory_trigger_custom_event.html.markdown | 2 +- ...ata_factory_trigger_schedule.html.markdown | 2 +- ...data_factory_tumbling_window.html.markdown | 2 +- ...backup_instance_blob_storage.html.markdown | 2 +- ...tection_backup_instance_disk.html.markdown | 2 +- ...n_backup_instance_postgresql.html.markdown | 2 +- ...n_backup_policy_blob_storage.html.markdown | 2 +- ...rotection_backup_policy_disk.html.markdown | 2 +- ...ion_backup_policy_postgresql.html.markdown | 2 +- ...data_protection_backup_vault.html.markdown | 2 +- ...ta_protection_resource_guard.html.markdown | 2 +- website/docs/r/data_share.html.markdown | 2 +- .../docs/r/data_share_account.html.markdown | 2 +- ...a_share_dataset_blob_storage.html.markdown | 2 +- ...share_dataset_data_lake_gen2.html.markdown | 2 +- ..._share_dataset_kusto_cluster.html.markdown | 2 +- ...share_dataset_kusto_database.html.markdown | 2 +- .../database_migration_project.html.markdown | 2 +- .../database_migration_service.html.markdown | 2 +- .../docs/r/databox_edge_device.html.markdown | 2 +- .../docs/r/databox_edge_order.html.markdown | 2 +- .../docs/r/databricks_workspace.html.markdown | 2 +- ...rkspace_customer_managed_key.html.markdown | 2 +- website/docs/r/datadog_monitors.html.markdown | 148 + ...ted_hardware_security_module.html.markdown | 2 +- website/docs/r/dedicated_host.html.markdown | 2 +- .../docs/r/dedicated_host_group.html.markdown | 2 +- website/docs/r/dev_test_lab.html.markdown | 2 +- ...v_test_linux_virtual_machine.html.markdown | 2 +- website/docs/r/dev_test_policy.html.markdown | 2 +- .../docs/r/dev_test_schedule.html.markdown | 2 +- .../r/dev_test_virtual_network.html.markdown | 2 +- ...test_windows_virtual_machine.html.markdown | 2 +- ...tal_twins_endpoint_eventgrid.html.markdown | 2 +- ...ital_twins_endpoint_eventhub.html.markdown | 2 +- ...al_twins_endpoint_servicebus.html.markdown | 2 +- .../r/digital_twins_instance.html.markdown | 2 +- website/docs/r/disk_access.html.markdown | 2 +- .../docs/r/disk_encryption_set.html.markdown | 2 +- website/docs/r/disk_pool.html.markdown | 2 +- .../r/disk_pool_iscsi_target.html.markdown | 2 +- .../disk_pool_iscsi_target_lun.html.markdown | 2 +- ...pool_managed_disk_attachment.html.markdown | 2 +- website/docs/r/disk_sas_token.html.markdown | 2 +- website/docs/r/dns_a_record.html.markdown | 12 +- website/docs/r/dns_aaaa_record.html.markdown | 12 +- website/docs/r/dns_caa_record.html.markdown | 13 +- website/docs/r/dns_cname_record.html.markdown | 18 +- website/docs/r/dns_mx_record.html.markdown | 15 +- website/docs/r/dns_ns_record.html.markdown | 17 +- website/docs/r/dns_ptr_record.html.markdown | 12 +- website/docs/r/dns_srv_record.html.markdown | 16 +- website/docs/r/dns_txt_record.html.markdown | 15 +- website/docs/r/dns_zone.html.markdown | 11 +- .../elastic_cloud_elasticsearch.html.markdown | 2 +- website/docs/r/eventgrid_domain.html.markdown | 2 +- .../r/eventgrid_domain_topic.html.markdown | 2 +- ...eventgrid_event_subscription.html.markdown | 2 +- .../r/eventgrid_system_topic.html.markdown | 2 +- ...tem_topic_event_subscription.html.markdown | 2 +- website/docs/r/eventgrid_topic.html.markdown | 2 +- website/docs/r/eventhub.html.markdown | 2 +- .../eventhub_authorization_rule.html.markdown | 2 +- website/docs/r/eventhub_cluster.html.markdown | 2 +- .../r/eventhub_consumer_group.html.markdown | 2 +- .../docs/r/eventhub_namespace.html.markdown | 10 +- ...namespace_authorization_rule.html.markdown | 2 +- ...mespace_customer_managed_key.html.markdown | 2 +- ...ace_disaster_recovery_config.html.markdown | 2 +- ...nthub_namespace_schema_group.html.markdown | 64 + .../r/express_route_circuit.html.markdown | 2 +- ..._route_circuit_authorization.html.markdown | 2 +- ...ess_route_circuit_connection.html.markdown | 2 +- ...xpress_route_circuit_peering.html.markdown | 68 +- .../r/express_route_connection.html.markdown | 2 +- .../r/express_route_gateway.html.markdown | 2 +- .../docs/r/express_route_port.html.markdown | 2 +- website/docs/r/firewall.html.markdown | 4 +- ..._application_rule_collection.html.markdown | 2 +- ...firewall_nat_rule_collection.html.markdown | 2 +- ...wall_network_rule_collection.html.markdown | 2 +- website/docs/r/firewall_policy.html.markdown | 6 +- ...policy_rule_collection_group.html.markdown | 4 +- .../docs/r/fluid_relay_servers.html.markdown | 2 +- website/docs/r/frontdoor.html.markdown | 2 +- ...r_custom_https_configuration.html.markdown | 2 +- .../r/frontdoor_firewall_policy.html.markdown | 2 +- website/docs/r/function_app.html.markdown | 2 +- .../r/function_app_active_slot.html.markdown | 2 +- .../r/function_app_function.html.markdown | 2 +- ...nction_app_hybrid_connection.html.markdown | 2 +- .../docs/r/function_app_slot.html.markdown | 2 +- .../docs/r/gallery_application.html.markdown | 2 +- .../gallery_application_version.html.markdown | 2 +- .../r/hdinsight_hadoop_cluster.html.markdown | 42 +- .../r/hdinsight_hbase_cluster.html.markdown | 14 +- ...ht_interactive_query_cluster.html.markdown | 14 +- .../r/hdinsight_kafka_cluster.html.markdown | 14 +- .../r/hdinsight_spark_cluster.html.markdown | 16 +- website/docs/r/healthcare_dicom.html.markdown | 2 +- .../r/healthcare_fhir_service.html.markdown | 2 +- .../healthcare_medtech_service.html.markdown | 111 + ...ech_service_fhir_destination.html.markdown | 85 + .../docs/r/healthcare_service.html.markdown | 2 +- .../docs/r/healthcare_workspace.html.markdown | 2 +- website/docs/r/hpc_cache.html.markdown | 2 +- .../r/hpc_cache_access_policy.html.markdown | 2 +- .../r/hpc_cache_blob_nfs_target.html.markdown | 2 +- .../r/hpc_cache_blob_target.html.markdown | 2 +- .../docs/r/hpc_cache_nfs_target.html.markdown | 2 +- website/docs/r/image.html.markdown | 2 +- ...egration_service_environment.html.markdown | 12 +- .../r/iot_security_device_group.html.markdown | 2 +- .../r/iot_security_solution.html.markdown | 2 +- ...eries_insights_access_policy.html.markdown | 2 +- ...sights_event_source_eventhub.html.markdown | 2 +- ...insights_event_source_iothub.html.markdown | 2 +- ...es_insights_gen2_environment.html.markdown | 2 +- ..._insights_reference_data_set.html.markdown | 2 +- ...nsights_standard_environment.html.markdown | 2 +- .../r/iotcentral_application.html.markdown | 4 +- website/docs/r/iothub.html.markdown | 2 +- .../docs/r/iothub_certificate.html.markdown | 2 +- .../r/iothub_consumer_group.html.markdown | 2 +- website/docs/r/iothub_dps.html.markdown | 4 +- .../r/iothub_dps_certificate.html.markdown | 4 +- ...hub_dps_shared_access_policy.html.markdown | 2 +- .../r/iothub_endpoint_eventhub.html.markdown | 2 +- ...ub_endpoint_servicebus_queue.html.markdown | 2 +- ...ub_endpoint_servicebus_topic.html.markdown | 2 +- ...b_endpoint_storage_container.html.markdown | 2 +- .../docs/r/iothub_enrichment.html.markdown | 2 +- .../r/iothub_fallback_route.html.markdown | 2 +- website/docs/r/iothub_route.html.markdown | 2 +- .../iothub_shared_access_policy.html.markdown | 2 +- website/docs/r/ip_group.html.markdown | 2 +- website/docs/r/key_vault.html.markdown | 4 +- .../r/key_vault_access_policy.html.markdown | 4 +- .../r/key_vault_certificate.html.markdown | 4 +- website/docs/r/key_vault_key.html.markdown | 4 +- ...ged_hardware_security_module.html.markdown | 2 +- ...ault_managed_storage_account.html.markdown | 2 +- ...account_sas_token_definition.html.markdown | 2 +- website/docs/r/key_vault_secret.html.markdown | 4 +- .../docs/r/kubernetes_cluster.html.markdown | 12 +- ...kubernetes_cluster_node_pool.html.markdown | 10 +- ...ached_database_configuration.html.markdown | 2 +- website/docs/r/kusto_cluster.html.markdown | 12 +- ...cluster_customer_managed_key.html.markdown | 2 +- ...ter_managed_private_endpoint.html.markdown | 86 + ...cluster_principal_assignment.html.markdown | 2 +- website/docs/r/kusto_database.html.markdown | 2 +- ...atabase_principal_assignment.html.markdown | 2 +- ...to_eventgrid_data_connection.html.markdown | 2 +- ...sto_eventhub_data_connection.html.markdown | 2 +- ...kusto_iothub_data_connection.html.markdown | 2 +- website/docs/r/kusto_script.html.markdown | 2 +- website/docs/r/lb.html.markdown | 2 +- .../r/lb_backend_address_pool.html.markdown | 2 +- ...backend_address_pool_address.html.markdown | 29 +- website/docs/r/lb_nat_pool.html.markdown | 2 +- website/docs/r/lb_nat_rule.html.markdown | 2 +- website/docs/r/lb_outbound_rule.html.markdown | 2 +- website/docs/r/lb_probe.html.markdown | 2 +- website/docs/r/lb_rule.html.markdown | 2 +- .../r/lighthouse_assignment.html.markdown | 2 +- .../r/lighthouse_definition.html.markdown | 2 +- .../docs/r/linux_function_app.html.markdown | 19 +- .../r/linux_function_app_slot.html.markdown | 8 +- .../r/linux_virtual_machine.html.markdown | 4 +- ...ux_virtual_machine_scale_set.html.markdown | 8 +- website/docs/r/linux_web_app.html.markdown | 8 +- .../docs/r/linux_web_app_slot.html.markdown | 8 +- website/docs/r/load_test.html.markdown | 2 +- .../r/local_network_gateway.html.markdown | 2 +- .../r/log_analytics_cluster.html.markdown | 6 +- ...cluster_customer_managed_key.html.markdown | 2 +- ...g_analytics_data_export_rule.html.markdown | 2 +- ...ics_datasource_windows_event.html.markdown | 2 +- ..._windows_performance_counter.html.markdown | 2 +- ...log_analytics_linked_service.html.markdown | 2 +- ...ytics_linked_storage_account.html.markdown | 2 +- .../r/log_analytics_query_pack.html.markdown | 63 + ...g_analytics_query_pack_query.html.markdown | 80 + .../log_analytics_saved_search.html.markdown | 2 +- .../r/log_analytics_solution.html.markdown | 2 +- ...g_analytics_storage_insights.html.markdown | 2 +- .../r/log_analytics_workspace.html.markdown | 4 +- .../r/logic_app_action_custom.html.markdown | 2 +- .../r/logic_app_action_http.html.markdown | 2 +- ...ogic_app_integration_account.html.markdown | 2 +- ...ntegration_account_agreement.html.markdown | 2 +- ...integration_account_assembly.html.markdown | 2 +- ..._account_batch_configuration.html.markdown | 2 +- ...egration_account_certificate.html.markdown | 2 +- ..._app_integration_account_map.html.markdown | 2 +- ..._integration_account_partner.html.markdown | 2 +- ...p_integration_account_schema.html.markdown | 2 +- ..._integration_account_session.html.markdown | 2 +- .../docs/r/logic_app_standard.html.markdown | 2 +- .../r/logic_app_trigger_custom.html.markdown | 2 +- ...gic_app_trigger_http_request.html.markdown | 2 +- ...logic_app_trigger_recurrence.html.markdown | 2 +- .../docs/r/logic_app_workflow.html.markdown | 2 +- website/docs/r/logz_monitor.html.markdown | 2 +- website/docs/r/logz_sub_account.html.markdown | 2 +- .../r/logz_sub_account_tag_rule.html.markdown | 119 + website/docs/r/logz_tag_rule.html.markdown | 2 +- ...ine_learning_compute_cluster.html.markdown | 6 +- ...ne_learning_compute_instance.html.markdown | 2 +- ...e_learning_inference_cluster.html.markdown | 2 +- ...chine_learning_synapse_spark.html.markdown | 2 +- .../machine_learning_workspace.html.markdown | 2 +- ...ce_assignment_dedicated_host.html.markdown | 4 +- ...e_assignment_virtual_machine.html.markdown | 2 +- ...nt_virtual_machine_scale_set.html.markdown | 2 +- .../r/maintenance_configuration.html.markdown | 6 +- .../docs/r/managed_application.html.markdown | 2 +- ...naged_application_definition.html.markdown | 2 +- website/docs/r/managed_disk.html.markdown | 4 +- website/docs/r/management_group.html.markdown | 2 +- ...ment_group_policy_assignment.html.markdown | 2 +- ...ement_group_policy_exemption.html.markdown | 2 +- ...ent_group_policy_remediation.html.markdown | 10 +- ...oup_subscription_association.html.markdown | 2 +- ...nt_group_template_deployment.html.markdown | 2 +- website/docs/r/management_lock.html.markdown | 2 +- website/docs/r/maps_account.html.markdown | 2 +- website/docs/r/maps_creator.html.markdown | 2 +- .../r/mariadb_configuration.html.markdown | 2 +- website/docs/r/mariadb_database.html.markdown | 2 +- .../r/mariadb_firewall_rule.html.markdown | 2 +- website/docs/r/mariadb_server.html.markdown | 2 +- ...mariadb_virtual_network_rule.html.markdown | 2 +- .../r/marketplace_agreement.html.markdown | 2 +- website/docs/r/media_asset.html.markdown | 2 +- .../docs/r/media_asset_filter.html.markdown | 2 +- .../r/media_content_key_policy.html.markdown | 2 +- website/docs/r/media_job.html.markdown | 2 +- website/docs/r/media_live_event.html.markdown | 2 +- .../docs/r/media_live_output.html.markdown | 2 +- .../r/media_services_account.html.markdown | 2 +- .../r/media_streaming_endpoint.html.markdown | 2 +- .../r/media_streaming_locator.html.markdown | 2 +- .../r/media_streaming_policy.html.markdown | 2 +- website/docs/r/media_transform.html.markdown | 2 +- ...nitor_aad_diagnostic_setting.html.markdown | 2 +- .../docs/r/monitor_action_group.html.markdown | 2 +- ...tor_action_rule_action_group.html.markdown | 2 +- ...itor_action_rule_suppression.html.markdown | 2 +- .../monitor_activity_log_alert.html.markdown | 2 +- .../r/monitor_autoscale_setting.html.markdown | 2 +- ...tor_data_collection_endpoint.html.markdown | 83 + ...monitor_data_collection_rule.html.markdown | 244 + .../monitor_diagnostic_setting.html.markdown | 8 +- .../docs/r/monitor_log_profile.html.markdown | 2 +- .../docs/r/monitor_metric_alert.html.markdown | 2 +- .../monitor_private_link_scope.html.markdown | 2 +- ..._private_link_scoped_service.html.markdown | 2 +- ..._scheduled_query_rules_alert.html.markdown | 11 +- ...heduled_query_rules_alert_v2.html.markdown | 204 + ...or_scheduled_query_rules_log.html.markdown | 6 +- ...or_smart_detector_alert_rule.html.markdown | 2 +- website/docs/r/mssql_database.html.markdown | 2 +- ...ase_extended_auditing_policy.html.markdown | 2 +- ...ity_assessment_rule_baseline.html.markdown | 2 +- .../docs/r/mssql_elasticpool.html.markdown | 4 +- .../docs/r/mssql_failover_group.html.markdown | 2 +- .../docs/r/mssql_firewall_rule.html.markdown | 2 +- website/docs/r/mssql_job_agent.html.markdown | 2 +- .../docs/r/mssql_job_credential.html.markdown | 2 +- .../r/mssql_managed_instance.html.markdown | 6 +- ...tive_directory_administrator.html.markdown | 2 +- ...aged_instance_failover_group.html.markdown | 2 +- ...nce_vulnerability_assessment.html.markdown | 2 +- ...mssql_outbound_firewall_rule.html.markdown | 2 +- website/docs/r/mssql_server.html.markdown | 13 +- .../r/mssql_server_dns_alias.html.markdown | 2 +- ...ver_extended_auditing_policy.html.markdown | 2 +- ...server_security_alert_policy.html.markdown | 2 +- ..._transparent_data_encryption.html.markdown | 2 +- ...ver_vulnerability_assessment.html.markdown | 2 +- .../r/mssql_virtual_machine.html.markdown | 2 +- .../mssql_virtual_network_rule.html.markdown | 2 +- ...tive_directory_administrator.html.markdown | 2 +- .../docs/r/mysql_configuration.html.markdown | 2 +- website/docs/r/mysql_database.html.markdown | 2 +- .../docs/r/mysql_firewall_rule.html.markdown | 2 +- .../r/mysql_flexible_database.html.markdown | 2 +- .../r/mysql_flexible_server.html.markdown | 2 +- ...lexible_server_configuration.html.markdown | 2 +- ...lexible_server_firewall_rule.html.markdown | 2 +- website/docs/r/mysql_server.html.markdown | 2 +- website/docs/r/mysql_server_key.html.markdown | 2 +- .../mysql_virtual_network_rule.html.markdown | 2 +- website/docs/r/nat_gateway.html.markdown | 2 +- ...ateway_public_ip_association.html.markdown | 2 +- ...public_ip_prefix_association.html.markdown | 2 +- website/docs/r/netapp_account.html.markdown | 2 +- website/docs/r/netapp_pool.html.markdown | 2 +- website/docs/r/netapp_snapshot.html.markdown | 2 +- .../r/netapp_snapshot_policy.html.markdown | 2 +- website/docs/r/netapp_volume.html.markdown | 2 +- .../network_connection_monitor.html.markdown | 2 +- ...network_ddos_protection_plan.html.markdown | 2 +- .../docs/r/network_interface.html.markdown | 8 +- ...end_address_pool_association.html.markdown | 3 +- ...n_security_group_association.html.markdown | 2 +- ...end_address_pool_association.html.markdown | 2 +- ...terface_nat_rule_association.html.markdown | 2 +- ...e_security_group_association.html.markdown | 2 +- .../r/network_packet_capture.html.markdown | 2 +- website/docs/r/network_profile.html.markdown | 2 +- .../r/network_security_group.html.markdown | 2 +- .../r/network_security_rule.html.markdown | 2 +- website/docs/r/network_watcher.html.markdown | 2 +- .../r/network_watcher_flow_log.html.markdown | 2 +- website/docs/r/notification_hub.html.markdown | 2 +- ...ation_hub_authorization_rule.html.markdown | 2 +- .../notification_hub_namespace.html.markdown | 2 +- ...ed_virtual_machine_scale_set.html.markdown | 2 +- .../r/point_to_site_vpn_gateway.html.markdown | 2 +- .../docs/r/policy_definition.html.markdown | 7 +- .../r/policy_set_definition.html.markdown | 2 +- ...ine_configuration_assignment.html.markdown | 2 +- website/docs/r/portal_dashboard.html.markdown | 2 +- .../portal_tenant_configuration.html.markdown | 2 +- ...tive_directory_administrator.html.markdown | 4 +- .../r/postgresql_configuration.html.markdown | 2 +- .../docs/r/postgresql_database.html.markdown | 2 +- .../r/postgresql_firewall_rule.html.markdown | 2 +- .../postgresql_flexible_server.html.markdown | 6 +- ...lexible_server_configuration.html.markdown | 2 +- ...sql_flexible_server_database.html.markdown | 2 +- ...lexible_server_firewall_rule.html.markdown | 2 +- .../docs/r/postgresql_server.html.markdown | 6 +- .../r/postgresql_server_key.html.markdown | 2 +- ...tgresql_virtual_network_rule.html.markdown | 2 +- website/docs/r/powerbi_embedded.html.markdown | 2 +- .../docs/r/private_dns_a_record.html.markdown | 2 +- .../r/private_dns_aaaa_record.html.markdown | 2 +- .../r/private_dns_cname_record.html.markdown | 2 +- .../r/private_dns_mx_record.html.markdown | 2 +- .../r/private_dns_ptr_record.html.markdown | 2 +- .../r/private_dns_srv_record.html.markdown | 2 +- .../r/private_dns_txt_record.html.markdown | 2 +- website/docs/r/private_dns_zone.html.markdown | 2 +- ...ns_zone_virtual_network_link.html.markdown | 2 +- website/docs/r/private_endpoint.html.markdown | 24 +- .../docs/r/private_link_service.html.markdown | 2 +- .../r/proximity_placement_group.html.markdown | 2 +- website/docs/r/public_ip.html.markdown | 2 +- website/docs/r/public_ip_prefix.html.markdown | 2 +- website/docs/r/purview_account.html.markdown | 2 +- .../r/recovery_services_vault.html.markdown | 2 +- website/docs/r/redis_cache.html.markdown | 6 +- .../r/redis_enterprise_cluster.html.markdown | 2 +- .../r/redis_enterprise_database.html.markdown | 2 +- .../docs/r/redis_firewall_rule.html.markdown | 2 +- .../docs/r/redis_linked_server.html.markdown | 2 +- .../r/relay_hybrid_connection.html.markdown | 2 +- ...onnection_authorization_rule.html.markdown | 2 +- website/docs/r/relay_namespace.html.markdown | 2 +- ...namespace_authorization_rule.html.markdown | 2 +- website/docs/r/resource_group.html.markdown | 2 +- ...group_cost_management_export.html.markdown | 2 +- ...urce_group_policy_assignment.html.markdown | 2 +- ...ource_group_policy_exemption.html.markdown | 2 +- ...rce_group_policy_remediation.html.markdown | 8 +- ...ce_group_template_deployment.html.markdown | 2 +- .../resource_policy_assignment.html.markdown | 2 +- .../r/resource_policy_exemption.html.markdown | 2 +- .../resource_policy_remediation.html.markdown | 8 +- ...source_provider_registration.html.markdown | 2 +- website/docs/r/role_assignment.html.markdown | 2 +- website/docs/r/role_definition.html.markdown | 2 +- website/docs/r/route.html.markdown | 2 +- website/docs/r/route_filter.html.markdown | 2 +- website/docs/r/route_server.html.markdown | 97 + .../route_server_bgp_connection.html.markdown | 56 + website/docs/r/route_table.html.markdown | 2 +- website/docs/r/search_service.html.markdown | 8 +- ..._shared_private_link_service.html.markdown | 81 + .../security_center_assessment.html.markdown | 2 +- ...ity_center_assessment_policy.html.markdown | 2 +- ...ity_center_auto_provisioning.html.markdown | 2 +- .../security_center_automation.html.markdown | 2 +- .../r/security_center_contact.html.markdown | 2 +- ...y_assessment_virtual_machine.html.markdown | 2 +- .../r/security_center_setting.html.markdown | 2 +- ..._center_subscription_pricing.html.markdown | 2 +- .../r/security_center_workspace.html.markdown | 2 +- .../sentinel_alert_rule_fusion.html.markdown | 2 +- ...rt_rule_ms_security_incident.html.markdown | 2 +- .../r/sentinel_alert_rule_nrt.html.markdown | 172 + ...entinel_alert_rule_scheduled.html.markdown | 2 +- .../r/sentinel_automation_rule.html.markdown | 2 +- ...ta_connector_aws_cloud_trail.html.markdown | 2 +- ...ntinel_data_connector_aws_s3.html.markdown | 2 +- ...ector_azure_active_directory.html.markdown | 2 +- ...e_advanced_threat_protection.html.markdown | 2 +- ...nector_azure_security_center.html.markdown | 2 +- ...microsoft_cloud_app_security.html.markdown | 2 +- ...r_advanced_threat_protection.html.markdown | 2 +- ...el_data_connector_office_365.html.markdown | 2 +- ...onnector_threat_intelligence.html.markdown | 2 +- .../docs/r/sentinel_watchlist.html.markdown | 2 +- .../r/sentinel_watchlist_item.html.markdown | 2 +- ...ervice_connector_app_service.html.markdown | 133 + ...rvice_connector_spring_cloud.html.markdown | 138 + .../r/service_fabric_cluster.html.markdown | 2 +- ...rvice_fabric_managed_cluster.html.markdown | 2 +- website/docs/r/service_plan.html.markdown | 4 +- .../docs/r/servicebus_namespace.html.markdown | 10 +- ...namespace_authorization_rule.html.markdown | 2 +- ...ace_disaster_recovery_config.html.markdown | 2 +- ...s_namespace_network_rule_set.html.markdown | 4 +- website/docs/r/servicebus_queue.html.markdown | 4 +- ...bus_queue_authorization_rule.html.markdown | 2 +- .../r/servicebus_subscription.html.markdown | 22 +- ...servicebus_subscription_rule.html.markdown | 4 +- website/docs/r/servicebus_topic.html.markdown | 4 +- ...bus_topic_authorization_rule.html.markdown | 2 +- website/docs/r/shared_image.html.markdown | 4 +- .../docs/r/shared_image_gallery.html.markdown | 2 +- .../docs/r/shared_image_version.html.markdown | 16 +- website/docs/r/signalr_service.html.markdown | 2 +- .../signalr_service_network_acl.html.markdown | 2 +- .../signalr_shared_private_link.html.markdown | 103 + .../docs/r/site_recovery_fabric.html.markdown | 2 +- ...ite_recovery_network_mapping.html.markdown | 2 +- ...ecovery_protection_container.html.markdown | 2 +- ...protection_container_mapping.html.markdown | 2 +- .../site_recovery_replicated_vm.html.markdown | 28 +- ..._recovery_replication_policy.html.markdown | 2 +- website/docs/r/snapshot.html.markdown | 2 +- .../docs/r/source_control_token.html.markdown | 2 +- .../r/spatial_anchors_account.html.markdown | 2 +- ...ring_cloud_active_deployment.html.markdown | 2 +- .../r/spring_cloud_api_portal.html.markdown | 4 +- ...oud_api_portal_custom_domain.html.markdown | 4 +- website/docs/r/spring_cloud_app.html.markdown | 4 +- ...oud_app_cosmosdb_association.html.markdown | 2 +- ..._cloud_app_mysql_association.html.markdown | 2 +- ..._cloud_app_redis_association.html.markdown | 2 +- ...pring_cloud_build_deployment.html.markdown | 4 +- ...ing_cloud_build_pack_binding.html.markdown | 4 +- .../docs/r/spring_cloud_builder.html.markdown | 4 +- .../r/spring_cloud_certificate.html.markdown | 2 +- ..._cloud_configuration_service.html.markdown | 4 +- ...g_cloud_container_deployment.html.markdown | 2 +- .../spring_cloud_custom_domain.html.markdown | 2 +- .../docs/r/spring_cloud_gateway.html.markdown | 4 +- ..._cloud_gateway_custom_domain.html.markdown | 4 +- ...g_cloud_gateway_route_config.html.markdown | 12 +- ...spring_cloud_java_deployment.html.markdown | 4 +- .../docs/r/spring_cloud_service.html.markdown | 13 +- .../docs/r/spring_cloud_storage.html.markdown | 2 +- ...tive_directory_administrator.html.markdown | 2 +- website/docs/r/sql_database.html.markdown | 2 +- website/docs/r/sql_elasticpool.html.markdown | 2 +- .../docs/r/sql_failover_group.html.markdown | 2 +- .../docs/r/sql_firewall_rule.html.markdown | 2 +- .../docs/r/sql_managed_instance.html.markdown | 2 +- ...tive_directory_administrator.html.markdown | 2 +- ...aged_instance_failover_group.html.markdown | 2 +- website/docs/r/sql_server.html.markdown | 2 +- .../r/sql_virtual_network_rule.html.markdown | 2 +- website/docs/r/ssh_public_key.html.markdown | 2 +- .../docs/r/stack_hci_cluster.html.markdown | 2 +- website/docs/r/static_site.html.markdown | 16 +- .../r/static_site_custom_domain.html.markdown | 2 +- website/docs/r/storage_account.html.markdown | 8 +- ...account_customer_managed_key.html.markdown | 2 +- ...torage_account_network_rules.html.markdown | 2 +- website/docs/r/storage_blob.html.markdown | 2 +- ...torage_blob_inventory_policy.html.markdown | 2 +- .../docs/r/storage_container.html.markdown | 2 +- ...ge_data_lake_gen2_filesystem.html.markdown | 2 +- .../storage_data_lake_gen2_path.html.markdown | 2 +- .../r/storage_encryption_scope.html.markdown | 2 +- .../r/storage_management_policy.html.markdown | 4 +- .../storage_object_replication.html.markdown | 2 +- website/docs/r/storage_queue.html.markdown | 2 +- website/docs/r/storage_share.html.markdown | 2 +- .../r/storage_share_directory.html.markdown | 2 +- .../docs/r/storage_share_file.html.markdown | 2 +- website/docs/r/storage_sync.html.markdown | 2 +- .../storage_sync_cloud_endpoint.html.markdown | 2 +- .../docs/r/storage_sync_group.html.markdown | 2 +- website/docs/r/storage_table.html.markdown | 2 +- .../docs/r/storage_table_entity.html.markdown | 2 +- .../r/stream_analytics_cluster.html.markdown | 2 +- ...tics_function_javascript_uda.html.markdown | 2 +- ...tics_function_javascript_udf.html.markdown | 2 +- .../docs/r/stream_analytics_job.html.markdown | 2 +- ...tream_analytics_job_schedule.html.markdown | 2 +- ...ics_managed_private_endpoint.html.markdown | 2 +- ...stream_analytics_output_blob.html.markdown | 2 +- ...am_analytics_output_cosmosdb.html.markdown | 4 +- ...am_analytics_output_eventhub.html.markdown | 4 +- ...am_analytics_output_function.html.markdown | 2 +- ...tream_analytics_output_mssql.html.markdown | 4 +- ...eam_analytics_output_powerbi.html.markdown | 6 +- ...tics_output_servicebus_queue.html.markdown | 2 +- ...tics_output_servicebus_topic.html.markdown | 4 +- ...eam_analytics_output_synapse.html.markdown | 2 +- ...tream_analytics_output_table.html.markdown | 2 +- ...alytics_reference_input_blob.html.markdown | 4 +- ...lytics_reference_input_mssql.html.markdown | 2 +- ..._analytics_stream_input_blob.html.markdown | 2 +- ...lytics_stream_input_eventhub.html.markdown | 4 +- ...nalytics_stream_input_iothub.html.markdown | 2 +- website/docs/r/subnet.html.markdown | 12 +- ...bnet_nat_gateway_association.html.markdown | 2 +- ...k_security_group_association.html.markdown | 2 +- ...bnet_route_table_association.html.markdown | 2 +- ...vice_endpoint_storage_policy.html.markdown | 2 +- website/docs/r/subscription.html.markdown | 2 +- ...ption_cost_management_export.html.markdown | 2 +- ...bscription_policy_assignment.html.markdown | 2 +- ...ubscription_policy_exemption.html.markdown | 2 +- ...scription_policy_remediation.html.markdown | 8 +- ...cription_template_deployment.html.markdown | 2 +- .../r/synapse_firewall_rule.html.markdown | 2 +- ...se_integration_runtime_azure.html.markdown | 2 +- ...egration_runtime_self_hosted.html.markdown | 2 +- .../r/synapse_linked_service.html.markdown | 2 +- ...pse_managed_private_endpoint.html.markdown | 2 +- .../r/synapse_private_link_hub.html.markdown | 2 +- .../r/synapse_role_assignment.html.markdown | 2 +- .../docs/r/synapse_spark_pool.html.markdown | 2 +- website/docs/r/synapse_sql_pool.html.markdown | 2 +- ...ool_extended_auditing_policy.html.markdown | 2 +- ...l_pool_security_alert_policy.html.markdown | 2 +- ...ool_vulnerability_assessment.html.markdown | 2 +- ...rability_assessment_baseline.html.markdown | 2 +- ...sql_pool_workload_classifier.html.markdown | 2 +- ...apse_sql_pool_workload_group.html.markdown | 2 +- .../docs/r/synapse_workspace.html.markdown | 2 +- .../synapse_workspace_aad_admin.html.markdown | 2 +- ...ace_extended_auditing_policy.html.markdown | 2 +- .../r/synapse_workspace_key.html.markdown | 2 +- ...kspace_security_alert_policy.html.markdown | 2 +- ...apse_workspace_sql_aad_admin.html.markdown | 2 +- ...ace_vulnerability_assessment.html.markdown | 2 +- .../docs/r/template_deployment.html.markdown | 2 +- .../tenant_template_deployment.html.markdown | 2 +- ...affic_manager_azure_endpoint.html.markdown | 2 +- ...ic_manager_external_endpoint.html.markdown | 2 +- ...ffic_manager_nested_endpoint.html.markdown | 2 +- .../r/traffic_manager_profile.html.markdown | 2 +- .../r/user_assigned_identity.html.markdown | 4 +- website/docs/r/video_analyzer.html.markdown | 2 +- .../video_analyzer_edge_module.html.markdown | 2 +- .../virtual_desktop_application.html.markdown | 2 +- ...al_desktop_application_group.html.markdown | 2 +- .../r/virtual_desktop_host_pool.html.markdown | 2 +- ..._host_pool_registration_info.html.markdown | 2 +- ...virtual_desktop_scaling_plan.html.markdown | 2 +- .../r/virtual_desktop_workspace.html.markdown | 2 +- ...pplication_group_association.html.markdown | 2 +- website/docs/r/virtual_hub.html.markdown | 2 +- .../virtual_hub_bgp_connection.html.markdown | 2 +- .../r/virtual_hub_connection.html.markdown | 2 +- website/docs/r/virtual_hub_ip.html.markdown | 2 +- .../r/virtual_hub_route_table.html.markdown | 2 +- ...irtual_hub_route_table_route.html.markdown | 2 +- ...ub_security_partner_provider.html.markdown | 2 +- website/docs/r/virtual_machine.html.markdown | 2 +- ...machine_data_disk_attachment.html.markdown | 2 +- .../r/virtual_machine_extension.html.markdown | 4 +- .../r/virtual_machine_scale_set.html.markdown | 4 +- ..._machine_scale_set_extension.html.markdown | 2 +- website/docs/r/virtual_network.html.markdown | 2 +- .../virtual_network_dns_servers.html.markdown | 2 +- .../r/virtual_network_gateway.html.markdown | 2 +- ...l_network_gateway_connection.html.markdown | 2 +- ...ual_network_gateway_nat_rule.html.markdown | 2 +- .../r/virtual_network_peering.html.markdown | 2 +- website/docs/r/virtual_wan.html.markdown | 2 +- website/docs/r/vmware_cluster.html.markdown | 2 +- ..._express_route_authorization.html.markdown | 2 +- .../docs/r/vmware_private_cloud.html.markdown | 2 +- website/docs/r/vpn_gateway.html.markdown | 2 +- .../r/vpn_gateway_connection.html.markdown | 2 +- .../docs/r/vpn_gateway_nat_rule.html.markdown | 2 +- .../r/vpn_server_configuration.html.markdown | 2 +- ...r_configuration_policy_group.html.markdown | 2 +- website/docs/r/vpn_site.html.markdown | 2 +- .../docs/r/web_app_active_slot.html.markdown | 2 +- .../r/web_app_hybrid_connection.html.markdown | 2 +- ..._application_firewall_policy.html.markdown | 22 +- website/docs/r/web_pubsub.html.markdown | 4 +- website/docs/r/web_pubsub_hub.html.markdown | 2 +- .../r/web_pubsub_network_acl.html.markdown | 2 +- ...b_pubsub_shared_private_link.html.markdown | 107 + .../docs/r/windows_function_app.html.markdown | 17 +- .../r/windows_function_app_slot.html.markdown | 8 +- .../r/windows_virtual_machine.html.markdown | 4 +- ...ws_virtual_machine_scale_set.html.markdown | 6 +- website/docs/r/windows_web_app.html.markdown | 16 +- .../docs/r/windows_web_app_slot.html.markdown | 12 +- 4756 files changed, 191050 insertions(+), 152640 deletions(-) create mode 100644 .github/workflows/pull-request-new-commit.yaml create mode 100644 .github/workflows/pull-request-reviewed-workflow.yaml create mode 100644 .github/workflows/pull-request-reviewed.yaml create mode 100644 examples/private-endpoint/private-link-scope/README.md create mode 100644 examples/private-endpoint/private-link-scope/main.tf create mode 100644 examples/private-endpoint/private-link-scope/variables.tf create mode 100644 internal/services/apimanagement/api_management_gateway_certificate_authority_resource.go create mode 100644 internal/services/apimanagement/api_management_gateway_certificate_authority_resource_test.go create mode 100644 internal/services/apimanagement/api_management_product_tag_resource.go create mode 100644 internal/services/apimanagement/api_management_product_tag_resource_test.go create mode 100644 internal/services/apimanagement/parse/gateway_certificate_authority.go create mode 100644 internal/services/apimanagement/parse/gateway_certificate_authority_test.go create mode 100644 internal/services/apimanagement/parse/product_tag.go create mode 100644 internal/services/apimanagement/parse/product_tag_test.go create mode 100644 internal/services/apimanagement/validate/gateway_certificate_authority_id.go create mode 100644 internal/services/apimanagement/validate/gateway_certificate_authority_id_test.go create mode 100644 internal/services/apimanagement/validate/product_tag_id.go create mode 100644 internal/services/apimanagement/validate/product_tag_id_test.go create mode 100644 internal/services/applicationinsights/application_insights_workbook_resource.go create mode 100644 internal/services/applicationinsights/application_insights_workbook_resource_test.go create mode 100644 internal/services/applicationinsights/validate/workbook_name.go create mode 100644 internal/services/applicationinsights/validate/workbook_tags.go create mode 100644 internal/services/appservice/validate/web_app_name_test.go create mode 100644 internal/services/automation/automation_connection_type_resource.go create mode 100644 internal/services/automation/automation_connection_type_resource_test.go create mode 100644 internal/services/automation/automation_hybrid_runbook_worker_group.go create mode 100644 internal/services/automation/automation_hybrid_runbook_worker_group_test.go create mode 100644 internal/services/automation/parse/connection_type.go create mode 100644 internal/services/automation/parse/connection_type_test.go create mode 100644 internal/services/automation/transition.go create mode 100644 internal/services/automation/validate/connection_type_id.go create mode 100644 internal/services/automation/validate/connection_type_id_test.go create mode 100644 internal/services/automation/validate/connection_type_name.go create mode 100644 internal/services/cdn/cdn_frontdoor_firewall_policy_resource.go create mode 100644 internal/services/cdn/cdn_frontdoor_firewall_policy_resource_test.go create mode 100644 internal/services/cdn/cdn_frontdoor_origin_group_data_source.go create mode 100644 internal/services/cdn/cdn_frontdoor_origin_group_data_source_test.go create mode 100644 internal/services/cdn/cdn_frontdoor_origin_group_resource.go create mode 100644 internal/services/cdn/cdn_frontdoor_origin_group_resource_test.go create mode 100644 internal/services/cdn/cdn_frontdoor_origin_resource.go create mode 100644 internal/services/cdn/cdn_frontdoor_origin_resource_test.go create mode 100644 internal/services/cdn/cdn_frontdoor_security_policy_resource.go create mode 100644 internal/services/cdn/cdn_frontdoor_security_policy_resource_test.go create mode 100644 internal/services/cdn/frontdoorsecurityparams/cdn_frontdoor_security_params.go create mode 100644 internal/services/cdn/parse/front_door_custom_domain.go create mode 100644 internal/services/cdn/parse/front_door_custom_domain_test.go create mode 100644 internal/services/cdn/parse/front_door_firewall_policy.go create mode 100644 internal/services/cdn/parse/front_door_firewall_policy_test.go create mode 100644 internal/services/cdn/parse/front_door_origin.go create mode 100644 internal/services/cdn/parse/front_door_origin_group.go create mode 100644 internal/services/cdn/parse/front_door_origin_group_test.go create mode 100644 internal/services/cdn/parse/front_door_origin_test.go create mode 100644 internal/services/cdn/parse/front_door_security_policy.go create mode 100644 internal/services/cdn/parse/front_door_security_policy_test.go create mode 100644 internal/services/cdn/parse/frontdoor_custom_domain.go create mode 100644 internal/services/cdn/parse/frontdoor_custom_domain_test.go create mode 100644 internal/services/cdn/validate/front_door_custom_domain_id.go create mode 100644 internal/services/cdn/validate/front_door_custom_domain_id_test.go create mode 100644 internal/services/cdn/validate/front_door_firewall_policy_id.go create mode 100644 internal/services/cdn/validate/front_door_firewall_policy_id_test.go create mode 100644 internal/services/cdn/validate/front_door_firewall_policy_name.go create mode 100644 internal/services/cdn/validate/front_door_firewall_policy_name_test.go create mode 100644 internal/services/cdn/validate/front_door_origin_group_id.go create mode 100644 internal/services/cdn/validate/front_door_origin_group_id_test.go create mode 100644 internal/services/cdn/validate/front_door_origin_group_name.go create mode 100644 internal/services/cdn/validate/front_door_origin_group_name_test.go create mode 100644 internal/services/cdn/validate/front_door_origin_id.go create mode 100644 internal/services/cdn/validate/front_door_origin_id_test.go create mode 100644 internal/services/cdn/validate/front_door_origin_name.go create mode 100644 internal/services/cdn/validate/front_door_origin_name_test.go create mode 100644 internal/services/cdn/validate/front_door_security_policy_domain_id.go create mode 100644 internal/services/cdn/validate/front_door_security_policy_id.go create mode 100644 internal/services/cdn/validate/front_door_security_policy_id_test.go create mode 100644 internal/services/cdn/validate/front_door_validation_helpers.go delete mode 100644 internal/services/compute/parse/dedicated_host.go delete mode 100644 internal/services/compute/parse/dedicated_host_group.go delete mode 100644 internal/services/compute/parse/dedicated_host_group_test.go delete mode 100644 internal/services/compute/parse/dedicated_host_test.go delete mode 100644 internal/services/compute/parse/proximity_placement_group.go delete mode 100644 internal/services/compute/parse/proximity_placement_group_test.go delete mode 100644 internal/services/compute/validate/dedicated_host_group_id.go delete mode 100644 internal/services/compute/validate/dedicated_host_group_id_test.go delete mode 100644 internal/services/compute/validate/dedicated_host_id.go delete mode 100644 internal/services/compute/validate/dedicated_host_id_test.go delete mode 100644 internal/services/compute/validate/proximity_placement_group_id.go delete mode 100644 internal/services/compute/validate/proximity_placement_group_id_test.go delete mode 100644 internal/services/consumption/parse/consumption_budget.go delete mode 100644 internal/services/consumption/parse/consumption_budget_management_group.go delete mode 100644 internal/services/consumption/parse/consumption_budget_management_group_test.go delete mode 100644 internal/services/consumption/parse/consumption_budget_resource_group.go delete mode 100644 internal/services/consumption/parse/consumption_budget_resource_group_test.go delete mode 100644 internal/services/consumption/parse/consumption_budget_subscription.go delete mode 100644 internal/services/consumption/parse/consumption_budget_subscription_test.go delete mode 100644 internal/services/consumption/parse/consumption_budget_test.go delete mode 100644 internal/services/consumption/resourceids.go delete mode 100644 internal/services/consumption/validate/consumption_budget_management_group_id.go delete mode 100644 internal/services/consumption/validate/consumption_budget_management_group_id_test.go delete mode 100644 internal/services/consumption/validate/consumption_budget_resource_group_id.go delete mode 100644 internal/services/consumption/validate/consumption_budget_resource_group_id_test.go delete mode 100644 internal/services/consumption/validate/consumption_budget_subscription_id.go delete mode 100644 internal/services/consumption/validate/consumption_budget_subscription_id_test.go create mode 100644 internal/services/containers/container_registry_task_schedule_run_now_resource.go create mode 100644 internal/services/containers/container_registry_task_schedule_run_now_resource_test.go create mode 100644 internal/services/containers/parse/container_registry_task_schedule.go create mode 100644 internal/services/containers/parse/container_registry_task_schedule_test.go create mode 100644 internal/services/containers/validate/container_registry_task_schedule_id.go create mode 100644 internal/services/containers/validate/container_registry_task_schedule_id_test.go create mode 100644 internal/services/cosmos/cosmosdb_sql_dedicated_gateway_resource.go create mode 100644 internal/services/cosmos/cosmosdb_sql_dedicated_gateway_resource_test.go create mode 100644 internal/services/dashboard/client/client.go create mode 100644 internal/services/dashboard/dashboard_grafana_resource.go create mode 100644 internal/services/dashboard/dashboard_grafana_resource_test.go create mode 100644 internal/services/dashboard/registration.go create mode 100644 internal/services/datadog/client/client.go create mode 100644 internal/services/datadog/datadog_monitors_resource.go create mode 100644 internal/services/datadog/datadog_monitors_resource_test.go create mode 100644 internal/services/datadog/parse/datadog_monitor.go create mode 100644 internal/services/datadog/parse/datadog_monitor_test.go create mode 100644 internal/services/datadog/registration.go create mode 100644 internal/services/datadog/resourceids.go create mode 100644 internal/services/datadog/validate/datadog_email_address.go create mode 100644 internal/services/datadog/validate/datadog_email_address_test.go create mode 100644 internal/services/datadog/validate/datadog_monitor_id.go create mode 100644 internal/services/datadog/validate/datadog_monitor_id_test.go create mode 100644 internal/services/datadog/validate/datadog_monitor_name.go create mode 100644 internal/services/datadog/validate/datadog_monitor_name_test.go create mode 100644 internal/services/datadog/validate/datadog_phone_number.go create mode 100644 internal/services/datadog/validate/datadog_phone_number_test.go create mode 100644 internal/services/datadog/validate/datadog_users_name.go create mode 100644 internal/services/datadog/validate/datadog_users_name_test.go create mode 100644 internal/services/datafactory/data_factory_flowlet_data_flow_resource.go create mode 100644 internal/services/datafactory/data_factory_flowlet_data_flow_resource_test.go delete mode 100644 internal/services/dataprotection/legacysdk/dataprotection/backupinstances.go delete mode 100644 internal/services/dataprotection/legacysdk/dataprotection/backuppolicies.go delete mode 100644 internal/services/dataprotection/legacysdk/dataprotection/backupvaultoperationresults.go delete mode 100644 internal/services/dataprotection/legacysdk/dataprotection/backupvaults.go delete mode 100644 internal/services/dataprotection/legacysdk/dataprotection/client.go delete mode 100644 internal/services/dataprotection/legacysdk/dataprotection/dataprotection.go delete mode 100644 internal/services/dataprotection/legacysdk/dataprotection/enums.go delete mode 100644 internal/services/dataprotection/legacysdk/dataprotection/exportjobs.go delete mode 100644 internal/services/dataprotection/legacysdk/dataprotection/exportjobsoperationresult.go delete mode 100644 internal/services/dataprotection/legacysdk/dataprotection/jobs.go delete mode 100644 internal/services/dataprotection/legacysdk/dataprotection/models.go delete mode 100644 internal/services/dataprotection/legacysdk/dataprotection/operationresult.go delete mode 100644 internal/services/dataprotection/legacysdk/dataprotection/operations.go delete mode 100644 internal/services/dataprotection/legacysdk/dataprotection/operationstatus.go delete mode 100644 internal/services/dataprotection/legacysdk/dataprotection/recoverypoints.go delete mode 100644 internal/services/dataprotection/legacysdk/dataprotection/resourceguards.go delete mode 100644 internal/services/dataprotection/legacysdk/dataprotection/restorabletimeranges.go delete mode 100644 internal/services/dataprotection/legacysdk/dataprotection/version.go delete mode 100644 internal/services/dataprotection/parse/backup_instance.go delete mode 100644 internal/services/dataprotection/parse/backup_instance_test.go delete mode 100644 internal/services/dataprotection/parse/backup_policy.go delete mode 100644 internal/services/dataprotection/parse/backup_policy_test.go delete mode 100644 internal/services/dataprotection/resourceids.go create mode 100644 internal/services/dataprotection/transition.go delete mode 100644 internal/services/dataprotection/validate/backup_instance_id.go delete mode 100644 internal/services/dataprotection/validate/backup_instance_id_test.go delete mode 100644 internal/services/dataprotection/validate/backup_policy_id.go delete mode 100644 internal/services/dataprotection/validate/backup_policy_id_test.go delete mode 100644 internal/services/dataprotection/validate/backup_vault_id.go delete mode 100644 internal/services/dataprotection/validate/backup_vault_id_test.go create mode 100644 internal/services/dns/dns_a_record_data_source.go create mode 100644 internal/services/dns/dns_a_record_data_source_test.go create mode 100644 internal/services/dns/dns_aaaa_record_data_source.go create mode 100644 internal/services/dns/dns_aaaa_record_data_source_test.go create mode 100644 internal/services/dns/dns_caa_record_data_source.go create mode 100644 internal/services/dns/dns_caa_record_data_source_test.go create mode 100644 internal/services/dns/dns_cname_record_data_source.go create mode 100644 internal/services/dns/dns_cname_record_data_source_test.go create mode 100644 internal/services/dns/dns_mx_record_data_source.go create mode 100644 internal/services/dns/dns_mx_record_data_source_test.go create mode 100644 internal/services/dns/dns_ns_record_data_source.go create mode 100644 internal/services/dns/dns_ns_record_data_source_test.go create mode 100644 internal/services/dns/dns_ptr_record_data_source.go create mode 100644 internal/services/dns/dns_ptr_record_data_source_test.go create mode 100644 internal/services/dns/dns_soa_record_data_source.go create mode 100644 internal/services/dns/dns_soa_record_data_source_test.go create mode 100644 internal/services/dns/dns_srv_record_data_source.go create mode 100644 internal/services/dns/dns_srv_record_data_source_test.go create mode 100644 internal/services/dns/dns_txt_record_data_source.go create mode 100644 internal/services/dns/dns_txt_record_data_source_test.go delete mode 100644 internal/services/dns/parse/a_record.go delete mode 100644 internal/services/dns/parse/a_record_test.go delete mode 100644 internal/services/dns/parse/aaaa_record.go delete mode 100644 internal/services/dns/parse/aaaa_record_test.go delete mode 100644 internal/services/dns/parse/caa_record.go delete mode 100644 internal/services/dns/parse/caa_record_test.go delete mode 100644 internal/services/dns/parse/cname_record.go delete mode 100644 internal/services/dns/parse/cname_record_test.go delete mode 100644 internal/services/dns/parse/dns_zone.go delete mode 100644 internal/services/dns/parse/dns_zone_test.go delete mode 100644 internal/services/dns/parse/mx_record.go delete mode 100644 internal/services/dns/parse/mx_record_test.go delete mode 100644 internal/services/dns/parse/ns_record.go delete mode 100644 internal/services/dns/parse/ns_record_test.go delete mode 100644 internal/services/dns/parse/ptr_record.go delete mode 100644 internal/services/dns/parse/ptr_record_test.go create mode 100644 internal/services/dns/parse/soa_record.go delete mode 100644 internal/services/dns/parse/srv_record.go delete mode 100644 internal/services/dns/parse/srv_record_test.go delete mode 100644 internal/services/dns/parse/txt_record.go delete mode 100644 internal/services/dns/parse/txt_record_test.go delete mode 100644 internal/services/dns/resourceids.go delete mode 100644 internal/services/dns/validate/a_record_id.go delete mode 100644 internal/services/dns/validate/a_record_id_test.go delete mode 100644 internal/services/dns/validate/aaaa_record_id.go delete mode 100644 internal/services/dns/validate/aaaa_record_id_test.go delete mode 100644 internal/services/dns/validate/caa_record_id.go delete mode 100644 internal/services/dns/validate/caa_record_id_test.go delete mode 100644 internal/services/dns/validate/cname_record_id.go delete mode 100644 internal/services/dns/validate/cname_record_id_test.go delete mode 100644 internal/services/dns/validate/dns_zone_id.go delete mode 100644 internal/services/dns/validate/dns_zone_id_test.go delete mode 100644 internal/services/dns/validate/mx_record_id.go delete mode 100644 internal/services/dns/validate/mx_record_id_test.go delete mode 100644 internal/services/dns/validate/ns_record_id.go delete mode 100644 internal/services/dns/validate/ns_record_id_test.go delete mode 100644 internal/services/dns/validate/ptr_record_id.go delete mode 100644 internal/services/dns/validate/ptr_record_id_test.go delete mode 100644 internal/services/dns/validate/srv_record_id.go delete mode 100644 internal/services/dns/validate/srv_record_id_test.go delete mode 100644 internal/services/dns/validate/txt_record_id.go delete mode 100644 internal/services/dns/validate/txt_record_id_test.go create mode 100644 internal/services/eventhub/eventhub_namespace_schema_registry_resource.go create mode 100644 internal/services/eventhub/eventhub_namespace_schema_registry_resource_test.go create mode 100644 internal/services/healthcare/healthcare_medtech_service_data_source.go create mode 100644 internal/services/healthcare/healthcare_medtech_service_data_source_test.go create mode 100644 internal/services/healthcare/healthcare_medtech_service_fhir_destination_resource.go create mode 100644 internal/services/healthcare/healthcare_medtech_service_fhir_destination_resource_test.go create mode 100644 internal/services/healthcare/healthcare_medtech_service_resource.go create mode 100644 internal/services/healthcare/healthcare_medtech_service_resource_test.go create mode 100644 internal/services/healthcare/parse/med_tech_service.go create mode 100644 internal/services/healthcare/parse/med_tech_service_fhir_destination.go create mode 100644 internal/services/healthcare/parse/med_tech_service_fhir_destination_test.go create mode 100644 internal/services/healthcare/parse/med_tech_service_test.go create mode 100644 internal/services/healthcare/validate/med_tech_service_fhir_destination_id.go create mode 100644 internal/services/healthcare/validate/med_tech_service_fhir_destination_id_test.go create mode 100644 internal/services/healthcare/validate/med_tech_service_id.go create mode 100644 internal/services/healthcare/validate/med_tech_service_id_test.go create mode 100644 internal/services/healthcare/validate/medtech_service_name.go create mode 100644 internal/services/kusto/kusto_cluster_managed_private_endpoint_resource.go create mode 100644 internal/services/kusto/kusto_cluster_managed_private_endpoint_resource_test.go create mode 100644 internal/services/kusto/parse/managed_private_endpoints.go create mode 100644 internal/services/kusto/parse/managed_private_endpoints_test.go create mode 100644 internal/services/kusto/validate/managed_private_endpoints_id.go create mode 100644 internal/services/kusto/validate/managed_private_endpoints_id_test.go create mode 100644 internal/services/loganalytics/log_analytics_query_pack_query_resource.go create mode 100644 internal/services/loganalytics/log_analytics_query_pack_query_resource_test.go create mode 100644 internal/services/loganalytics/log_analytics_query_pack_resource.go create mode 100644 internal/services/loganalytics/log_analytics_query_pack_resource_test.go delete mode 100644 internal/services/loganalytics/parse/data_source.go delete mode 100644 internal/services/loganalytics/parse/data_source_test.go delete mode 100644 internal/services/loganalytics/parse/log_analytics_cluster.go delete mode 100644 internal/services/loganalytics/parse/log_analytics_cluster_test.go delete mode 100644 internal/services/loganalytics/parse/log_analytics_data_export.go delete mode 100644 internal/services/loganalytics/parse/log_analytics_data_export_test.go delete mode 100644 internal/services/loganalytics/parse/log_analytics_linked_service.go delete mode 100644 internal/services/loganalytics/parse/log_analytics_linked_service_test.go delete mode 100644 internal/services/loganalytics/parse/log_analytics_linked_storage_account.go delete mode 100644 internal/services/loganalytics/parse/log_analytics_linked_storage_account_test.go delete mode 100644 internal/services/loganalytics/parse/log_analytics_saved_search.go delete mode 100644 internal/services/loganalytics/parse/log_analytics_saved_search_test.go delete mode 100644 internal/services/loganalytics/parse/log_analytics_solution.go delete mode 100644 internal/services/loganalytics/parse/log_analytics_solution_test.go delete mode 100644 internal/services/loganalytics/parse/log_analytics_storage_insights.go delete mode 100644 internal/services/loganalytics/parse/log_analytics_storage_insights_test.go delete mode 100644 internal/services/loganalytics/parse/log_analytics_workspace.go delete mode 100644 internal/services/loganalytics/parse/log_analytics_workspace_test.go delete mode 100644 internal/services/loganalytics/resourceids.go create mode 100644 internal/services/loganalytics/transition.go delete mode 100644 internal/services/loganalytics/validate/data_source_id.go delete mode 100644 internal/services/loganalytics/validate/data_source_id_test.go delete mode 100644 internal/services/loganalytics/validate/log_analytics_cluster_id.go delete mode 100644 internal/services/loganalytics/validate/log_analytics_cluster_id_test.go delete mode 100644 internal/services/loganalytics/validate/log_analytics_data_export_id.go delete mode 100644 internal/services/loganalytics/validate/log_analytics_data_export_id_test.go delete mode 100644 internal/services/loganalytics/validate/log_analytics_linked_service_id.go delete mode 100644 internal/services/loganalytics/validate/log_analytics_linked_service_id_test.go delete mode 100644 internal/services/loganalytics/validate/log_analytics_linked_storage_account_id.go delete mode 100644 internal/services/loganalytics/validate/log_analytics_linked_storage_account_id_test.go delete mode 100644 internal/services/loganalytics/validate/log_analytics_saved_search_id.go delete mode 100644 internal/services/loganalytics/validate/log_analytics_saved_search_id_test.go delete mode 100644 internal/services/loganalytics/validate/log_analytics_solution_id.go delete mode 100644 internal/services/loganalytics/validate/log_analytics_solution_id_test.go delete mode 100644 internal/services/loganalytics/validate/log_analytics_storage_insights_id.go delete mode 100644 internal/services/loganalytics/validate/log_analytics_storage_insights_id_test.go delete mode 100644 internal/services/loganalytics/validate/log_analytics_workspace_id.go delete mode 100644 internal/services/loganalytics/validate/log_analytics_workspace_id_test.go create mode 100644 internal/services/logz/logz_sub_account_tag_rule_resource.go create mode 100644 internal/services/logz/logz_sub_account_tag_rule_resource_test.go create mode 100644 internal/services/logz/parse/logz_sub_account_tag_rule.go create mode 100644 internal/services/logz/parse/logz_sub_account_tag_rule_test.go create mode 100644 internal/services/logz/validate/logz_sub_account_tag_rule_id.go create mode 100644 internal/services/logz/validate/logz_sub_account_tag_rule_id_test.go delete mode 100644 internal/services/maintenance/parse/maintenance_configuration.go delete mode 100644 internal/services/maintenance/parse/maintenance_configuration_test.go delete mode 100644 internal/services/maintenance/parse/public_maintenance_configuration.go delete mode 100644 internal/services/maintenance/parse/public_maintenance_configuration_test.go delete mode 100644 internal/services/maintenance/resourceids.go create mode 100644 internal/services/maintenance/transition.go delete mode 100644 internal/services/maintenance/validate/maintenance_configuration_id.go delete mode 100644 internal/services/maintenance/validate/maintenance_configuration_id_test.go delete mode 100644 internal/services/maintenance/validate/public_maintenance_configuration_id.go delete mode 100644 internal/services/maintenance/validate/public_maintenance_configuration_id_test.go delete mode 100644 internal/services/mariadb/parse/maria_db_configuration.go delete mode 100644 internal/services/mariadb/parse/maria_db_configuration_test.go delete mode 100644 internal/services/mariadb/parse/maria_db_database.go delete mode 100644 internal/services/mariadb/parse/maria_db_database_test.go delete mode 100644 internal/services/mariadb/parse/maria_db_firewall_rule.go delete mode 100644 internal/services/mariadb/parse/maria_db_firewall_rule_test.go delete mode 100644 internal/services/mariadb/parse/maria_db_virtual_network_rule.go delete mode 100644 internal/services/mariadb/parse/maria_db_virtual_network_rule_test.go delete mode 100644 internal/services/mariadb/parse/server.go delete mode 100644 internal/services/mariadb/parse/server_test.go delete mode 100644 internal/services/mariadb/resourceids.go delete mode 100644 internal/services/mariadb/validate/maria_db_configuration_id.go delete mode 100644 internal/services/mariadb/validate/maria_db_configuration_id_test.go delete mode 100644 internal/services/mariadb/validate/maria_db_database_id.go delete mode 100644 internal/services/mariadb/validate/maria_db_database_id_test.go delete mode 100644 internal/services/mariadb/validate/maria_db_firewall_rule_id.go delete mode 100644 internal/services/mariadb/validate/maria_db_firewall_rule_id_test.go delete mode 100644 internal/services/mariadb/validate/maria_db_virtual_network_rule_id.go delete mode 100644 internal/services/mariadb/validate/maria_db_virtual_network_rule_id_test.go delete mode 100644 internal/services/mariadb/validate/server_id.go delete mode 100644 internal/services/mariadb/validate/server_id_test.go create mode 100644 internal/services/monitor/monitor_data_collection_endpoint_data_source.go create mode 100644 internal/services/monitor/monitor_data_collection_endpoint_data_source_test.go create mode 100644 internal/services/monitor/monitor_data_collection_endpoint_resource.go create mode 100644 internal/services/monitor/monitor_data_collection_endpoint_resource_test.go create mode 100644 internal/services/monitor/monitor_data_collection_rule_resource.go create mode 100644 internal/services/monitor/monitor_data_collection_rule_resource_test.go create mode 100644 internal/services/monitor/monitor_scheduled_query_rules_alert_v2_resource.go create mode 100644 internal/services/monitor/monitor_scheduled_query_rules_alert_v2_resource_test.go create mode 100644 internal/services/network/parse/virtual_machine_scale_set_public_ip_address.go create mode 100644 internal/services/network/parse/virtual_machine_scale_set_public_ip_address_test.go create mode 100644 internal/services/network/route_server_bgp_connection_resource.go create mode 100644 internal/services/network/route_server_bgp_connection_resource_test.go create mode 100644 internal/services/network/route_server_resource.go create mode 100644 internal/services/network/route_server_resource_test.go create mode 100644 internal/services/network/validate/route_server_name.go create mode 100644 internal/services/network/validate/virtual_machine_scale_set_public_ip_address_id.go create mode 100644 internal/services/network/validate/virtual_machine_scale_set_public_ip_address_id_test.go create mode 100644 internal/services/postgres/migration/postgresql_aad_administrator.go create mode 100644 internal/services/postgres/migration/postgresql_database.go create mode 100644 internal/services/postgres/migration/postgresql_server.go delete mode 100644 internal/services/postgres/parse/configuration.go delete mode 100644 internal/services/postgres/parse/configuration_test.go delete mode 100644 internal/services/postgres/parse/database.go delete mode 100644 internal/services/postgres/parse/database_test.go delete mode 100644 internal/services/postgres/parse/firewall_rule.go delete mode 100644 internal/services/postgres/parse/firewall_rule_test.go delete mode 100644 internal/services/postgres/parse/flexible_server.go delete mode 100644 internal/services/postgres/parse/flexible_server_configuration.go delete mode 100644 internal/services/postgres/parse/flexible_server_configuration_test.go delete mode 100644 internal/services/postgres/parse/flexible_server_database.go delete mode 100644 internal/services/postgres/parse/flexible_server_database_test.go delete mode 100644 internal/services/postgres/parse/flexible_server_firewall_rule.go delete mode 100644 internal/services/postgres/parse/flexible_server_firewall_rule_test.go delete mode 100644 internal/services/postgres/parse/flexible_server_test.go delete mode 100644 internal/services/postgres/parse/server.go delete mode 100644 internal/services/postgres/parse/server_key.go delete mode 100644 internal/services/postgres/parse/server_key_test.go delete mode 100644 internal/services/postgres/parse/server_test.go delete mode 100644 internal/services/postgres/parse/virtual_network_rule.go delete mode 100644 internal/services/postgres/parse/virtual_network_rule_test.go delete mode 100644 internal/services/postgres/validate/configuration_id.go delete mode 100644 internal/services/postgres/validate/configuration_id_test.go delete mode 100644 internal/services/postgres/validate/database_id.go delete mode 100644 internal/services/postgres/validate/database_id_test.go delete mode 100644 internal/services/postgres/validate/firewall_rule_id.go delete mode 100644 internal/services/postgres/validate/firewall_rule_id_test.go delete mode 100644 internal/services/postgres/validate/flexible_server_configuration_id.go delete mode 100644 internal/services/postgres/validate/flexible_server_configuration_id_test.go delete mode 100644 internal/services/postgres/validate/flexible_server_database_id.go delete mode 100644 internal/services/postgres/validate/flexible_server_database_id_test.go delete mode 100644 internal/services/postgres/validate/flexible_server_firewall_rule_id.go delete mode 100644 internal/services/postgres/validate/flexible_server_firewall_rule_id_test.go delete mode 100644 internal/services/postgres/validate/flexible_server_id.go delete mode 100644 internal/services/postgres/validate/flexible_server_id_test.go delete mode 100644 internal/services/postgres/validate/server_id.go delete mode 100644 internal/services/postgres/validate/server_id_test.go delete mode 100644 internal/services/postgres/validate/server_key_id.go delete mode 100644 internal/services/postgres/validate/server_key_id_test.go delete mode 100644 internal/services/postgres/validate/virtual_network_rule_id.go delete mode 100644 internal/services/postgres/validate/virtual_network_rule_id_test.go create mode 100644 internal/services/privatedns/private_dns_a_record_data_source.go create mode 100644 internal/services/privatedns/private_dns_a_record_data_source_test.go create mode 100644 internal/services/privatedns/private_dns_aaaa_record_data_source.go create mode 100644 internal/services/privatedns/private_dns_aaaa_record_data_source_test.go create mode 100644 internal/services/privatedns/private_dns_cname_record_data_source.go create mode 100644 internal/services/privatedns/private_dns_cname_record_data_source_test.go create mode 100644 internal/services/privatedns/private_dns_mx_record_data_source.go create mode 100644 internal/services/privatedns/private_dns_mx_record_data_source_test.go create mode 100644 internal/services/privatedns/private_dns_ptr_record_data_source.go create mode 100644 internal/services/privatedns/private_dns_ptr_record_data_source_test.go create mode 100644 internal/services/privatedns/private_dns_soa_record_data_source.go create mode 100644 internal/services/privatedns/private_dns_soa_record_data_source_test.go create mode 100644 internal/services/privatedns/private_dns_srv_record_data_source.go create mode 100644 internal/services/privatedns/private_dns_srv_record_data_source_test.go create mode 100644 internal/services/privatedns/private_dns_txt_record_data_source.go create mode 100644 internal/services/privatedns/private_dns_txt_record_data_source_test.go create mode 100644 internal/services/recoveryservices/backup_policy_vm_workload_resource.go create mode 100644 internal/services/recoveryservices/backup_policy_vm_workload_resource_test.go create mode 100644 internal/services/recoveryservices/validate/backup_policy_name.go create mode 100644 internal/services/recoveryservices/validate/backup_policy_name_test.go create mode 100644 internal/services/search/search_shared_private_link_service_resource.go create mode 100644 internal/services/search/search_shared_private_link_service_resource_test.go create mode 100644 internal/services/sentinel/sentinel_alert_rule_nrt_resource.go create mode 100644 internal/services/sentinel/sentinel_alert_rule_nrt_resource_test.go create mode 100644 internal/services/servicebus/migration/namespace_auth_rule.go create mode 100644 internal/services/serviceconnector/client/client.go create mode 100644 internal/services/serviceconnector/helper.go create mode 100644 internal/services/serviceconnector/registration.go create mode 100644 internal/services/serviceconnector/service_connector_app_service_resource.go create mode 100644 internal/services/serviceconnector/service_connector_app_service_resource_test.go create mode 100644 internal/services/serviceconnector/service_connector_spring_cloud_resource.go create mode 100644 internal/services/serviceconnector/service_connector_spring_cloud_resource_test.go create mode 100644 internal/services/signalr/migration/web_pubsub_hub_v0_to_v1.go create mode 100644 internal/services/signalr/migration/web_pubsub_v0_to_v1.go create mode 100644 internal/services/signalr/parse/web_pubsub_shared_private_link_resource.go create mode 100644 internal/services/signalr/parse/web_pubsub_shared_private_link_resource_test.go create mode 100644 internal/services/signalr/signalr_shared_private_link_resource.go create mode 100644 internal/services/signalr/signalr_shared_private_link_resource_test.go create mode 100644 internal/services/signalr/validate/web_pubsub_shared_private_link_resource_id.go create mode 100644 internal/services/signalr/validate/web_pubsub_shared_private_link_resource_id_test.go create mode 100644 internal/services/signalr/web_pubsub_private_linked_service_data_source.go create mode 100644 internal/services/signalr/web_pubsub_private_linked_service_data_source_test.go create mode 100644 internal/services/signalr/web_pubsub_shared_private_link_resource.go create mode 100644 internal/services/signalr/web_pubsub_shared_private_link_resource_test.go create mode 100644 internal/tf/pluginsdk/explicitly_null_config.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/consumption/mgmt/2019-10-01/consumption/_meta.json delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/consumption/mgmt/2019-10-01/consumption/aggregatedcost.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/consumption/mgmt/2019-10-01/consumption/balances.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/consumption/mgmt/2019-10-01/consumption/budgets.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/consumption/mgmt/2019-10-01/consumption/charges.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/consumption/mgmt/2019-10-01/consumption/client.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/consumption/mgmt/2019-10-01/consumption/credits.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/consumption/mgmt/2019-10-01/consumption/enums.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/consumption/mgmt/2019-10-01/consumption/events.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/consumption/mgmt/2019-10-01/consumption/forecasts.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/consumption/mgmt/2019-10-01/consumption/lots.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/consumption/mgmt/2019-10-01/consumption/marketplaces.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/consumption/mgmt/2019-10-01/consumption/models.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/consumption/mgmt/2019-10-01/consumption/operations.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/consumption/mgmt/2019-10-01/consumption/pricesheet.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/consumption/mgmt/2019-10-01/consumption/reservationrecommendationdetails.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/consumption/mgmt/2019-10-01/consumption/reservationrecommendations.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/consumption/mgmt/2019-10-01/consumption/reservationsdetails.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/consumption/mgmt/2019-10-01/consumption/reservationssummaries.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/consumption/mgmt/2019-10-01/consumption/reservationtransactions.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/consumption/mgmt/2019-10-01/consumption/tags.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/consumption/mgmt/2019-10-01/consumption/usagedetails.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/consumption/mgmt/2019-10-01/consumption/version.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/costmanagement/mgmt/2020-06-01/costmanagement/_meta.json delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/costmanagement/mgmt/2020-06-01/costmanagement/alerts.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/costmanagement/mgmt/2020-06-01/costmanagement/client.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/costmanagement/mgmt/2020-06-01/costmanagement/dimensions.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/costmanagement/mgmt/2020-06-01/costmanagement/enums.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/costmanagement/mgmt/2020-06-01/costmanagement/exports.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/costmanagement/mgmt/2020-06-01/costmanagement/forecast.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/costmanagement/mgmt/2020-06-01/costmanagement/models.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/costmanagement/mgmt/2020-06-01/costmanagement/operations.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/costmanagement/mgmt/2020-06-01/costmanagement/query.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/costmanagement/mgmt/2020-06-01/costmanagement/version.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/costmanagement/mgmt/2020-06-01/costmanagement/views.go rename vendor/github.com/Azure/azure-sdk-for-go/services/{consumption/mgmt/2019-10-01/consumption => datadog/mgmt/2021-03-01/datadog}/CHANGELOG.md (100%) create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/datadog/mgmt/2021-03-01/datadog/_meta.json create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/datadog/mgmt/2021-03-01/datadog/client.go create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/datadog/mgmt/2021-03-01/datadog/enums.go create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/datadog/mgmt/2021-03-01/datadog/marketplaceagreements.go create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/datadog/mgmt/2021-03-01/datadog/models.go create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/datadog/mgmt/2021-03-01/datadog/monitors.go create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/datadog/mgmt/2021-03-01/datadog/operations.go create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/datadog/mgmt/2021-03-01/datadog/singlesignonconfigurations.go create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/datadog/mgmt/2021-03-01/datadog/tagrules.go create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/datadog/mgmt/2021-03-01/datadog/version.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2018-05-01/dns/_meta.json delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2018-05-01/dns/client.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2018-05-01/dns/enums.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2018-05-01/dns/models.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2018-05-01/dns/recordsets.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2018-05-01/dns/resourcereference.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2018-05-01/dns/version.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2018-05-01/dns/zones.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/domainservices/mgmt/2020-01-01/aad/CHANGELOG.md delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/domainservices/mgmt/2020-01-01/aad/_meta.json delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/domainservices/mgmt/2020-01-01/aad/client.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/domainservices/mgmt/2020-01-01/aad/domainserviceoperations.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/domainservices/mgmt/2020-01-01/aad/domainservices.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/domainservices/mgmt/2020-01-01/aad/enums.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/domainservices/mgmt/2020-01-01/aad/models.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/domainservices/mgmt/2020-01-01/aad/oucontainer.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/domainservices/mgmt/2020-01-01/aad/oucontaineroperations.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/domainservices/mgmt/2020-01-01/aad/version.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/maintenance/mgmt/2021-05-01/maintenance/CHANGELOG.md delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/maintenance/mgmt/2021-05-01/maintenance/_meta.json delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/maintenance/mgmt/2021-05-01/maintenance/applyupdateforresourcegroup.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/maintenance/mgmt/2021-05-01/maintenance/applyupdates.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/maintenance/mgmt/2021-05-01/maintenance/client.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/maintenance/mgmt/2021-05-01/maintenance/configurationassignments.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/maintenance/mgmt/2021-05-01/maintenance/configurations.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/maintenance/mgmt/2021-05-01/maintenance/configurationsforresourcegroup.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/maintenance/mgmt/2021-05-01/maintenance/enums.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/maintenance/mgmt/2021-05-01/maintenance/models.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/maintenance/mgmt/2021-05-01/maintenance/operations.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/maintenance/mgmt/2021-05-01/maintenance/publicmaintenanceconfigurations.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/maintenance/mgmt/2021-05-01/maintenance/updates.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/maintenance/mgmt/2021-05-01/maintenance/version.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/mariadb/mgmt/2018-06-01/mariadb/CHANGELOG.md delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/mariadb/mgmt/2018-06-01/mariadb/_meta.json delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/mariadb/mgmt/2018-06-01/mariadb/advisors.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/mariadb/mgmt/2018-06-01/mariadb/checknameavailability.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/mariadb/mgmt/2018-06-01/mariadb/client.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/mariadb/mgmt/2018-06-01/mariadb/configurations.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/mariadb/mgmt/2018-06-01/mariadb/databases.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/mariadb/mgmt/2018-06-01/mariadb/enums.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/mariadb/mgmt/2018-06-01/mariadb/firewallrules.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/mariadb/mgmt/2018-06-01/mariadb/locationbasedperformancetier.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/mariadb/mgmt/2018-06-01/mariadb/locationbasedrecommendedactionsessionsoperationstatus.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/mariadb/mgmt/2018-06-01/mariadb/locationbasedrecommendedactionsessionsresult.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/mariadb/mgmt/2018-06-01/mariadb/logfiles.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/mariadb/mgmt/2018-06-01/mariadb/models.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/mariadb/mgmt/2018-06-01/mariadb/operations.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/mariadb/mgmt/2018-06-01/mariadb/privateendpointconnections.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/mariadb/mgmt/2018-06-01/mariadb/privatelinkresources.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/mariadb/mgmt/2018-06-01/mariadb/querytexts.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/mariadb/mgmt/2018-06-01/mariadb/recommendedactions.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/mariadb/mgmt/2018-06-01/mariadb/replicas.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/mariadb/mgmt/2018-06-01/mariadb/servers.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/mariadb/mgmt/2018-06-01/mariadb/serversecurityalertpolicies.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/mariadb/mgmt/2018-06-01/mariadb/topquerystatistics.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/mariadb/mgmt/2018-06-01/mariadb/version.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/mariadb/mgmt/2018-06-01/mariadb/virtualnetworkrules.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/mariadb/mgmt/2018-06-01/mariadb/waitstatistics.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/operationalinsights/mgmt/2020-08-01/operationalinsights/CHANGELOG.md delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/operationalinsights/mgmt/2020-08-01/operationalinsights/_meta.json delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/operationalinsights/mgmt/2020-08-01/operationalinsights/availableservicetiers.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/operationalinsights/mgmt/2020-08-01/operationalinsights/client.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/operationalinsights/mgmt/2020-08-01/operationalinsights/clusters.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/operationalinsights/mgmt/2020-08-01/operationalinsights/dataexports.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/operationalinsights/mgmt/2020-08-01/operationalinsights/datasources.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/operationalinsights/mgmt/2020-08-01/operationalinsights/deletedworkspaces.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/operationalinsights/mgmt/2020-08-01/operationalinsights/enums.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/operationalinsights/mgmt/2020-08-01/operationalinsights/gateways.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/operationalinsights/mgmt/2020-08-01/operationalinsights/intelligencepacks.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/operationalinsights/mgmt/2020-08-01/operationalinsights/linkedservices.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/operationalinsights/mgmt/2020-08-01/operationalinsights/linkedstorageaccounts.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/operationalinsights/mgmt/2020-08-01/operationalinsights/managementgroups.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/operationalinsights/mgmt/2020-08-01/operationalinsights/models.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/operationalinsights/mgmt/2020-08-01/operationalinsights/operations.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/operationalinsights/mgmt/2020-08-01/operationalinsights/operationstatuses.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/operationalinsights/mgmt/2020-08-01/operationalinsights/savedsearches.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/operationalinsights/mgmt/2020-08-01/operationalinsights/schema.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/operationalinsights/mgmt/2020-08-01/operationalinsights/sharedkeys.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/operationalinsights/mgmt/2020-08-01/operationalinsights/storageinsightconfigs.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/operationalinsights/mgmt/2020-08-01/operationalinsights/tables.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/operationalinsights/mgmt/2020-08-01/operationalinsights/usages.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/operationalinsights/mgmt/2020-08-01/operationalinsights/version.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/operationalinsights/mgmt/2020-08-01/operationalinsights/workspacepurge.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/operationalinsights/mgmt/2020-08-01/operationalinsights/workspaces.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2020-01-01/postgresql/CHANGELOG.md delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2020-01-01/postgresql/_meta.json delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2020-01-01/postgresql/checknameavailability.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2020-01-01/postgresql/client.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2020-01-01/postgresql/configurations.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2020-01-01/postgresql/databases.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2020-01-01/postgresql/enums.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2020-01-01/postgresql/firewallrules.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2020-01-01/postgresql/locationbasedperformancetier.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2020-01-01/postgresql/logfiles.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2020-01-01/postgresql/models.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2020-01-01/postgresql/operations.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2020-01-01/postgresql/privateendpointconnections.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2020-01-01/postgresql/privatelinkresources.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2020-01-01/postgresql/recoverableservers.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2020-01-01/postgresql/replicas.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2020-01-01/postgresql/serveradministrators.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2020-01-01/postgresql/serverbasedperformancetier.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2020-01-01/postgresql/serverkeys.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2020-01-01/postgresql/serverparameters.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2020-01-01/postgresql/servers.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2020-01-01/postgresql/serversecurityalertpolicies.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2020-01-01/postgresql/version.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2020-01-01/postgresql/virtualnetworkrules.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2021-06-01/postgresqlflexibleservers/CHANGELOG.md delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2021-06-01/postgresqlflexibleservers/_meta.json delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2021-06-01/postgresqlflexibleservers/checknameavailability.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2021-06-01/postgresqlflexibleservers/client.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2021-06-01/postgresqlflexibleservers/configurations.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2021-06-01/postgresqlflexibleservers/databases.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2021-06-01/postgresqlflexibleservers/enums.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2021-06-01/postgresqlflexibleservers/firewallrules.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2021-06-01/postgresqlflexibleservers/getprivatednszonesuffix.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2021-06-01/postgresqlflexibleservers/locationbasedcapabilities.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2021-06-01/postgresqlflexibleservers/models.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2021-06-01/postgresqlflexibleservers/operations.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2021-06-01/postgresqlflexibleservers/servers.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2021-06-01/postgresqlflexibleservers/version.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2021-06-01/postgresqlflexibleservers/virtualnetworksubnetusage.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2019-06-01-preview/containerregistry/CHANGELOG.md delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2019-06-01-preview/containerregistry/_meta.json delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2019-06-01-preview/containerregistry/enums.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2019-06-01-preview/containerregistry/models.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2019-06-01-preview/containerregistry/operations.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2019-06-01-preview/containerregistry/registries.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2019-06-01-preview/containerregistry/replications.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2019-06-01-preview/containerregistry/scopemaps.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2019-06-01-preview/containerregistry/tokens.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2019-06-01-preview/containerregistry/version.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2019-06-01-preview/containerregistry/webhooks.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2021-08-01-preview/containerregistry/CHANGELOG.md delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2021-08-01-preview/containerregistry/_meta.json delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2021-08-01-preview/containerregistry/agentpools.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2021-08-01-preview/containerregistry/client.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2021-08-01-preview/containerregistry/enums.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2021-08-01-preview/containerregistry/models.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2021-08-01-preview/containerregistry/operations.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2021-08-01-preview/containerregistry/privateendpointconnections.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2021-08-01-preview/containerregistry/registries.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2021-08-01-preview/containerregistry/replications.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2021-08-01-preview/containerregistry/runs.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2021-08-01-preview/containerregistry/scopemaps.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2021-08-01-preview/containerregistry/taskruns.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2021-08-01-preview/containerregistry/tasks.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2021-08-01-preview/containerregistry/tokens.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2021-08-01-preview/containerregistry/version.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2021-08-01-preview/containerregistry/webhooks.go rename vendor/github.com/Azure/azure-sdk-for-go/services/{costmanagement/mgmt/2020-06-01/costmanagement => preview/containerregistry/mgmt/2022-02-01-preview/containerregistry}/CHANGELOG.md (100%) create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2022-02-01-preview/containerregistry/_meta.json rename vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/{2019-06-01-preview => 2022-02-01-preview}/containerregistry/agentpools.go (100%) rename vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/{2019-06-01-preview => 2022-02-01-preview}/containerregistry/client.go (100%) rename vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/{2021-08-01-preview => 2022-02-01-preview}/containerregistry/connectedregistries.go (99%) create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2022-02-01-preview/containerregistry/enums.go rename vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/{2021-08-01-preview => 2022-02-01-preview}/containerregistry/exportpipelines.go (99%) rename vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/{2021-08-01-preview => 2022-02-01-preview}/containerregistry/importpipelines.go (99%) create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2022-02-01-preview/containerregistry/models.go create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2022-02-01-preview/containerregistry/operations.go rename vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/{2021-08-01-preview => 2022-02-01-preview}/containerregistry/pipelineruns.go (99%) create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2022-02-01-preview/containerregistry/privateendpointconnections.go create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2022-02-01-preview/containerregistry/registries.go create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2022-02-01-preview/containerregistry/replications.go rename vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/{2019-06-01-preview => 2022-02-01-preview}/containerregistry/runs.go (100%) create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2022-02-01-preview/containerregistry/scopemaps.go rename vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/{2019-06-01-preview => 2022-02-01-preview}/containerregistry/taskruns.go (100%) rename vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/{2019-06-01-preview => 2022-02-01-preview}/containerregistry/tasks.go (100%) create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2022-02-01-preview/containerregistry/tokens.go create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2022-02-01-preview/containerregistry/version.go create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2022-02-01-preview/containerregistry/webhooks.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/operationsmanagement/mgmt/2015-11-01-preview/operationsmanagement/CHANGELOG.md delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/operationsmanagement/mgmt/2015-11-01-preview/operationsmanagement/_meta.json delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/operationsmanagement/mgmt/2015-11-01-preview/operationsmanagement/client.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/operationsmanagement/mgmt/2015-11-01-preview/operationsmanagement/managementassociations.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/operationsmanagement/mgmt/2015-11-01-preview/operationsmanagement/managementconfigurations.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/operationsmanagement/mgmt/2015-11-01-preview/operationsmanagement/models.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/operationsmanagement/mgmt/2015-11-01-preview/operationsmanagement/operations.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/operationsmanagement/mgmt/2015-11-01-preview/operationsmanagement/solutions.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/preview/operationsmanagement/mgmt/2015-11-01-preview/operationsmanagement/version.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2021-04-01/storage/CHANGELOG.md delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2021-04-01/storage/_meta.json delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2021-04-01/storage/client.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2021-04-01/storage/enums.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2021-04-01/storage/models.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2021-04-01/storage/operations.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2021-04-01/storage/privateendpointconnections.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2021-04-01/storage/privatelinkresources.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2021-04-01/storage/usages.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2021-04-01/storage/version.go rename vendor/github.com/Azure/azure-sdk-for-go/services/{dns/mgmt/2018-05-01/dns => storage/mgmt/2021-09-01/storage}/CHANGELOG.md (100%) create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2021-09-01/storage/_meta.json rename vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/{2021-04-01 => 2021-09-01}/storage/accounts.go (85%) rename vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/{2021-04-01 => 2021-09-01}/storage/blobcontainers.go (99%) rename vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/{2021-04-01 => 2021-09-01}/storage/blobinventorypolicies.go (99%) rename vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/{2021-04-01 => 2021-09-01}/storage/blobservices.go (99%) create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2021-09-01/storage/client.go rename vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/{2021-04-01 => 2021-09-01}/storage/deletedaccounts.go (99%) rename vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/{2021-04-01 => 2021-09-01}/storage/encryptionscopes.go (99%) create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2021-09-01/storage/enums.go rename vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/{2021-04-01 => 2021-09-01}/storage/fileservices.go (99%) rename vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/{2021-04-01 => 2021-09-01}/storage/fileshares.go (99%) create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2021-09-01/storage/localusers.go rename vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/{2021-04-01 => 2021-09-01}/storage/managementpolicies.go (99%) create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2021-09-01/storage/models.go rename vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/{2021-04-01 => 2021-09-01}/storage/objectreplicationpolicies.go (94%) create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2021-09-01/storage/operations.go create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2021-09-01/storage/privateendpointconnections.go create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2021-09-01/storage/privatelinkresources.go rename vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/{2021-04-01 => 2021-09-01}/storage/queue.go (99%) rename vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/{2021-04-01 => 2021-09-01}/storage/queueservices.go (99%) rename vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/{2021-04-01 => 2021-09-01}/storage/skus.go (99%) rename vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/{2021-04-01 => 2021-09-01}/storage/table.go (95%) rename vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/{2021-04-01 => 2021-09-01}/storage/tableservices.go (99%) create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2021-09-01/storage/usages.go create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2021-09-01/storage/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-helpers/resourcemanager/commonids/cloud_services_ip_configuration.go create mode 100644 vendor/github.com/hashicorp/go-azure-helpers/resourcemanager/commonids/cloud_services_public_ip.go create mode 100644 vendor/github.com/hashicorp/go-azure-helpers/resourcemanager/commonids/express_route_circuit_peering.go create mode 100644 vendor/github.com/hashicorp/go-azure-helpers/resourcemanager/commonids/network_interface.go create mode 100644 vendor/github.com/hashicorp/go-azure-helpers/resourcemanager/commonids/network_interface_ip_configuration.go create mode 100644 vendor/github.com/hashicorp/go-azure-helpers/resourcemanager/commonids/provisioning_service.go create mode 100644 vendor/github.com/hashicorp/go-azure-helpers/resourcemanager/commonids/public_ip_address.go create mode 100644 vendor/github.com/hashicorp/go-azure-helpers/resourcemanager/commonids/virtual_hub_bgp_connection.go create mode 100644 vendor/github.com/hashicorp/go-azure-helpers/resourcemanager/commonids/virtual_hub_ip_configuration.go create mode 100644 vendor/github.com/hashicorp/go-azure-helpers/resourcemanager/commonids/virtual_machine_scale_set_ip_configuration.go create mode 100644 vendor/github.com/hashicorp/go-azure-helpers/resourcemanager/commonids/virtual_machine_scale_set_network_interface.go create mode 100644 vendor/github.com/hashicorp/go-azure-helpers/resourcemanager/commonids/virtual_machine_scale_set_public_ip_address.go create mode 100644 vendor/github.com/hashicorp/go-azure-helpers/resourcemanager/commonids/virtual_router_peering.go create mode 100644 vendor/github.com/hashicorp/go-azure-helpers/resourcemanager/commonids/virtual_wan_p2s_vpn_gateway.go create mode 100644 vendor/github.com/hashicorp/go-azure-helpers/resourcemanager/commonids/vpn_connection.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/aad/2021-05-01/domainservices/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/aad/2021-05-01/domainservices/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/aad/2021-05-01/domainservices/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/aad/2021-05-01/domainservices/id_domainservice.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/aad/2021-05-01/domainservices/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/aad/2021-05-01/domainservices/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/aad/2021-05-01/domainservices/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/aad/2021-05-01/domainservices/method_list_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/aad/2021-05-01/domainservices/method_listbyresourcegroup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/aad/2021-05-01/domainservices/method_update_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/aad/2021-05-01/domainservices/model_configdiagnostics.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/aad/2021-05-01/domainservices/model_configdiagnosticsvalidatorresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/aad/2021-05-01/domainservices/model_configdiagnosticsvalidatorresultissue.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/aad/2021-05-01/domainservices/model_domainsecuritysettings.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/aad/2021-05-01/domainservices/model_domainservice.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/aad/2021-05-01/domainservices/model_domainserviceproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/aad/2021-05-01/domainservices/model_foresttrust.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/aad/2021-05-01/domainservices/model_healthalert.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/aad/2021-05-01/domainservices/model_healthmonitor.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/aad/2021-05-01/domainservices/model_ldapssettings.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/aad/2021-05-01/domainservices/model_migrationprogress.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/aad/2021-05-01/domainservices/model_migrationproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/aad/2021-05-01/domainservices/model_notificationsettings.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/aad/2021-05-01/domainservices/model_replicaset.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/aad/2021-05-01/domainservices/model_resourceforestsettings.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/aad/2021-05-01/domainservices/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/aad/2021-05-01/domainservices/version.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2020-11-20/applicationinsights/README.md delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2020-11-20/applicationinsights/client.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2020-11-20/applicationinsights/method_workbooktemplatescreateorupdate_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2020-11-20/applicationinsights/method_workbooktemplatesdelete_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2020-11-20/applicationinsights/method_workbooktemplatesget_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2020-11-20/applicationinsights/method_workbooktemplateslistbyresourcegroup_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2020-11-20/applicationinsights/method_workbooktemplatesupdate_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2020-11-20/applicationinsights/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2020-11-20/workbooktemplatesapis/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2020-11-20/workbooktemplatesapis/client.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2020-11-20/{applicationinsights => workbooktemplatesapis}/id_workbooktemplate.go (99%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2020-11-20/workbooktemplatesapis/method_workbooktemplatescreateorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2020-11-20/workbooktemplatesapis/method_workbooktemplatesdelete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2020-11-20/workbooktemplatesapis/method_workbooktemplatesget_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2020-11-20/workbooktemplatesapis/method_workbooktemplateslistbyresourcegroup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2020-11-20/workbooktemplatesapis/method_workbooktemplatesupdate_autorest.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2020-11-20/{applicationinsights => workbooktemplatesapis}/model_workbooktemplate.go (95%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2020-11-20/{applicationinsights => workbooktemplatesapis}/model_workbooktemplategallery.go (93%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2020-11-20/{applicationinsights => workbooktemplatesapis}/model_workbooktemplatelocalizedgallery.go (92%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2020-11-20/{applicationinsights => workbooktemplatesapis}/model_workbooktemplateproperties.go (95%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2020-11-20/{applicationinsights => workbooktemplatesapis}/model_workbooktemplateslistresult.go (89%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2020-11-20/{applicationinsights => workbooktemplatesapis}/model_workbooktemplateupdateparameters.go (91%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2020-11-20/workbooktemplatesapis/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2022-04-01/workbooksapis/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2022-04-01/workbooksapis/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2022-04-01/workbooksapis/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2022-04-01/workbooksapis/id_revision.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2022-04-01/workbooksapis/id_workbook.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2022-04-01/workbooksapis/method_workbookscreateorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2022-04-01/workbooksapis/method_workbooksdelete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2022-04-01/workbooksapis/method_workbooksget_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2022-04-01/workbooksapis/method_workbookslistbyresourcegroup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2022-04-01/workbooksapis/method_workbookslistbysubscription_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2022-04-01/workbooksapis/method_workbooksrevisionget_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2022-04-01/workbooksapis/method_workbooksrevisionslist_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2022-04-01/workbooksapis/method_workbooksupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2022-04-01/workbooksapis/model_workbook.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2022-04-01/workbooksapis/model_workbookproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2022-04-01/workbooksapis/model_workbookpropertiesupdateparameters.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2022-04-01/workbooksapis/model_workbookupdateparameters.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2022-04-01/workbooksapis/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2022-04-01/workbooksapis/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/automationaccount/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/automationaccount/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/automationaccount/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/automationaccount/id_automationaccount.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/automationaccount/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/automationaccount/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/automationaccount/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/automationaccount/method_list_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/automationaccount/method_listbyresourcegroup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/automationaccount/method_update_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/automationaccount/model_automationaccount.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/automationaccount/model_automationaccountcreateorupdateparameters.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/automationaccount/model_automationaccountcreateorupdateproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/automationaccount/model_automationaccountproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/automationaccount/model_automationaccountupdateparameters.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/automationaccount/model_automationaccountupdateproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/automationaccount/model_encryptionproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/automationaccount/model_encryptionpropertiesidentity.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/automationaccount/model_keyvaultproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/automationaccount/model_privateendpointconnection.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/automationaccount/model_privateendpointconnectionproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/automationaccount/model_privateendpointproperty.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/automationaccount/model_privatelinkserviceconnectionstateproperty.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/automationaccount/model_sku.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/automationaccount/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/automationaccount/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/hybridrunbookworkergroup/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/hybridrunbookworkergroup/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/hybridrunbookworkergroup/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/hybridrunbookworkergroup/id_automationaccount.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/hybridrunbookworkergroup/id_hybridrunbookworkergroup.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/hybridrunbookworkergroup/method_create_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/hybridrunbookworkergroup/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/hybridrunbookworkergroup/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/hybridrunbookworkergroup/method_listbyautomationaccount_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/hybridrunbookworkergroup/method_update_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/hybridrunbookworkergroup/model_hybridrunbookworkergroup.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/hybridrunbookworkergroup/model_hybridrunbookworkergroupcreateorupdateparameters.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/hybridrunbookworkergroup/model_hybridrunbookworkerlegacy.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/hybridrunbookworkergroup/model_runascredentialassociationproperty.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/hybridrunbookworkergroup/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/hybridrunbookworkergroup/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhostgroups/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhostgroups/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhostgroups/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhostgroups/id_hostgroup.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhostgroups/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhostgroups/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhostgroups/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhostgroups/method_listbyresourcegroup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhostgroups/method_listbysubscription_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhostgroups/method_update_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhostgroups/model_dedicatedhostallocatablevm.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhostgroups/model_dedicatedhostavailablecapacity.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhostgroups/model_dedicatedhostgroup.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhostgroups/model_dedicatedhostgroupinstanceview.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhostgroups/model_dedicatedhostgroupproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhostgroups/model_dedicatedhostgroupupdate.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhostgroups/model_dedicatedhostinstanceviewwithname.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhostgroups/model_instanceviewstatus.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhostgroups/model_subresourcereadonly.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhostgroups/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhostgroups/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhosts/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhosts/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhosts/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhosts/id_host.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhosts/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhosts/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhosts/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhosts/method_update_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhosts/model_dedicatedhost.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhosts/model_dedicatedhostallocatablevm.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhosts/model_dedicatedhostavailablecapacity.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhosts/model_dedicatedhostinstanceview.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhosts/model_dedicatedhostproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhosts/model_dedicatedhostupdate.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhosts/model_instanceviewstatus.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhosts/model_sku.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhosts/model_subresourcereadonly.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhosts/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/proximityplacementgroups/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/proximityplacementgroups/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/proximityplacementgroups/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/proximityplacementgroups/id_proximityplacementgroup.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/proximityplacementgroups/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/proximityplacementgroups/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/proximityplacementgroups/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/proximityplacementgroups/method_listbyresourcegroup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/proximityplacementgroups/method_listbysubscription_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/proximityplacementgroups/method_update_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/proximityplacementgroups/model_instanceviewstatus.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/proximityplacementgroups/model_proximityplacementgroup.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/proximityplacementgroups/model_proximityplacementgroupproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/proximityplacementgroups/model_subresourcewithcolocationstatus.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/proximityplacementgroups/model_updateresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/proximityplacementgroups/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/proximityplacementgroups/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/consumption/2019-10-01/budgets/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/consumption/2019-10-01/budgets/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/consumption/2019-10-01/budgets/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/consumption/2019-10-01/budgets/id_scopedbudget.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/consumption/2019-10-01/budgets/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/consumption/2019-10-01/budgets/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/consumption/2019-10-01/budgets/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/consumption/2019-10-01/budgets/method_list_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/consumption/2019-10-01/budgets/model_budget.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/consumption/2019-10-01/budgets/model_budgetcomparisonexpression.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/consumption/2019-10-01/budgets/model_budgetfilter.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/consumption/2019-10-01/budgets/model_budgetfilterproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/consumption/2019-10-01/budgets/model_budgetproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/consumption/2019-10-01/budgets/model_budgettimeperiod.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/consumption/2019-10-01/budgets/model_currentspend.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/consumption/2019-10-01/budgets/model_forecastspend.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/consumption/2019-10-01/budgets/model_notification.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/consumption/2019-10-01/budgets/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/consumption/2019-10-01/budgets/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/id_cassandrakeyspace.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/id_cassandrakeyspacetable.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/id_collection.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/id_collectionpartitionkeyrangeid.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/id_container.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/id_database.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/id_databaseaccount.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/id_databaseaccountname.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/id_databasecollection.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/id_graph.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/id_gremlindatabase.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/id_location.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/id_mongodbdatabase.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/id_mongodbdatabasecollection.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/id_partitionkeyrangeid.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/id_region.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/id_sourceregiontargetregion.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/id_sqldatabase.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/id_storedprocedure.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/id_table.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/id_targetregion.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/id_trigger.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/id_userdefinedfunction.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_cassandraresourcescreateupdatecassandrakeyspace_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_cassandraresourcescreateupdatecassandratable_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_cassandraresourcesdeletecassandrakeyspace_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_cassandraresourcesdeletecassandratable_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_cassandraresourcesgetcassandrakeyspace_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_cassandraresourcesgetcassandrakeyspacethroughput_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_cassandraresourcesgetcassandratable_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_cassandraresourcesgetcassandratablethroughput_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_cassandraresourceslistcassandrakeyspaces_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_cassandraresourceslistcassandratables_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_cassandraresourcesmigratecassandrakeyspacetoautoscale_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_cassandraresourcesmigratecassandrakeyspacetomanualthroughput_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_cassandraresourcesmigratecassandratabletoautoscale_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_cassandraresourcesmigratecassandratabletomanualthroughput_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_cassandraresourcesupdatecassandrakeyspacethroughput_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_cassandraresourcesupdatecassandratablethroughput_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_collectionlistmetricdefinitions_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_collectionlistmetrics_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_collectionlistusages_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_collectionpartitionlistmetrics_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_collectionpartitionlistusages_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_collectionpartitionregionlistmetrics_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_collectionregionlistmetrics_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_databaseaccountregionlistmetrics_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_databaseaccountschecknameexists_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_databaseaccountscreateorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_databaseaccountsdelete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_databaseaccountsfailoverprioritychange_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_databaseaccountsget_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_databaseaccountsgetreadonlykeys_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_databaseaccountslist_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_databaseaccountslistbyresourcegroup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_databaseaccountslistconnectionstrings_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_databaseaccountslistkeys_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_databaseaccountslistmetricdefinitions_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_databaseaccountslistmetrics_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_databaseaccountslistreadonlykeys_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_databaseaccountslistusages_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_databaseaccountsofflineregion_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_databaseaccountsonlineregion_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_databaseaccountsregeneratekey_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_databaseaccountsupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_databaselistmetricdefinitions_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_databaselistmetrics_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_databaselistusages_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_gremlinresourcescreateupdategremlindatabase_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_gremlinresourcescreateupdategremlingraph_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_gremlinresourcesdeletegremlindatabase_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_gremlinresourcesdeletegremlingraph_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_gremlinresourcesgetgremlindatabase_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_gremlinresourcesgetgremlindatabasethroughput_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_gremlinresourcesgetgremlingraph_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_gremlinresourcesgetgremlingraphthroughput_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_gremlinresourceslistgremlindatabases_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_gremlinresourceslistgremlingraphs_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_gremlinresourcesmigrategremlindatabasetoautoscale_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_gremlinresourcesmigrategremlindatabasetomanualthroughput_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_gremlinresourcesmigrategremlingraphtoautoscale_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_gremlinresourcesmigrategremlingraphtomanualthroughput_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_gremlinresourcesupdategremlindatabasethroughput_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_gremlinresourcesupdategremlingraphthroughput_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_locationsget_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_locationslist_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_mongodbresourcescreateupdatemongodbcollection_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_mongodbresourcescreateupdatemongodbdatabase_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_mongodbresourcesdeletemongodbcollection_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_mongodbresourcesdeletemongodbdatabase_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_mongodbresourcesgetmongodbcollection_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_mongodbresourcesgetmongodbcollectionthroughput_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_mongodbresourcesgetmongodbdatabase_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_mongodbresourcesgetmongodbdatabasethroughput_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_mongodbresourceslistmongodbcollections_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_mongodbresourceslistmongodbdatabases_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_mongodbresourcesmigratemongodbcollectiontoautoscale_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_mongodbresourcesmigratemongodbcollectiontomanualthroughput_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_mongodbresourcesmigratemongodbdatabasetoautoscale_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_mongodbresourcesmigratemongodbdatabasetomanualthroughput_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_mongodbresourcesupdatemongodbcollectionthroughput_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_mongodbresourcesupdatemongodbdatabasethroughput_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_partitionkeyrangeidlistmetrics_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_partitionkeyrangeidregionlistmetrics_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_percentilelistmetrics_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_percentilesourcetargetlistmetrics_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_percentiletargetlistmetrics_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_sqlresourcescreateupdatesqlcontainer_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_sqlresourcescreateupdatesqldatabase_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_sqlresourcescreateupdatesqlstoredprocedure_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_sqlresourcescreateupdatesqltrigger_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_sqlresourcescreateupdatesqluserdefinedfunction_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_sqlresourcesdeletesqlcontainer_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_sqlresourcesdeletesqldatabase_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_sqlresourcesdeletesqlstoredprocedure_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_sqlresourcesdeletesqltrigger_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_sqlresourcesdeletesqluserdefinedfunction_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_sqlresourcesgetsqlcontainer_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_sqlresourcesgetsqlcontainerthroughput_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_sqlresourcesgetsqldatabase_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_sqlresourcesgetsqldatabasethroughput_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_sqlresourcesgetsqlstoredprocedure_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_sqlresourcesgetsqltrigger_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_sqlresourcesgetsqluserdefinedfunction_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_sqlresourceslistsqlcontainers_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_sqlresourceslistsqldatabases_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_sqlresourceslistsqlstoredprocedures_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_sqlresourceslistsqltriggers_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_sqlresourceslistsqluserdefinedfunctions_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_sqlresourcesmigratesqlcontainertoautoscale_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_sqlresourcesmigratesqlcontainertomanualthroughput_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_sqlresourcesmigratesqldatabasetoautoscale_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_sqlresourcesmigratesqldatabasetomanualthroughput_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_sqlresourcesupdatesqlcontainerthroughput_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_sqlresourcesupdatesqldatabasethroughput_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_tableresourcescreateupdatetable_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_tableresourcesdeletetable_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_tableresourcesgettable_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_tableresourcesgettablethroughput_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_tableresourceslisttables_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_tableresourcesmigratetabletoautoscale_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_tableresourcesmigratetabletomanualthroughput_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/method_tableresourcesupdatetablethroughput_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_analyticalstorageconfiguration.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_apiproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_autoscalesettings.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_autoscalesettingsresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_autoupgradepolicyresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_backuppolicy.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_backuppolicymigrationstate.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_capability.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_capacity.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_cassandrakeyspacecreateupdateparameters.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_cassandrakeyspacecreateupdateproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_cassandrakeyspacegetproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_cassandrakeyspacegetresults.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_cassandrakeyspacelistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_cassandrakeyspaceresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_cassandrapartitionkey.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_cassandraschema.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_cassandratablecreateupdateparameters.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_cassandratablecreateupdateproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_cassandratablegetproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_cassandratablegetresults.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_cassandratablelistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_cassandratableresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_clusterkey.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_column.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_compositepath.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_conflictresolutionpolicy.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_consistencypolicy.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_containerpartitionkey.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_continuousmodebackuppolicy.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_corspolicy.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_createupdateoptions.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_databaseaccountconnectionstring.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_databaseaccountcreateupdateparameters.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_databaseaccountcreateupdateproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_databaseaccountgetproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_databaseaccountgetresults.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_databaseaccountlistconnectionstringsresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_databaseaccountlistkeysresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_databaseaccountlistreadonlykeysresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_databaseaccountregeneratekeyparameters.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_databaseaccountslistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_databaseaccountupdateparameters.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_databaseaccountupdateproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_databaserestoreresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_excludedpath.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_failoverpolicies.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_failoverpolicy.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_gremlindatabasecreateupdateparameters.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_gremlindatabasecreateupdateproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_gremlindatabasegetproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_gremlindatabasegetresults.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_gremlindatabaselistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_gremlindatabaseresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_gremlingraphcreateupdateparameters.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_gremlingraphcreateupdateproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_gremlingraphgetproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_gremlingraphgetresults.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_gremlingraphlistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_gremlingraphresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_includedpath.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_indexes.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_indexingpolicy.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_ipaddressorrange.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_location.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_locationgetresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_locationlistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_locationproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_metric.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_metricavailability.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_metricdefinition.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_metricdefinitionslistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_metriclistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_metricname.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_metricvalue.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_mongodbcollectioncreateupdateparameters.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_mongodbcollectioncreateupdateproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_mongodbcollectiongetproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_mongodbcollectiongetresults.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_mongodbcollectionlistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_mongodbcollectionresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_mongodbdatabasecreateupdateparameters.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_mongodbdatabasecreateupdateproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_mongodbdatabasegetproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_mongodbdatabasegetresults.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_mongodbdatabaselistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_mongodbdatabaseresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_mongoindex.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_mongoindexkeys.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_mongoindexoptions.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_optionsresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_partitionmetric.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_partitionmetriclistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_partitionusage.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_partitionusagesresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_percentilemetric.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_percentilemetriclistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_percentilemetricvalue.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_periodicmodebackuppolicy.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_periodicmodeproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_privateendpointconnection.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_privateendpointconnectionproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_privateendpointproperty.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_privatelinkserviceconnectionstateproperty.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_regionforonlineoffline.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_restoreparameters.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_spatialspec.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_sqlcontainercreateupdateparameters.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_sqlcontainercreateupdateproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_sqlcontainergetproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_sqlcontainergetresults.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_sqlcontainerlistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_sqlcontainerresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_sqldatabasecreateupdateparameters.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_sqldatabasecreateupdateproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_sqldatabasegetproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_sqldatabasegetpropertiesresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_sqldatabasegetresults.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_sqldatabaselistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_sqldatabaseresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_sqlstoredprocedurecreateupdateparameters.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_sqlstoredprocedurecreateupdateproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_sqlstoredproceduregetproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_sqlstoredproceduregetresults.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_sqlstoredprocedurelistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_sqlstoredprocedureresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_sqltriggercreateupdateparameters.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_sqltriggercreateupdateproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_sqltriggergetproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_sqltriggergetresults.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_sqltriggerlistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_sqltriggerresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_sqluserdefinedfunctioncreateupdateparameters.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_sqluserdefinedfunctioncreateupdateproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_sqluserdefinedfunctiongetproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_sqluserdefinedfunctiongetresults.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_sqluserdefinedfunctionlistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_sqluserdefinedfunctionresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_tablecreateupdateparameters.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_tablecreateupdateproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_tablegetproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_tablegetresults.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_tablelistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_tableresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_throughputpolicyresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_throughputsettingsgetproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_throughputsettingsgetresults.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_throughputsettingsresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_throughputsettingsupdateparameters.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_throughputsettingsupdateproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_uniquekey.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_uniquekeypolicy.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_usage.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_usagesresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/model_virtualnetworkrule.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/sqldedicatedgateway/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/sqldedicatedgateway/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/sqldedicatedgateway/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/sqldedicatedgateway/id_service.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/sqldedicatedgateway/method_servicecreate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/sqldedicatedgateway/method_servicedelete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/sqldedicatedgateway/method_serviceget_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/sqldedicatedgateway/model_datatransferserviceresourceproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/sqldedicatedgateway/model_graphapicomputeregionalserviceresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/sqldedicatedgateway/model_graphapicomputeserviceresourceproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/sqldedicatedgateway/model_materializedviewsbuilderserviceresourceproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/sqldedicatedgateway/model_regionalserviceresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/sqldedicatedgateway/model_serviceresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/sqldedicatedgateway/model_serviceresourcecreateupdateparameters.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/sqldedicatedgateway/model_serviceresourcecreateupdateproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/sqldedicatedgateway/model_serviceresourceproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/sqldedicatedgateway/model_sqldedicatedgatewayregionalserviceresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/sqldedicatedgateway/model_sqldedicatedgatewayserviceresourceproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/sqldedicatedgateway/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/costmanagement/2021-10-01/exports/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/costmanagement/2021-10-01/exports/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/costmanagement/2021-10-01/exports/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/costmanagement/2021-10-01/exports/id_scopedexport.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/costmanagement/2021-10-01/exports/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/costmanagement/2021-10-01/exports/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/costmanagement/2021-10-01/exports/method_execute_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/costmanagement/2021-10-01/exports/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/costmanagement/2021-10-01/exports/method_getexecutionhistory_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/costmanagement/2021-10-01/exports/method_list_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/costmanagement/2021-10-01/exports/model_commonexportproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/costmanagement/2021-10-01/exports/model_errordetails.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/costmanagement/2021-10-01/exports/model_export.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/costmanagement/2021-10-01/exports/model_exportdataset.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/costmanagement/2021-10-01/exports/model_exportdatasetconfiguration.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/costmanagement/2021-10-01/exports/model_exportdefinition.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/costmanagement/2021-10-01/exports/model_exportdeliverydestination.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/costmanagement/2021-10-01/exports/model_exportdeliveryinfo.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/costmanagement/2021-10-01/exports/model_exportexecution.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/costmanagement/2021-10-01/exports/model_exportexecutionlistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/costmanagement/2021-10-01/exports/model_exportexecutionproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/costmanagement/2021-10-01/exports/model_exportlistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/costmanagement/2021-10-01/exports/model_exportproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/costmanagement/2021-10-01/exports/model_exportrecurrenceperiod.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/costmanagement/2021-10-01/exports/model_exportschedule.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/costmanagement/2021-10-01/exports/model_exporttimeperiod.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/costmanagement/2021-10-01/exports/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dashboard/2022-08-01/grafanaresource/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dashboard/2022-08-01/grafanaresource/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dashboard/2022-08-01/grafanaresource/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dashboard/2022-08-01/grafanaresource/id_grafana.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dashboard/2022-08-01/grafanaresource/method_grafanacreate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dashboard/2022-08-01/grafanaresource/method_grafanadelete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dashboard/2022-08-01/grafanaresource/method_grafanaget_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dashboard/2022-08-01/grafanaresource/method_grafanalist_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dashboard/2022-08-01/grafanaresource/method_grafanalistbyresourcegroup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dashboard/2022-08-01/grafanaresource/method_grafanaupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dashboard/2022-08-01/grafanaresource/model_azuremonitorworkspaceintegration.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dashboard/2022-08-01/grafanaresource/model_grafanaintegrations.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dashboard/2022-08-01/grafanaresource/model_managedgrafana.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dashboard/2022-08-01/grafanaresource/model_managedgrafanaproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dashboard/2022-08-01/grafanaresource/model_managedgrafanapropertiesupdateparameters.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dashboard/2022-08-01/grafanaresource/model_managedgrafanaupdateparameters.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dashboard/2022-08-01/grafanaresource/model_privateendpoint.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dashboard/2022-08-01/grafanaresource/model_privateendpointconnection.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dashboard/2022-08-01/grafanaresource/model_privateendpointconnectionproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dashboard/2022-08-01/grafanaresource/model_privatelinkserviceconnectionstate.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dashboard/2022-08-01/grafanaresource/model_resourcesku.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dashboard/2022-08-01/grafanaresource/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dashboard/2022-08-01/grafanaresource/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/id_backupinstance.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/id_backupvault.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/method_adhocbackup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/method_list_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/method_resumebackups_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/method_resumeprotection_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/method_stopprotection_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/method_suspendbackups_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/method_syncbackupinstance_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/method_triggerrehydrate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/method_triggerrestore_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/method_validateforbackup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/method_validateforrestore_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/model_adhocbackupruleoptions.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/model_adhocbackuptriggeroption.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/model_authcredentials.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/model_azurebackuprecoverypointbasedrestorerequest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/model_azurebackuprecoverytimebasedrestorerequest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/model_azurebackuprehydrationrequest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/model_azurebackuprestorerequest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/model_azureoperationalstoreparameters.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/model_backupinstance.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/model_backupinstanceresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/model_datasource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/model_datasourceset.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/model_datastoreparameters.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/model_innererror.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/model_itemlevelrestorecriteria.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/model_itemlevelrestoretargetinfo.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/model_kubernetespvrestorecriteria.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/model_kubernetesstorageclassrestorecriteria.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/model_operationextendedinfo.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/model_operationjobextendedinfo.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/model_policyinfo.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/model_policyparameters.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/model_protectionstatusdetails.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/model_rangebaseditemlevelrestorecriteria.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/model_restorefilestargetinfo.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/model_restoretargetinfo.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/model_restoretargetinfobase.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/model_secretstorebasedauthcredentials.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/model_secretstoreresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/model_syncbackupinstancerequest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/model_targetdetails.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/model_triggerbackuprequest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/model_userfacingerror.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/model_validateforbackuprequest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/model_validaterestorerequestobject.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/id_backuppolicies.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/id_backupvault.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/method_list_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/model_absolutedeleteoption.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/model_adhocbasedtaggingcriteria.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/model_adhocbasedtriggercontext.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/model_azurebackupparams.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/model_azurebackuprule.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/model_azureretentionrule.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/model_backupcriteria.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/model_backupparameters.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/model_backuppolicy.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/model_backupschedule.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/model_basebackuppolicy.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/model_basebackuppolicyresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/model_basepolicyrule.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/model_copyonexpiryoption.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/model_copyoption.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/model_customcopyoption.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/model_datastoreinfobase.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/model_day.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/model_deleteoption.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/model_immediatecopyoption.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/model_retentiontag.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/model_schedulebasedbackupcriteria.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/model_schedulebasedtriggercontext.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/model_sourcelifecycle.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/model_taggingcriteria.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/model_targetcopysetting.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/model_triggercontext.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupvaults/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupvaults/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupvaults/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupvaults/id_backupvault.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupvaults/id_providerlocation.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupvaults/method_checknameavailability_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupvaults/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupvaults/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupvaults/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupvaults/method_getinresourcegroup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupvaults/method_getinsubscription_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupvaults/method_update_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupvaults/model_azuremonitoralertsettings.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupvaults/model_backupvault.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupvaults/model_backupvaultresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupvaults/model_checknameavailabilityrequest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupvaults/model_checknameavailabilityresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupvaults/model_dppidentitydetails.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupvaults/model_monitoringsettings.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupvaults/model_patchbackupvaultinput.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupvaults/model_patchresourcerequestinput.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupvaults/model_resourcemovedetails.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupvaults/model_storagesetting.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupvaults/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupvaults/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/dns/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/dns/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/dns/method_dnsresourcereferencegetbytargetresources_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/dns/model_dnsresourcereference.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/dns/model_dnsresourcereferencerequest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/dns/model_dnsresourcereferencerequestproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/dns/model_dnsresourcereferenceresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/dns/model_dnsresourcereferenceresultproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/dns/model_subresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/dns/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets/id_dnszone.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets/id_recordtype.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets/id_zone.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets/method_listallbydnszone_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets/method_listbydnszone_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets/method_listbytype_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets/method_update_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets/model_aaaarecord.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets/model_arecord.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets/model_caarecord.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets/model_cnamerecord.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets/model_mxrecord.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets/model_nsrecord.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets/model_ptrrecord.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets/model_recordset.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets/model_recordsetproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets/model_soarecord.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets/model_srvrecord.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets/model_subresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets/model_txtrecord.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/zones/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/zones/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/zones/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/zones/id_dnszone.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/zones/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/zones/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/zones/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/zones/method_list_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/zones/method_listbyresourcegroup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/zones/method_update_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/zones/model_subresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/zones/model_zone.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/zones/model_zoneproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/zones/model_zoneupdate.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/zones/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/zones/version.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/authorizationruleseventhubs/README.md delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/authorizationruleseventhubs/model_authorizationrule.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/authorizationruleseventhubs/predicates.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/authorizationruleseventhubs/version.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/authorizationrulesnamespaces/README.md delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/authorizationrulesnamespaces/model_authorizationrule.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/authorizationrulesnamespaces/predicates.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/authorizationrulesnamespaces/version.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/checknameavailabilitydisasterrecoveryconfigs/README.md delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/checknameavailabilitydisasterrecoveryconfigs/version.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/consumergroups/README.md delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/consumergroups/method_createorupdate_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/consumergroups/method_delete_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/consumergroups/method_get_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/consumergroups/model_consumergroup.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/consumergroups/predicates.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/consumergroups/version.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/disasterrecoveryconfigs/README.md delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/disasterrecoveryconfigs/method_createorupdate_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/disasterrecoveryconfigs/method_delete_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/disasterrecoveryconfigs/method_get_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/disasterrecoveryconfigs/method_list_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/disasterrecoveryconfigs/model_armdisasterrecovery.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/disasterrecoveryconfigs/predicates.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/disasterrecoveryconfigs/version.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/eventhubs/README.md delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/eventhubs/method_createorupdate_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/eventhubs/method_delete_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/eventhubs/method_get_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/eventhubs/method_listbynamespace_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/eventhubs/model_authorizationrule.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/eventhubs/model_destinationproperties.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/eventhubs/model_eventhub.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/eventhubs/predicates.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/eventhubs/version.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2018-01-01-preview/eventhubsclusters/README.md delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2018-01-01-preview/eventhubsclusters/model_cluster.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2018-01-01-preview/eventhubsclusters/version.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2018-01-01-preview/networkrulesets/README.md delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2018-01-01-preview/networkrulesets/constants.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2018-01-01-preview/networkrulesets/model_networkruleset.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2018-01-01-preview/networkrulesets/model_networkrulesetproperties.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2018-01-01-preview/networkrulesets/model_nwrulesetiprules.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2018-01-01-preview/networkrulesets/version.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-01-01-preview/namespaces/README.md delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-01-01-preview/namespaces/method_get_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-01-01-preview/namespaces/method_list_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-01-01-preview/namespaces/method_listbyresourcegroup_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-01-01-preview/namespaces/method_update_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-01-01-preview/namespaces/model_ehnamespaceproperties.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-01-01-preview/namespaces/model_privateendpointconnection.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-01-01-preview/namespaces/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/authorizationruleseventhubs/README.md rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/authorizationruleseventhubs/client.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/authorizationruleseventhubs/constants.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/authorizationruleseventhubs/id_eventhub.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/authorizationruleseventhubs/id_eventhubauthorizationrule.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/authorizationruleseventhubs/method_eventhubscreateorupdateauthorizationrule_autorest.go (99%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/authorizationruleseventhubs/method_eventhubslistauthorizationrules_autorest.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/authorizationruleseventhubs/method_eventhubslistkeys_autorest.go (99%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/authorizationruleseventhubs/method_eventhubsregeneratekeys_autorest.go (99%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/authorizationruleseventhubs/model_accesskeys.go (100%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/authorizationruleseventhubs/model_authorizationrule.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/authorizationruleseventhubs/model_authorizationruleproperties.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/authorizationruleseventhubs/model_regenerateaccesskeyparameters.go (100%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/authorizationruleseventhubs/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/authorizationruleseventhubs/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/authorizationrulesnamespaces/README.md rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/authorizationrulesnamespaces/client.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/authorizationrulesnamespaces/constants.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/authorizationrulesnamespaces/id_authorizationrule.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/authorizationrulesnamespaces/id_namespace.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/authorizationrulesnamespaces/method_namespacescreateorupdateauthorizationrule_autorest.go (99%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/authorizationrulesnamespaces/method_namespacesdeleteauthorizationrule_autorest.go (99%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/authorizationrulesnamespaces/method_namespacesgetauthorizationrule_autorest.go (99%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/authorizationrulesnamespaces/method_namespaceslistauthorizationrules_autorest.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/authorizationrulesnamespaces/method_namespaceslistkeys_autorest.go (99%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/authorizationrulesnamespaces/method_namespacesregeneratekeys_autorest.go (99%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/authorizationrulesnamespaces/model_accesskeys.go (100%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/authorizationrulesnamespaces/model_authorizationrule.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/authorizationrulesnamespaces/model_authorizationruleproperties.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/authorizationrulesnamespaces/model_regenerateaccesskeyparameters.go (100%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/authorizationrulesnamespaces/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/authorizationrulesnamespaces/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/checknameavailabilitydisasterrecoveryconfigs/README.md rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/checknameavailabilitydisasterrecoveryconfigs/client.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/checknameavailabilitydisasterrecoveryconfigs/constants.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/checknameavailabilitydisasterrecoveryconfigs/id_namespace.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/checknameavailabilitydisasterrecoveryconfigs/method_disasterrecoveryconfigschecknameavailability_autorest.go (99%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/checknameavailabilitydisasterrecoveryconfigs/model_checknameavailabilityparameter.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/checknameavailabilitydisasterrecoveryconfigs/model_checknameavailabilityresult.go (100%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/checknameavailabilitydisasterrecoveryconfigs/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/consumergroups/README.md rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/consumergroups/client.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/consumergroups/id_consumergroup.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/consumergroups/id_eventhub.go (100%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/consumergroups/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/consumergroups/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/consumergroups/method_get_autorest.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/consumergroups/method_listbyeventhub_autorest.go (100%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/consumergroups/model_consumergroup.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/consumergroups/model_consumergroupproperties.go (100%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/consumergroups/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/consumergroups/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/disasterrecoveryconfigs/README.md rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/disasterrecoveryconfigs/client.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/disasterrecoveryconfigs/constants.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/disasterrecoveryconfigs/id_disasterrecoveryconfig.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/disasterrecoveryconfigs/id_namespace.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/disasterrecoveryconfigs/method_breakpairing_autorest.go (99%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/disasterrecoveryconfigs/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/disasterrecoveryconfigs/method_delete_autorest.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/disasterrecoveryconfigs/method_failover_autorest.go (99%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/disasterrecoveryconfigs/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/disasterrecoveryconfigs/method_list_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/disasterrecoveryconfigs/model_armdisasterrecovery.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/disasterrecoveryconfigs/model_armdisasterrecoveryproperties.go (100%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/disasterrecoveryconfigs/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/disasterrecoveryconfigs/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/eventhubs/README.md rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/eventhubs/client.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/eventhubs/constants.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/eventhubs/id_eventhub.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/eventhubs/id_eventhubauthorizationrule.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/eventhubs/id_namespace.go (100%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/eventhubs/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/eventhubs/method_delete_autorest.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/eventhubs/method_deleteauthorizationrule_autorest.go (99%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/eventhubs/method_get_autorest.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/eventhubs/method_getauthorizationrule_autorest.go (99%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/eventhubs/method_listbynamespace_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/eventhubs/model_authorizationrule.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/eventhubs/model_authorizationruleproperties.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/eventhubs/model_capturedescription.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/eventhubs/model_destination.go (100%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/eventhubs/model_destinationproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/eventhubs/model_eventhub.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2017-04-01 => 2021-11-01}/eventhubs/model_eventhubproperties.go (100%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/eventhubs/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/eventhubs/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/eventhubsclusters/README.md rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2018-01-01-preview => 2021-11-01}/eventhubsclusters/client.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2018-01-01-preview => 2021-11-01}/eventhubsclusters/constants.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2018-01-01-preview => 2021-11-01}/eventhubsclusters/id_cluster.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2018-01-01-preview => 2021-11-01}/eventhubsclusters/method_clusterscreateorupdate_autorest.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2018-01-01-preview => 2021-11-01}/eventhubsclusters/method_clustersdelete_autorest.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2018-01-01-preview => 2021-11-01}/eventhubsclusters/method_clustersget_autorest.go (99%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2018-01-01-preview => 2021-11-01}/eventhubsclusters/method_clusterslistbyresourcegroup_autorest.go (100%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/eventhubsclusters/method_clusterslistbysubscription_autorest.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2018-01-01-preview => 2021-11-01}/eventhubsclusters/method_clustersupdate_autorest.go (100%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/eventhubsclusters/model_cluster.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2018-01-01-preview => 2021-11-01}/eventhubsclusters/model_clusterproperties.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2018-01-01-preview => 2021-11-01}/eventhubsclusters/model_clustersku.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2018-01-01-preview => 2021-11-01}/eventhubsclusters/predicates.go (100%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/eventhubsclusters/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/namespaces/README.md rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2021-01-01-preview => 2021-11-01}/namespaces/client.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2021-01-01-preview => 2021-11-01}/namespaces/constants.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2021-01-01-preview => 2021-11-01}/namespaces/id_namespace.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2021-01-01-preview => 2021-11-01}/namespaces/method_createorupdate_autorest.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2021-01-01-preview => 2021-11-01}/namespaces/method_delete_autorest.go (100%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/namespaces/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/namespaces/method_list_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/namespaces/method_listbyresourcegroup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/namespaces/method_update_autorest.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2021-01-01-preview => 2021-11-01}/namespaces/model_connectionstate.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2021-01-01-preview => 2021-11-01}/namespaces/model_ehnamespace.go (100%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/namespaces/model_ehnamespaceproperties.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2021-01-01-preview => 2021-11-01}/namespaces/model_encryption.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2021-01-01-preview => 2021-11-01}/namespaces/model_keyvaultproperties.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2021-01-01-preview => 2021-11-01}/namespaces/model_privateendpoint.go (100%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/namespaces/model_privateendpointconnection.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2021-01-01-preview => 2021-11-01}/namespaces/model_privateendpointconnectionproperties.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2021-01-01-preview => 2021-11-01}/namespaces/model_sku.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2021-01-01-preview => 2021-11-01}/namespaces/model_userassignedidentityproperties.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2021-01-01-preview => 2021-11-01}/namespaces/predicates.go (100%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/namespaces/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/networkrulesets/README.md rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2018-01-01-preview => 2021-11-01}/networkrulesets/client.go (100%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/networkrulesets/constants.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2018-01-01-preview => 2021-11-01}/networkrulesets/id_namespace.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2018-01-01-preview => 2021-11-01}/networkrulesets/method_namespacescreateorupdatenetworkruleset_autorest.go (99%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2018-01-01-preview => 2021-11-01}/networkrulesets/method_namespacesgetnetworkruleset_autorest.go (99%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/networkrulesets/method_namespaceslistnetworkruleset_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/networkrulesets/model_networkruleset.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/networkrulesets/model_networkrulesetlistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/networkrulesets/model_networkrulesetproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/networkrulesets/model_nwrulesetiprules.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2018-01-01-preview => 2021-11-01}/networkrulesets/model_nwrulesetvirtualnetworkrules.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/{2018-01-01-preview => 2021-11-01}/networkrulesets/model_subnet.go (100%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/networkrulesets/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/schemaregistry/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/schemaregistry/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/schemaregistry/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/schemaregistry/id_namespace.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/schemaregistry/id_schemagroup.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/schemaregistry/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/schemaregistry/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/schemaregistry/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/schemaregistry/method_listbynamespace_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/schemaregistry/model_schemagroup.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/schemaregistry/model_schemagroupproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/schemaregistry/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/schemaregistry/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2022-01-01-preview/namespaces/README.md rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/{servicebus/2021-06-01-preview => eventhub/2022-01-01-preview}/namespaces/client.go (100%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2022-01-01-preview/namespaces/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2022-01-01-preview/namespaces/id_namespace.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2022-01-01-preview/namespaces/method_createorupdate_autorest.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/{servicebus/2021-06-01-preview => eventhub/2022-01-01-preview}/namespaces/method_delete_autorest.go (100%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2022-01-01-preview/namespaces/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2022-01-01-preview/namespaces/method_list_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2022-01-01-preview/namespaces/method_listbyresourcegroup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2022-01-01-preview/namespaces/method_update_autorest.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/{servicebus/2021-06-01-preview => eventhub/2022-01-01-preview}/namespaces/model_connectionstate.go (100%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2022-01-01-preview/namespaces/model_ehnamespace.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2022-01-01-preview/namespaces/model_ehnamespaceproperties.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/{servicebus/2021-06-01-preview => eventhub/2022-01-01-preview}/namespaces/model_encryption.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/{servicebus/2021-06-01-preview => eventhub/2022-01-01-preview}/namespaces/model_keyvaultproperties.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/{servicebus/2021-06-01-preview => eventhub/2022-01-01-preview}/namespaces/model_privateendpoint.go (100%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2022-01-01-preview/namespaces/model_privateendpointconnection.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/{servicebus/2021-06-01-preview => eventhub/2022-01-01-preview}/namespaces/model_privateendpointconnectionproperties.go (100%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2022-01-01-preview/namespaces/model_sku.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/{servicebus/2021-06-01-preview => eventhub/2022-01-01-preview}/namespaces/model_userassignedidentityproperties.go (100%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2022-01-01-preview/namespaces/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2022-01-01-preview/namespaces/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionendpoints/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionendpoints/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionendpoints/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionendpoints/id_datacollectionendpoint.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionendpoints/method_create_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionendpoints/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionendpoints/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionendpoints/method_listbyresourcegroup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionendpoints/method_listbysubscription_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionendpoints/method_update_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionendpoints/model_configurationaccessendpointspec.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionendpoints/model_datacollectionendpoint.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionendpoints/model_datacollectionendpointresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionendpoints/model_logsingestionendpointspec.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionendpoints/model_networkruleset.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionendpoints/model_resourceforupdate.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionendpoints/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionendpoints/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionrules/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionrules/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionrules/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionrules/id_datacollectionrule.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionrules/method_create_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionrules/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionrules/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionrules/method_listbyresourcegroup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionrules/method_listbysubscription_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionrules/method_update_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionrules/model_azuremonitormetricsdestination.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionrules/model_datacollectionrule.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionrules/model_datacollectionruleresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionrules/model_dataflow.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionrules/model_datasourcesspec.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionrules/model_destinationsspec.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionrules/model_extensiondatasource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionrules/model_loganalyticsdestination.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionrules/model_perfcounterdatasource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionrules/model_resourceforupdate.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionrules/model_syslogdatasource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionrules/model_windowseventlogdatasource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionrules/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionrules/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-05-01-preview/diagnosticsettings/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-05-01-preview/diagnosticsettings/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-05-01-preview/diagnosticsettings/id_scopeddiagnosticsetting.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-05-01-preview/diagnosticsettings/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-05-01-preview/diagnosticsettings/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-05-01-preview/diagnosticsettings/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-05-01-preview/diagnosticsettings/method_list_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-05-01-preview/diagnosticsettings/model_diagnosticsettings.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-05-01-preview/diagnosticsettings/model_diagnosticsettingsresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-05-01-preview/diagnosticsettings/model_diagnosticsettingsresourcecollection.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-05-01-preview/diagnosticsettings/model_logsettings.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-05-01-preview/diagnosticsettings/model_metricsettings.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-05-01-preview/diagnosticsettings/model_retentionpolicy.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-05-01-preview/diagnosticsettings/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-05-01-preview/diagnosticsettingscategories/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-05-01-preview/diagnosticsettingscategories/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-05-01-preview/diagnosticsettingscategories/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-05-01-preview/diagnosticsettingscategories/id_scopeddiagnosticsettingscategories.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-05-01-preview/diagnosticsettingscategories/method_diagnosticsettingscategoryget_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-05-01-preview/diagnosticsettingscategories/method_diagnosticsettingscategorylist_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-05-01-preview/diagnosticsettingscategories/model_diagnosticsettingscategory.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-05-01-preview/diagnosticsettingscategories/model_diagnosticsettingscategoryresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-05-01-preview/diagnosticsettingscategories/model_diagnosticsettingscategoryresourcecollection.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-05-01-preview/diagnosticsettingscategories/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-08-01/scheduledqueryrules/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-08-01/scheduledqueryrules/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-08-01/scheduledqueryrules/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-08-01/scheduledqueryrules/id_scheduledqueryrule.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-08-01/scheduledqueryrules/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-08-01/scheduledqueryrules/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-08-01/scheduledqueryrules/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-08-01/scheduledqueryrules/method_listbyresourcegroup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-08-01/scheduledqueryrules/method_listbysubscription_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-08-01/scheduledqueryrules/method_update_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-08-01/scheduledqueryrules/model_actions.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-08-01/scheduledqueryrules/model_condition.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-08-01/scheduledqueryrules/model_conditionfailingperiods.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-08-01/scheduledqueryrules/model_dimension.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-08-01/scheduledqueryrules/model_scheduledqueryrulecriteria.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-08-01/scheduledqueryrules/model_scheduledqueryruleproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-08-01/scheduledqueryrules/model_scheduledqueryruleresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-08-01/scheduledqueryrules/model_scheduledqueryruleresourcepatch.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-08-01/scheduledqueryrules/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-08-01/scheduledqueryrules/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/configurationassignments/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/configurationassignments/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/configurationassignments/id_configurationassignment.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/configurationassignments/id_provider.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/configurationassignments/id_providers2configurationassignment.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/configurationassignments/id_resourcegroupprovider.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/configurationassignments/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/configurationassignments/method_createorupdateparent_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/configurationassignments/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/configurationassignments/method_deleteparent_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/configurationassignments/method_list_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/configurationassignments/method_listparent_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/configurationassignments/model_configurationassignment.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/configurationassignments/model_configurationassignmentproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/configurationassignments/model_listconfigurationassignmentsresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/configurationassignments/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/maintenanceconfigurations/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/maintenanceconfigurations/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/maintenanceconfigurations/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/maintenanceconfigurations/id_maintenanceconfiguration.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/maintenanceconfigurations/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/maintenanceconfigurations/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/maintenanceconfigurations/method_forresourcegrouplist_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/maintenanceconfigurations/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/maintenanceconfigurations/method_list_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/maintenanceconfigurations/method_update_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/maintenanceconfigurations/model_listmaintenanceconfigurationsresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/maintenanceconfigurations/model_maintenanceconfiguration.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/maintenanceconfigurations/model_maintenanceconfigurationproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/maintenanceconfigurations/model_maintenancewindow.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/maintenanceconfigurations/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/publicmaintenanceconfigurations/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/publicmaintenanceconfigurations/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/publicmaintenanceconfigurations/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/publicmaintenanceconfigurations/id_publicmaintenanceconfiguration.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/publicmaintenanceconfigurations/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/publicmaintenanceconfigurations/method_list_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/publicmaintenanceconfigurations/model_listmaintenanceconfigurationsresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/publicmaintenanceconfigurations/model_maintenanceconfiguration.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/publicmaintenanceconfigurations/model_maintenanceconfigurationproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/publicmaintenanceconfigurations/model_maintenancewindow.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/publicmaintenanceconfigurations/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/managedidentity/2018-11-30/managedidentities/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/managedidentity/2018-11-30/managedidentities/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/managedidentity/2018-11-30/managedidentities/method_systemassignedidentitiesgetbyscope_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/managedidentity/2018-11-30/managedidentities/method_userassignedidentitiescreateorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/managedidentity/2018-11-30/managedidentities/method_userassignedidentitiesdelete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/managedidentity/2018-11-30/managedidentities/method_userassignedidentitiesget_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/managedidentity/2018-11-30/managedidentities/method_userassignedidentitieslistbyresourcegroup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/managedidentity/2018-11-30/managedidentities/method_userassignedidentitieslistbysubscription_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/managedidentity/2018-11-30/managedidentities/method_userassignedidentitiesupdate_autorest.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/managedidentity/2018-11-30/{managedidentity => managedidentities}/model_identity.go (95%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/managedidentity/2018-11-30/{managedidentity => managedidentities}/model_identityupdate.go (95%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/managedidentity/2018-11-30/{managedidentity => managedidentities}/model_systemassignedidentity.go (95%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/managedidentity/2018-11-30/{managedidentity => managedidentities}/model_systemassignedidentityproperties.go (94%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/managedidentity/2018-11-30/managedidentities/model_userassignedidentityproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/managedidentity/2018-11-30/managedidentities/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/managedidentity/2018-11-30/managedidentities/version.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/managedidentity/2018-11-30/managedidentity/README.md delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/managedidentity/2018-11-30/managedidentity/client.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/managedidentity/2018-11-30/managedidentity/method_systemassignedidentitiesgetbyscope_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/managedidentity/2018-11-30/managedidentity/method_userassignedidentitiescreateorupdate_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/managedidentity/2018-11-30/managedidentity/method_userassignedidentitiesdelete_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/managedidentity/2018-11-30/managedidentity/method_userassignedidentitiesget_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/managedidentity/2018-11-30/managedidentity/method_userassignedidentitieslistbyresourcegroup_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/managedidentity/2018-11-30/managedidentity/method_userassignedidentitieslistbysubscription_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/managedidentity/2018-11-30/managedidentity/method_userassignedidentitiesupdate_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/managedidentity/2018-11-30/managedidentity/model_userassignedidentityproperties.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/managedidentity/2018-11-30/managedidentity/predicates.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/managedidentity/2018-11-30/managedidentity/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/configurations/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/configurations/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/configurations/id_configuration.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/configurations/id_server.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/configurations/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/configurations/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/configurations/method_listbyserver_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/configurations/model_configuration.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/configurations/model_configurationlistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/configurations/model_configurationproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/configurations/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/databases/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/databases/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/databases/id_database.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/databases/id_server.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/databases/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/databases/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/databases/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/databases/method_listbyserver_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/databases/model_database.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/databases/model_databaselistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/databases/model_databaseproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/databases/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/firewallrules/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/firewallrules/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/firewallrules/id_firewallrule.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/firewallrules/id_server.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/firewallrules/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/firewallrules/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/firewallrules/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/firewallrules/method_listbyserver_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/firewallrules/model_firewallrule.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/firewallrules/model_firewallrulelistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/firewallrules/model_firewallruleproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/firewallrules/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers/id_server.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers/method_create_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers/method_list_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers/method_listbyresourcegroup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers/method_update_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers/model_privateendpointproperty.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers/model_server.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers/model_serverforcreate.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers/model_serverlistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers/model_serverprivateendpointconnection.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers/model_serverprivateendpointconnectionproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers/model_serverprivatelinkserviceconnectionstateproperty.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers/model_serverproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers/model_serverpropertiesforcreate.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers/model_serverpropertiesfordefaultcreate.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers/model_serverpropertiesforgeorestore.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers/model_serverpropertiesforreplica.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers/model_serverpropertiesforrestore.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers/model_serverupdateparameters.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers/model_serverupdateparametersproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers/model_sku.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers/model_storageprofile.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/virtualnetworkrules/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/virtualnetworkrules/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/virtualnetworkrules/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/virtualnetworkrules/id_server.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/virtualnetworkrules/id_virtualnetworkrule.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/virtualnetworkrules/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/virtualnetworkrules/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/virtualnetworkrules/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/virtualnetworkrules/method_listbyserver_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/virtualnetworkrules/model_virtualnetworkrule.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/virtualnetworkrules/model_virtualnetworkruleproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/virtualnetworkrules/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/virtualnetworkrules/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2019-09-01/querypackqueries/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2019-09-01/querypackqueries/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2019-09-01/querypackqueries/id_queries.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2019-09-01/querypackqueries/id_querypack.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2019-09-01/querypackqueries/method_queriesdelete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2019-09-01/querypackqueries/method_queriesget_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2019-09-01/querypackqueries/method_querieslist_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2019-09-01/querypackqueries/method_queriesput_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2019-09-01/querypackqueries/method_queriessearch_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2019-09-01/querypackqueries/method_queriesupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2019-09-01/querypackqueries/model_loganalyticsquerypackquery.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2019-09-01/querypackqueries/model_loganalyticsquerypackqueryproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2019-09-01/querypackqueries/model_loganalyticsquerypackquerypropertiesrelated.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2019-09-01/querypackqueries/model_loganalyticsquerypackquerysearchproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2019-09-01/querypackqueries/model_loganalyticsquerypackquerysearchpropertiesrelated.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2019-09-01/querypackqueries/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2019-09-01/querypackqueries/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2019-09-01/querypacks/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2019-09-01/querypacks/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2019-09-01/querypacks/id_querypack.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2019-09-01/querypacks/method_querypackscreateorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2019-09-01/querypacks/method_querypacksdelete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2019-09-01/querypacks/method_querypacksget_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2019-09-01/querypacks/method_querypackslist_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2019-09-01/querypacks/method_querypackslistbyresourcegroup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2019-09-01/querypacks/method_querypacksupdatetags_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2019-09-01/querypacks/model_loganalyticsquerypack.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2019-09-01/querypacks/model_loganalyticsquerypackproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2019-09-01/querypacks/model_tagsresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2019-09-01/querypacks/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2019-09-01/querypacks/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/clusters/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/clusters/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/clusters/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/clusters/id_cluster.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/clusters/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/clusters/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/clusters/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/clusters/method_list_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/clusters/method_listbyresourcegroup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/clusters/method_update_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/clusters/model_cluster.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/clusters/model_clusterpatch.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/clusters/model_clusterpatchproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/clusters/model_clusterproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/clusters/model_clustersku.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/clusters/model_keyvaultproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/clusters/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/clusters/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/dataexport/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/dataexport/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/dataexport/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/dataexport/id_dataexport.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/dataexport/id_workspace.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/dataexport/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/dataexport/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/dataexport/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/dataexport/method_listbyworkspace_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/dataexport/model_dataexport.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/dataexport/model_dataexportlistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/dataexport/model_dataexportproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/dataexport/model_destination.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/dataexport/model_destinationmetadata.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/dataexport/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/datasources/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/datasources/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/datasources/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/datasources/id_datasource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/datasources/id_workspace.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/datasources/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/datasources/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/datasources/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/datasources/method_listbyworkspace_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/datasources/model_datasource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/datasources/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/datasources/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/linkedservices/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/linkedservices/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/linkedservices/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/linkedservices/id_linkedservice.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/linkedservices/id_workspace.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/linkedservices/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/linkedservices/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/linkedservices/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/linkedservices/method_listbyworkspace_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/linkedservices/model_linkedservice.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/linkedservices/model_linkedservicelistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/linkedservices/model_linkedserviceproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/linkedservices/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/linkedstorageaccounts/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/linkedstorageaccounts/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/linkedstorageaccounts/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/linkedstorageaccounts/id_datasourcetype.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/linkedstorageaccounts/id_workspace.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/linkedstorageaccounts/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/linkedstorageaccounts/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/linkedstorageaccounts/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/linkedstorageaccounts/method_listbyworkspace_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/linkedstorageaccounts/model_linkedstorageaccountslistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/linkedstorageaccounts/model_linkedstorageaccountsproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/linkedstorageaccounts/model_linkedstorageaccountsresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/linkedstorageaccounts/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/savedsearches/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/savedsearches/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/savedsearches/id_savedsearche.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/savedsearches/id_workspace.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/savedsearches/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/savedsearches/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/savedsearches/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/savedsearches/method_listbyworkspace_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/savedsearches/model_savedsearch.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/savedsearches/model_savedsearcheslistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/savedsearches/model_savedsearchproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/savedsearches/model_tag.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/savedsearches/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/storageinsights/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/storageinsights/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/storageinsights/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/storageinsights/id_storageinsightconfig.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/storageinsights/id_workspace.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/storageinsights/method_storageinsightconfigscreateorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/storageinsights/method_storageinsightconfigsdelete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/storageinsights/method_storageinsightconfigsget_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/storageinsights/method_storageinsightconfigslistbyworkspace_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/storageinsights/model_storageaccount.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/storageinsights/model_storageinsight.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/storageinsights/model_storageinsightproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/storageinsights/model_storageinsightstatus.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/storageinsights/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/storageinsights/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/id_gateway.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/id_intelligencepack.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/id_operation.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/id_workspace.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/method_gatewaysdelete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/method_intelligencepacksdisable_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/method_intelligencepacksenable_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/method_intelligencepackslist_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/method_list_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/method_listbyresourcegroup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/method_managementgroupslist_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/method_schemaget_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/method_sharedkeysgetsharedkeys_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/method_sharedkeysregenerate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/method_update_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/method_usageslist_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/method_workspacepurgegetpurgestatus_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/method_workspacepurgepurge_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/model_coresummary.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/model_intelligencepack.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/model_managementgroup.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/model_managementgroupproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/model_metricname.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/model_privatelinkscopedresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/model_searchgetschemaresponse.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/model_searchmetadata.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/model_searchmetadataschema.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/model_searchschemavalue.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/model_searchsort.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/model_sharedkeys.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/model_usagemetric.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/model_workspace.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/model_workspacecapping.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/model_workspacelistmanagementgroupsresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/model_workspacelistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/model_workspacelistusagesresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/model_workspacepatch.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/model_workspaceproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/model_workspacepurgebody.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/model_workspacepurgebodyfilters.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/model_workspacepurgeresponse.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/model_workspacepurgestatusresponse.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/model_workspacesku.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationsmanagement/2015-11-01-preview/solution/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationsmanagement/2015-11-01-preview/solution/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationsmanagement/2015-11-01-preview/solution/id_solution.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationsmanagement/2015-11-01-preview/solution/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationsmanagement/2015-11-01-preview/solution/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationsmanagement/2015-11-01-preview/solution/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationsmanagement/2015-11-01-preview/solution/method_listbyresourcegroup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationsmanagement/2015-11-01-preview/solution/method_listbysubscription_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationsmanagement/2015-11-01-preview/solution/method_update_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationsmanagement/2015-11-01-preview/solution/model_solution.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationsmanagement/2015-11-01-preview/solution/model_solutionpatch.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationsmanagement/2015-11-01-preview/solution/model_solutionplan.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationsmanagement/2015-11-01-preview/solution/model_solutionproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationsmanagement/2015-11-01-preview/solution/model_solutionpropertieslist.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/operationsmanagement/2015-11-01-preview/solution/version.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights/README.md delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights/client.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights/constants.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights/method_remediationscancelatmanagementgroup_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights/method_remediationscancelatresource_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights/method_remediationscancelatresourcegroup_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights/method_remediationscancelatsubscription_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights/method_remediationscreateorupdateatmanagementgroup_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights/method_remediationscreateorupdateatresource_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights/method_remediationscreateorupdateatresourcegroup_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights/method_remediationscreateorupdateatsubscription_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights/method_remediationsdeleteatmanagementgroup_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights/method_remediationsdeleteatresource_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights/method_remediationsdeleteatresourcegroup_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights/method_remediationsdeleteatsubscription_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights/method_remediationsgetatmanagementgroup_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights/method_remediationsgetatresource_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights/method_remediationsgetatresourcegroup_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights/method_remediationsgetatsubscription_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights/method_remediationslistdeploymentsatmanagementgroup_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights/method_remediationslistdeploymentsatresource_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights/method_remediationslistdeploymentsatresourcegroup_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights/method_remediationslistdeploymentsatsubscription_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights/method_remediationslistformanagementgroup_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights/method_remediationslistforresource_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights/method_remediationslistforresourcegroup_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights/method_remediationslistforsubscription_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights/predicates.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations/constants.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/{policyinsights => remediations}/id_managementgroup.go (99%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/{policyinsights => remediations}/id_providerremediation.go (99%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/{policyinsights => remediations}/id_providers2remediation.go (99%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/{policyinsights => remediations}/id_remediation.go (99%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/{policyinsights => remediations}/id_scopedremediation.go (99%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations/method_remediationscancelatmanagementgroup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations/method_remediationscancelatresource_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations/method_remediationscancelatresourcegroup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations/method_remediationscancelatsubscription_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations/method_remediationscreateorupdateatmanagementgroup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations/method_remediationscreateorupdateatresource_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations/method_remediationscreateorupdateatresourcegroup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations/method_remediationscreateorupdateatsubscription_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations/method_remediationsdeleteatmanagementgroup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations/method_remediationsdeleteatresource_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations/method_remediationsdeleteatresourcegroup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations/method_remediationsdeleteatsubscription_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations/method_remediationsgetatmanagementgroup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations/method_remediationsgetatresource_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations/method_remediationsgetatresourcegroup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations/method_remediationsgetatsubscription_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations/method_remediationslistdeploymentsatmanagementgroup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations/method_remediationslistdeploymentsatresource_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations/method_remediationslistdeploymentsatresourcegroup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations/method_remediationslistdeploymentsatsubscription_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations/method_remediationslistformanagementgroup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations/method_remediationslistforresource_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations/method_remediationslistforresourcegroup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations/method_remediationslistforsubscription_autorest.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/{policyinsights => remediations}/model_errordefinition.go (95%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/{policyinsights => remediations}/model_remediation.go (96%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/{policyinsights => remediations}/model_remediationdeployment.go (98%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/{policyinsights => remediations}/model_remediationdeploymentsummary.go (94%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/{policyinsights => remediations}/model_remediationfilters.go (91%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/{policyinsights => remediations}/model_remediationproperties.go (99%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/{policyinsights => remediations}/model_remediationpropertiesfailurethreshold.go (91%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/{policyinsights => remediations}/model_typederrorinfo.go (92%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/configurations/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/configurations/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/configurations/id_configuration.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/configurations/id_server.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/configurations/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/configurations/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/configurations/method_listbyserver_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/configurations/model_configuration.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/configurations/model_configurationlistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/configurations/model_configurationproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/configurations/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/databases/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/databases/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/databases/id_database.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/databases/id_server.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/databases/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/databases/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/databases/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/databases/method_listbyserver_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/databases/model_database.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/databases/model_databaselistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/databases/model_databaseproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/databases/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/firewallrules/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/firewallrules/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/firewallrules/id_firewallrule.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/firewallrules/id_server.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/firewallrules/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/firewallrules/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/firewallrules/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/firewallrules/method_listbyserver_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/firewallrules/model_firewallrule.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/firewallrules/model_firewallrulelistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/firewallrules/model_firewallruleproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/firewallrules/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/replicas/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/replicas/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/replicas/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/replicas/id_server.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/replicas/method_listbyserver_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/replicas/model_privateendpointproperty.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/replicas/model_server.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/replicas/model_serverlistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/replicas/model_serverprivateendpointconnection.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/replicas/model_serverprivateendpointconnectionproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/replicas/model_serverprivatelinkserviceconnectionstateproperty.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/replicas/model_serverproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/replicas/model_sku.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/replicas/model_storageprofile.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/replicas/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/serveradministrators/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/serveradministrators/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/serveradministrators/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/serveradministrators/id_server.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/serveradministrators/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/serveradministrators/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/serveradministrators/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/serveradministrators/method_list_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/serveradministrators/model_serveradministratorproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/serveradministrators/model_serveradministratorresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/serveradministrators/model_serveradministratorresourcelistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/serveradministrators/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers/id_server.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers/method_create_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers/method_list_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers/method_listbyresourcegroup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers/method_update_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers/model_privateendpointproperty.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers/model_server.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers/model_serverforcreate.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers/model_serverlistresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers/model_serverprivateendpointconnection.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers/model_serverprivateendpointconnectionproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers/model_serverprivatelinkserviceconnectionstateproperty.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers/model_serverproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers/model_serverpropertiesforcreate.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers/model_serverpropertiesfordefaultcreate.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers/model_serverpropertiesforgeorestore.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers/model_serverpropertiesforreplica.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers/model_serverpropertiesforrestore.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers/model_serverupdateparameters.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers/model_serverupdateparametersproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers/model_sku.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers/model_storageprofile.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/serversecurityalertpolicies/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/serversecurityalertpolicies/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/serversecurityalertpolicies/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/serversecurityalertpolicies/id_server.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/serversecurityalertpolicies/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/serversecurityalertpolicies/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/serversecurityalertpolicies/method_listbyserver_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/serversecurityalertpolicies/model_securityalertpolicyproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/serversecurityalertpolicies/model_serversecurityalertpolicy.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/serversecurityalertpolicies/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/serversecurityalertpolicies/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/virtualnetworkrules/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/virtualnetworkrules/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/virtualnetworkrules/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/virtualnetworkrules/id_server.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/virtualnetworkrules/id_virtualnetworkrule.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/virtualnetworkrules/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/virtualnetworkrules/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/virtualnetworkrules/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/virtualnetworkrules/method_listbyserver_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/virtualnetworkrules/model_virtualnetworkrule.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/virtualnetworkrules/model_virtualnetworkruleproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/virtualnetworkrules/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/virtualnetworkrules/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2020-01-01/serverkeys/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2020-01-01/serverkeys/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2020-01-01/serverkeys/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2020-01-01/serverkeys/id_key.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2020-01-01/serverkeys/id_server.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2020-01-01/serverkeys/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2020-01-01/serverkeys/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2020-01-01/serverkeys/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2020-01-01/serverkeys/method_list_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2020-01-01/serverkeys/model_serverkey.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2020-01-01/serverkeys/model_serverkeyproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2020-01-01/serverkeys/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2020-01-01/serverkeys/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/configurations/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/configurations/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/configurations/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/configurations/id_configuration.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/configurations/id_flexibleserver.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/configurations/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/configurations/method_listbyserver_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/configurations/method_put_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/configurations/method_update_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/configurations/model_configuration.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/configurations/model_configurationproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/configurations/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/configurations/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/databases/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/databases/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/databases/id_database.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/databases/id_flexibleserver.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/databases/method_create_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/databases/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/databases/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/databases/method_listbyserver_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/databases/model_database.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/databases/model_databaseproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/databases/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/databases/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/firewallrules/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/firewallrules/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/firewallrules/id_firewallrule.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/firewallrules/id_flexibleserver.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/firewallrules/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/firewallrules/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/firewallrules/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/firewallrules/method_listbyserver_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/firewallrules/model_firewallrule.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/firewallrules/model_firewallruleproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/firewallrules/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/firewallrules/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/serverrestart/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/serverrestart/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/serverrestart/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/serverrestart/id_flexibleserver.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/serverrestart/method_serversrestart_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/serverrestart/model_restartparameter.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/serverrestart/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/servers/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/servers/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/servers/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/servers/id_flexibleserver.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/servers/method_create_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/servers/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/servers/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/servers/method_list_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/servers/method_listbyresourcegroup_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/servers/method_update_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/servers/model_backup.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/servers/model_highavailability.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/servers/model_maintenancewindow.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/servers/model_network.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/servers/model_server.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/servers/model_serverforupdate.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/servers/model_serverproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/servers/model_serverpropertiesforupdate.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/servers/model_sku.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/servers/model_storage.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/servers/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/servers/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/search/2020-08-01/sharedprivatelinkresources/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/search/2020-08-01/sharedprivatelinkresources/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/search/2020-08-01/sharedprivatelinkresources/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/search/2020-08-01/sharedprivatelinkresources/id_searchservice.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/search/2020-08-01/sharedprivatelinkresources/id_sharedprivatelinkresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/search/2020-08-01/sharedprivatelinkresources/method_createorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/search/2020-08-01/sharedprivatelinkresources/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/search/2020-08-01/sharedprivatelinkresources/method_get_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/search/2020-08-01/sharedprivatelinkresources/method_listbyservice_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/search/2020-08-01/sharedprivatelinkresources/model_sharedprivatelinkresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/search/2020-08-01/sharedprivatelinkresources/model_sharedprivatelinkresourceproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/search/2020-08-01/sharedprivatelinkresources/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/search/2020-08-01/sharedprivatelinkresources/version.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/2021-06-01-preview/namespaces/README.md delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/2021-06-01-preview/namespaces/constants.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/2021-06-01-preview/namespaces/method_checknameavailability_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/2021-06-01-preview/namespaces/method_get_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/2021-06-01-preview/namespaces/method_list_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/2021-06-01-preview/namespaces/method_listbyresourcegroup_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/2021-06-01-preview/namespaces/method_update_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/2021-06-01-preview/namespaces/model_networkruleset.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/2021-06-01-preview/namespaces/model_networkrulesetproperties.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/2021-06-01-preview/namespaces/model_nwrulesetiprules.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/2021-06-01-preview/namespaces/model_privateendpointconnection.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/2021-06-01-preview/namespaces/predicates.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/2021-06-01-preview/namespaces/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/2022-01-01-preview/namespaces/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/2022-01-01-preview/namespaces/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/2022-01-01-preview/namespaces/constants.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/{2021-06-01-preview => 2022-01-01-preview}/namespaces/id_namespace.go (100%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/2022-01-01-preview/namespaces/method_checknameavailability_autorest.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/{2021-06-01-preview => 2022-01-01-preview}/namespaces/method_createorupdate_autorest.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/{2021-06-01-preview => 2022-01-01-preview}/namespaces/method_createorupdatenetworkruleset_autorest.go (99%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/2022-01-01-preview/namespaces/method_delete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/2022-01-01-preview/namespaces/method_get_autorest.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/{2021-06-01-preview => 2022-01-01-preview}/namespaces/method_getnetworkruleset_autorest.go (99%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/2022-01-01-preview/namespaces/method_list_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/2022-01-01-preview/namespaces/method_listbyresourcegroup_autorest.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/{2021-06-01-preview => 2022-01-01-preview}/namespaces/method_listnetworkrulesets_autorest.go (100%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/2022-01-01-preview/namespaces/method_update_autorest.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/{2021-06-01-preview => 2022-01-01-preview}/namespaces/model_checknameavailability.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/{2021-06-01-preview => 2022-01-01-preview}/namespaces/model_checknameavailabilityresult.go (100%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/2022-01-01-preview/namespaces/model_connectionstate.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/2022-01-01-preview/namespaces/model_encryption.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/2022-01-01-preview/namespaces/model_keyvaultproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/2022-01-01-preview/namespaces/model_networkruleset.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/2022-01-01-preview/namespaces/model_networkrulesetproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/2022-01-01-preview/namespaces/model_nwrulesetiprules.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/{2021-06-01-preview => 2022-01-01-preview}/namespaces/model_nwrulesetvirtualnetworkrules.go (100%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/2022-01-01-preview/namespaces/model_privateendpoint.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/2022-01-01-preview/namespaces/model_privateendpointconnection.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/2022-01-01-preview/namespaces/model_privateendpointconnectionproperties.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/{2021-06-01-preview => 2022-01-01-preview}/namespaces/model_sbnamespace.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/{2021-06-01-preview => 2022-01-01-preview}/namespaces/model_sbnamespaceproperties.go (87%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/{2021-06-01-preview => 2022-01-01-preview}/namespaces/model_sbnamespaceupdateparameters.go (92%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/2022-01-01-preview/namespaces/model_sbnamespaceupdateproperties.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/{2021-06-01-preview => 2022-01-01-preview}/namespaces/model_sbsku.go (100%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/{2021-06-01-preview => 2022-01-01-preview}/namespaces/model_subnet.go (100%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/2022-01-01-preview/namespaces/model_userassignedidentityproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/2022-01-01-preview/namespaces/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicebus/2022-01-01-preview/namespaces/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links/id_scopedlinker.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links/method_linkerdelete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links/method_linkerlistconfigurations_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links/method_linkerupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links/method_linkervalidate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links/model_authinfobase.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links/model_azurekeyvaultproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links/model_azureresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links/model_azureresourcepropertiesbase.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links/model_confluentbootstrapserver.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links/model_confluentschemaregistry.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links/model_keyvaultsecretreferencesecretinfo.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links/model_keyvaultsecreturisecretinfo.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links/model_linkerpatch.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links/model_linkerproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links/model_linkerresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links/model_secretauthinfo.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links/model_secretinfobase.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links/model_secretstore.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links/model_serviceprincipalcertificateauthinfo.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links/model_serviceprincipalsecretauthinfo.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links/model_sourceconfiguration.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links/model_sourceconfigurationresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links/model_systemassignedidentityauthinfo.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links/model_targetservicebase.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links/model_userassignedidentityauthinfo.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links/model_validateoperationresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links/model_validateresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links/model_validationresultitem.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links/model_valuesecretinfo.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links/model_vnetsolution.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/servicelinker/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/servicelinker/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/servicelinker/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/servicelinker/id_scopedlinker.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/servicelinker/method_linkercreateorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/servicelinker/method_linkerget_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/servicelinker/method_linkerlist_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/servicelinker/model_authinfobase.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/servicelinker/model_azurekeyvaultproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/servicelinker/model_azureresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/servicelinker/model_azureresourcepropertiesbase.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/servicelinker/model_confluentbootstrapserver.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/servicelinker/model_confluentschemaregistry.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/servicelinker/model_keyvaultsecretreferencesecretinfo.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/servicelinker/model_keyvaultsecreturisecretinfo.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/servicelinker/model_linkerproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/servicelinker/model_linkerresource.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/servicelinker/model_secretauthinfo.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/servicelinker/model_secretinfobase.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/servicelinker/model_secretstore.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/servicelinker/model_serviceprincipalcertificateauthinfo.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/servicelinker/model_serviceprincipalsecretauthinfo.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/servicelinker/model_systemassignedidentityauthinfo.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/servicelinker/model_targetservicebase.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/servicelinker/model_userassignedidentityauthinfo.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/servicelinker/model_valuesecretinfo.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/servicelinker/model_vnetsolution.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/servicelinker/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/servicelinker/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/edgemodules/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/edgemodules/client.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/{videoanalyzer => edgemodules}/id_edgemodule.go (99%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/edgemodules/id_videoanalyzer.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/edgemodules/method_edgemodulescreateorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/edgemodules/method_edgemodulesdelete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/edgemodules/method_edgemodulesget_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/edgemodules/method_edgemoduleslist_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/edgemodules/method_edgemoduleslistprovisioningtoken_autorest.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/{videoanalyzer => edgemodules}/model_edgemoduleentity.go (96%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/{videoanalyzer => edgemodules}/model_edgemoduleproperties.go (91%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/{videoanalyzer => edgemodules}/model_edgemoduleprovisioningtoken.go (97%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/{videoanalyzer => edgemodules}/model_listprovisioningtokeninput.go (96%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/edgemodules/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/edgemodules/version.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/README.md delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/client.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/constants.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/id_accesspolicies.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/id_location.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/id_video.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/id_videoanalyzer.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/method_accesspoliciescreateorupdate_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/method_accesspoliciesdelete_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/method_accesspoliciesget_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/method_accesspolicieslist_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/method_accesspoliciesupdate_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/method_edgemodulescreateorupdate_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/method_edgemodulesdelete_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/method_edgemodulesget_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/method_edgemoduleslist_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/method_edgemoduleslistprovisioningtoken_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/method_locationschecknameavailability_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/method_videoanalyzerscreateorupdate_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/method_videoanalyzersdelete_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/method_videoanalyzersget_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/method_videoanalyzerslist_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/method_videoanalyzerslistbysubscription_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/method_videoanalyzerssyncstoragekeys_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/method_videoanalyzersupdate_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/method_videoscreateorupdate_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/method_videosdelete_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/method_videosget_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/method_videoslist_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/method_videosliststreamingtoken_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/method_videosupdate_autorest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/model_accesspolicyentity.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/model_accesspolicyproperties.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/model_authenticationbase.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/model_checknameavailabilityrequest.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/model_ecctokenkey.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/model_jwtauthentication.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/model_keyvaultproperties.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/model_rsatokenkey.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/model_storageaccount.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/model_tokenclaim.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/model_tokenkey.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/model_videoentity.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/model_videoflags.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/model_videomediainfo.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/model_videoproperties.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/model_videostreaming.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/model_videostreamingtoken.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/predicates.go delete mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzer/version.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzers/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzers/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzers/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzers/id_location.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzers/id_videoanalyzer.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzers/method_locationschecknameavailability_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzers/method_videoanalyzerscreateorupdate_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzers/method_videoanalyzersdelete_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzers/method_videoanalyzersget_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzers/method_videoanalyzerslist_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzers/method_videoanalyzerslistbysubscription_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzers/method_videoanalyzerssyncstoragekeys_autorest.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzers/method_videoanalyzersupdate_autorest.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/{videoanalyzer => videoanalyzers}/model_accountencryption.go (95%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzers/model_checknameavailabilityrequest.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/{videoanalyzer => videoanalyzers}/model_checknameavailabilityresponse.go (94%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/{videoanalyzer => videoanalyzers}/model_endpoint.go (93%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzers/model_keyvaultproperties.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/{videoanalyzer => videoanalyzers}/model_resourceidentity.go (91%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzers/model_storageaccount.go rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/{videoanalyzer => videoanalyzers}/model_syncstoragekeysinput.go (90%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/{videoanalyzer => videoanalyzers}/model_userassignedmanagedidentity.go (92%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/{videoanalyzer => videoanalyzers}/model_videoanalyzer.go (97%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/{videoanalyzer => videoanalyzers}/model_videoanalyzercollection.go (91%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/{videoanalyzer => videoanalyzers}/model_videoanalyzeridentity.go (94%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/{videoanalyzer => videoanalyzers}/model_videoanalyzerpropertiesupdate.go (94%) rename vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/{videoanalyzer => videoanalyzers}/model_videoanalyzerupdate.go (94%) create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/videoanalyzer/2021-05-01-preview/videoanalyzers/version.go delete mode 100644 vendor/github.com/shopspring/decimal/.gitignore delete mode 100644 vendor/github.com/shopspring/decimal/.travis.yml delete mode 100644 vendor/github.com/shopspring/decimal/CHANGELOG.md delete mode 100644 vendor/github.com/shopspring/decimal/LICENSE delete mode 100644 vendor/github.com/shopspring/decimal/README.md delete mode 100644 vendor/github.com/shopspring/decimal/decimal-go.go delete mode 100644 vendor/github.com/shopspring/decimal/decimal.go delete mode 100644 vendor/github.com/shopspring/decimal/rounding.go create mode 100644 website/docs/d/cdn_frontdoor_origin_group.html.markdown create mode 100644 website/docs/d/dns_a_record.html.markdown create mode 100644 website/docs/d/dns_aaaa_record.html.markdown create mode 100644 website/docs/d/dns_caa_record.html.markdown create mode 100644 website/docs/d/dns_cname_record.html.markdown create mode 100644 website/docs/d/dns_mx_record.html.markdown create mode 100644 website/docs/d/dns_ns_record.html.markdown create mode 100644 website/docs/d/dns_ptr_record.html.markdown create mode 100644 website/docs/d/dns_soa_record.html.markdown create mode 100644 website/docs/d/dns_srv_record.html.markdown create mode 100644 website/docs/d/dns_txt_record.html.markdown create mode 100644 website/docs/d/healthcare_medtech_service.html.markdown create mode 100644 website/docs/d/monitor_data_collection_endpoint.html.markdown create mode 100644 website/docs/d/private_dns_a_record.html.markdown create mode 100644 website/docs/d/private_dns_aaaa_record.html.markdown create mode 100644 website/docs/d/private_dns_cname_record.html.markdown create mode 100644 website/docs/d/private_dns_mx_record.html.markdown create mode 100644 website/docs/d/private_dns_ptr_record.html.markdown create mode 100644 website/docs/d/private_dns_soa_record.html.markdown create mode 100644 website/docs/d/private_dns_srv_record.html.markdown create mode 100644 website/docs/d/private_dns_txt_record.html.markdown create mode 100644 website/docs/d/web_pubsub_private_link_resource.html.markdown create mode 100644 website/docs/r/api_management_gateway_certificate_authority.html.markdown create mode 100644 website/docs/r/api_management_product_tag.html.markdown create mode 100644 website/docs/r/application_insights_workbook.html.markdown create mode 100644 website/docs/r/automation_connection_type.html.markdown create mode 100644 website/docs/r/automation_hybrid_runbook_worker_group.html.markdown create mode 100644 website/docs/r/backup_policy_vm_workload.html.markdown create mode 100644 website/docs/r/cdn_frontdoor_firewall_policy.html.markdown create mode 100644 website/docs/r/cdn_frontdoor_origin.html.markdown create mode 100644 website/docs/r/cdn_frontdoor_origin_group.html.markdown create mode 100644 website/docs/r/cdn_frontdoor_security_policy.html.markdown create mode 100644 website/docs/r/container_registry_task_schedule_run_now.html.markdown create mode 100644 website/docs/r/cosmosdb_sql_dedicated_gateway.html.markdown create mode 100644 website/docs/r/dashboard_grafana.html.markdown create mode 100644 website/docs/r/data_factory_flowlet_data_flow.html.markdown create mode 100644 website/docs/r/datadog_monitors.html.markdown create mode 100644 website/docs/r/eventhub_namespace_schema_group.html.markdown create mode 100644 website/docs/r/healthcare_medtech_service.html.markdown create mode 100644 website/docs/r/healthcare_medtech_service_fhir_destination.html.markdown create mode 100644 website/docs/r/kusto_cluster_managed_private_endpoint.html.markdown create mode 100644 website/docs/r/log_analytics_query_pack.html.markdown create mode 100644 website/docs/r/log_analytics_query_pack_query.html.markdown create mode 100644 website/docs/r/logz_sub_account_tag_rule.html.markdown create mode 100644 website/docs/r/monitor_data_collection_endpoint.html.markdown create mode 100644 website/docs/r/monitor_data_collection_rule.html.markdown create mode 100644 website/docs/r/monitor_scheduled_query_rules_alert_v2.html.markdown create mode 100644 website/docs/r/route_server.html.markdown create mode 100644 website/docs/r/route_server_bgp_connection.html.markdown create mode 100644 website/docs/r/search_shared_private_link_service.html.markdown create mode 100644 website/docs/r/sentinel_alert_rule_nrt.html.markdown create mode 100644 website/docs/r/service_connector_app_service.html.markdown create mode 100644 website/docs/r/service_connector_spring_cloud.html.markdown create mode 100644 website/docs/r/signalr_shared_private_link.html.markdown create mode 100644 website/docs/r/web_pubsub_shared_private_link.html.markdown diff --git a/.github/labeler-pull-request-triage.yml b/.github/labeler-pull-request-triage.yml index 6fb7ff96aea3..246e625bd0c9 100644 --- a/.github/labeler-pull-request-triage.yml +++ b/.github/labeler-pull-request-triage.yml @@ -74,6 +74,9 @@ service/cost-management: service/custom-resource-provider: - internal/services/customproviders/**/* +service/dashboard: + - internal/services/dashboard/**/* + service/data-factory: - internal/services/datafactory/**/* diff --git a/.github/workflows/depscheck.yaml b/.github/workflows/depscheck.yaml index 29335ca659b5..8a4faf1ab843 100644 --- a/.github/workflows/depscheck.yaml +++ b/.github/workflows/depscheck.yaml @@ -1,5 +1,7 @@ --- name: Vendor Dependencies Check +permissions: + contents: read on: pull_request: types: ['opened', 'synchronize'] @@ -16,7 +18,6 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-go@v2 with: - go-version: '1.18.1' + go-version: '1.18.5' - run: bash scripts/gogetcookie.sh - - run: make tools - run: make depscheck diff --git a/.github/workflows/gencheck.yaml b/.github/workflows/gencheck.yaml index 00e1d253774a..005ecded4068 100644 --- a/.github/workflows/gencheck.yaml +++ b/.github/workflows/gencheck.yaml @@ -1,5 +1,7 @@ --- name: Generation Check +permissions: + contents: read on: pull_request: types: ['opened', 'synchronize'] @@ -20,7 +22,6 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-go@v2 with: - go-version: '1.18.1' + go-version: '1.18.5' - run: bash scripts/gogetcookie.sh - - run: make tools - run: make gencheck diff --git a/.github/workflows/golint.yaml b/.github/workflows/golint.yaml index 9e436960a83d..873be8a3b8a8 100644 --- a/.github/workflows/golint.yaml +++ b/.github/workflows/golint.yaml @@ -1,5 +1,7 @@ --- name: GoLang Linting +permissions: + contents: read on: pull_request: types: ['opened', 'synchronize'] @@ -20,7 +22,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-go@v2 with: - go-version: '1.18.1' + go-version: '1.18.5' - uses: golangci/golangci-lint-action@v2 with: version: 'v1.45.0' diff --git a/.github/workflows/gradually-deprecated.yaml b/.github/workflows/gradually-deprecated.yaml index 3b854851353f..caa4a0924bab 100644 --- a/.github/workflows/gradually-deprecated.yaml +++ b/.github/workflows/gradually-deprecated.yaml @@ -1,5 +1,7 @@ --- name: Check for new usages of deprecated functionality +permissions: + contents: read on: pull_request: types: ['opened', 'synchronize'] @@ -16,5 +18,5 @@ jobs: fetch-depth: 0 - uses: actions/setup-go@v2 with: - go-version: '1.18.1' + go-version: '1.18.5' - run: ./scripts/run-gradually-deprecated.sh diff --git a/.github/workflows/issue-comment-created.yaml b/.github/workflows/issue-comment-created.yaml index c5e499b51140..9fc1a1778e70 100644 --- a/.github/workflows/issue-comment-created.yaml +++ b/.github/workflows/issue-comment-created.yaml @@ -4,6 +4,10 @@ on: issue_comment: types: [created] +permissions: + pull-requests: write + issues: write + jobs: issue_comment_triage: runs-on: ubuntu-latest @@ -13,6 +17,19 @@ jobs: github_token: "${{ secrets.GITHUB_TOKEN }}" labels: stale - uses: actions-ecosystem/action-remove-labels@v1 + if: ${{ !github.event.issue.pull_request }} with: github_token: "${{ secrets.GITHUB_TOKEN }}" labels: waiting-response + - uses: actions-ecosystem/action-remove-labels@v1 + if: (github.event.issue.pull_request && github.actor == github.event.issue.user.login) + with: + github_token: "${{ secrets.GITHUB_TOKEN }}" + labels: waiting-response + pull_request_comment: + runs-on: ubuntu-latest + if: github.event.issue.pull_request && endsWith(github.event.comment.body, '/wr') + steps: + - shell: bash + run: | + curl -X POST -H "Accept: application/vnd.github+json" -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" "https://api.github.com/repos${{ github.owner }}/${{ github.repository }}/issues/${{ github.event.issue.number }}/labels" -d '{"labels":["waiting-response"]}' diff --git a/.github/workflows/issue-opened.yaml b/.github/workflows/issue-opened.yaml index c3a4c065d878..98d9143fbae7 100644 --- a/.github/workflows/issue-opened.yaml +++ b/.github/workflows/issue-opened.yaml @@ -1,5 +1,8 @@ name: Issue Opened Triage +permissions: + issues: write + on: issues: types: [opened] diff --git a/.github/workflows/link-milestone.yaml b/.github/workflows/link-milestone.yaml index b497805f8e22..a531f5136f01 100644 --- a/.github/workflows/link-milestone.yaml +++ b/.github/workflows/link-milestone.yaml @@ -16,7 +16,7 @@ jobs: steps: - uses: actions/setup-go@v2 with: - go-version: '1.18.1' + go-version: '1.18.5' - run: | go install github.com/stephybun/link-milestone@latest link-milestone diff --git a/.github/workflows/lock.yaml b/.github/workflows/lock.yaml index ed67648c7887..4e162901f70c 100644 --- a/.github/workflows/lock.yaml +++ b/.github/workflows/lock.yaml @@ -6,6 +6,9 @@ on: jobs: lock: + permissions: + issues: write + pull-requests: write runs-on: ubuntu-latest steps: - uses: dessant/lock-threads@v2 diff --git a/.github/workflows/pull-request-new-commit.yaml b/.github/workflows/pull-request-new-commit.yaml new file mode 100644 index 000000000000..7042b90f2a90 --- /dev/null +++ b/.github/workflows/pull-request-new-commit.yaml @@ -0,0 +1,18 @@ +--- +name: Pull Request New Commit + +permissions: + pull-requests: write + +on: + pull_request_target: + types: [synchronize] + +jobs: + issue_comment_triage: + runs-on: ubuntu-latest + steps: + - uses: actions-ecosystem/action-remove-labels@v1 + with: + github_token: "${{ secrets.GITHUB_TOKEN }}" + labels: waiting-response diff --git a/.github/workflows/pull-request-reviewed-workflow.yaml b/.github/workflows/pull-request-reviewed-workflow.yaml new file mode 100644 index 000000000000..64f9da723f54 --- /dev/null +++ b/.github/workflows/pull-request-reviewed-workflow.yaml @@ -0,0 +1,48 @@ +--- +name: "Pull Request Reviewed Workflow" + +on: + workflow_run: + workflows: + - "Pull Request Reviewed" + types: + - completed + +permissions: + pull-requests: write + +jobs: + add-or-remove-waiting-response: + runs-on: ubuntu-latest + outputs: + ghrepo: ${{ steps.env_vars.outputs.ghrepo }} + ghowner: ${{ steps.env_vars.outputs.ghowner }} + prnumber: ${{ steps.env_vars.outputs.prnumber }} + action: ${{ steps.env_vars.outputs.action }} + steps: + - name: Get Artifact + id: get_artifact + continue-on-error: true + uses: dawidd6/action-download-artifact@v2 + with: + github_token: ${{secrets.GITHUB_TOKEN}} + workflow: pull-request-reviewed.yaml + + - name: env_vars + id: env_vars + if: steps.get_artifact.outcome == 'success' + run: | + echo "::set-output name=ghrepo::$(cat artifact/ghrepo.txt)" + echo "::set-output name=ghowner::$(cat artifact/ghowner.txt)" + echo "::set-output name=prnumber::$(cat artifact/prnumber.txt)" + echo "::set-output name=action::$(cat artifact/action.txt)" + + - name: add waiting-reponse + if: steps.get_artifact.outcome == 'success' && steps.env_vars.outputs.action == 'add-waiting-response' + run: | + curl -X POST -H "Accept: application/vnd.github+json" -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" "https://api.github.com/repos${{ steps.env_vars.outputs.ghowner }}/${{ steps.env_vars.outputs.ghrepo }}/issues/${{ steps.env_vars.outputs.prnumber }}/labels" -d '{"labels":["waiting-response"]}' + + - name: remove waiting-reponse + if: steps.get_artifact.outcome == 'success' && steps.env_vars.outputs.action == 'remove-waiting-response' + run: | + curl -X DELETE -H "Accept: application/vnd.github+json" -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" "https://api.github.com/repos${{ steps.env_vars.outputs.ghowner }}/${{ steps.env_vars.outputs.ghrepo }}/issues/${{ steps.env_vars.outputs.prnumber }}/labels/waiting-response" diff --git a/.github/workflows/pull-request-reviewed.yaml b/.github/workflows/pull-request-reviewed.yaml new file mode 100644 index 000000000000..691170a65157 --- /dev/null +++ b/.github/workflows/pull-request-reviewed.yaml @@ -0,0 +1,36 @@ +--- +name: "Pull Request Reviewed" + +on: + pull_request_review: + types: [submitted] + +permissions: + pull-requests: read + +jobs: + add-or-remove-waiting-response: + runs-on: ubuntu-latest + steps: + - name: "Set Artifacts for add-waiting-response" + if: github.event.review.state != 'approved' && github.actor != github.event.pull_request.user.login + shell: bash + run: | + mkdir -p wr_actions + echo ${{ github.owner }} > wr_actions/ghowner.txt + echo ${{ github.repository }} > wr_actions/ghrepo.txt + echo ${{ github.event.pull_request.number }} > wr_actions/prnumber.txt + echo "add-waiting-response" > wr_actions/action.txt + - name: "Set Artifacts for remove-waiting-response" + if: github.actor == github.event.pull_request.user.login + shell: bash + run: | + mkdir -p wr_actions + echo ${{ github.owner }} > wr_actions/ghowner.txt + echo ${{ github.repository }} > wr_actions/ghrepo.txt + echo ${{ github.event.pull_request.number }} > wr_actions/prnumber.txt + echo "remove-waiting-response" > wr_actions/action.txt + - uses: actions/upload-artifact@v3 + with: + name: artifact + path: wr_actions diff --git a/.github/workflows/pull-request.yaml b/.github/workflows/pull-request.yaml index 9c58e3d541c8..bc8541c25aae 100644 --- a/.github/workflows/pull-request.yaml +++ b/.github/workflows/pull-request.yaml @@ -1,5 +1,8 @@ name: "Pull Request Triage" +permissions: + pull-requests: write + on: [pull_request_target] jobs: diff --git a/.github/workflows/teamcity-test.yaml b/.github/workflows/teamcity-test.yaml index 6724f390dc50..1e691f7525b9 100644 --- a/.github/workflows/teamcity-test.yaml +++ b/.github/workflows/teamcity-test.yaml @@ -1,5 +1,9 @@ --- name: TeamCity Config Test + +permissions: + contents: read + on: pull_request: types: ['opened', 'synchronize'] diff --git a/.github/workflows/tflint.yaml b/.github/workflows/tflint.yaml index c8e4400abaa6..a958f2babfa8 100644 --- a/.github/workflows/tflint.yaml +++ b/.github/workflows/tflint.yaml @@ -1,5 +1,9 @@ --- name: Terraform Schema Linting + +permissions: + contents: read + on: pull_request: types: ['opened', 'synchronize'] @@ -20,7 +24,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-go@v2 with: - go-version: '1.18.1' + go-version: '1.18.5' - run: bash scripts/gogetcookie.sh - run: make tools - run: make tflint diff --git a/.github/workflows/thirty-two-bit.yaml b/.github/workflows/thirty-two-bit.yaml index 658d2f5c5ab0..e0ddd0fdc45a 100644 --- a/.github/workflows/thirty-two-bit.yaml +++ b/.github/workflows/thirty-two-bit.yaml @@ -1,5 +1,9 @@ --- name: 32 Bit Build + +permissions: + pull-requests: read + on: pull_request: types: ['opened', 'synchronize'] @@ -20,7 +24,6 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-go@v2 with: - go-version: '1.18.1' + go-version: '1.18.5' - run: bash scripts/gogetcookie.sh - - run: make tools - run: GOARCH=386 GOOS=linux go build -o 32bitbuild . diff --git a/.github/workflows/unit-test.yaml b/.github/workflows/unit-test.yaml index cb1820ea7ef1..c295f5f1bef1 100644 --- a/.github/workflows/unit-test.yaml +++ b/.github/workflows/unit-test.yaml @@ -1,5 +1,9 @@ --- name: Unit Tests + +permissions: + pull-requests: read + on: pull_request: types: ['opened', 'synchronize'] @@ -19,7 +23,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-go@v2 with: - go-version: '1.18.1' + go-version: '1.18.5' - run: bash scripts/gogetcookie.sh - run: make test env: diff --git a/.github/workflows/validate-examples.yaml b/.github/workflows/validate-examples.yaml index 7ef44548a1dc..28a586d6a6a9 100644 --- a/.github/workflows/validate-examples.yaml +++ b/.github/workflows/validate-examples.yaml @@ -1,5 +1,9 @@ --- name: Validate Examples + +permissions: + pull-requests: read + on: pull_request: types: ['opened', 'synchronize'] @@ -18,7 +22,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-go@v2 with: - go-version: '1.18.1' + go-version: '1.18.5' - run: bash scripts/gogetcookie.sh - run: make tools - run: make validate-examples diff --git a/.github/workflows/website-lint.yaml b/.github/workflows/website-lint.yaml index 57fd18b081d5..48339db39c0f 100644 --- a/.github/workflows/website-lint.yaml +++ b/.github/workflows/website-lint.yaml @@ -1,5 +1,9 @@ --- name: Website Linting + +permissions: + pull-requests: read + on: pull_request: types: ['opened', 'synchronize'] @@ -14,7 +18,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-go@v2 with: - go-version: '1.18.1' + go-version: '1.18.5' - run: bash scripts/gogetcookie.sh - run: make tools - run: make website-lint diff --git a/.go-version b/.go-version index 5ce8b3959987..8e8b0a9335a8 100644 --- a/.go-version +++ b/.go-version @@ -1 +1 @@ -1.18.1 \ No newline at end of file +1.18.5 diff --git a/.teamcity/components/generated/services.kt b/.teamcity/components/generated/services.kt index dc82027890cb..5bfbe77a004e 100644 --- a/.teamcity/components/generated/services.kt +++ b/.teamcity/components/generated/services.kt @@ -28,12 +28,14 @@ var services = mapOf( "costmanagement" to "Cost Management", "customproviders" to "Custom Providers", "dns" to "DNS", + "dashboard" to "Dashboard", "datafactory" to "Data Factory", "datashare" to "Data Share", "databricks" to "DataBricks", "dataprotection" to "DataProtection", "databasemigration" to "Database Migration", "databoxedge" to "Databox Edge", + "datadog" to "Datadog", "desktopvirtualization" to "Desktop Virtualization", "devtestlabs" to "Dev Test", "digitaltwins" to "Digital Twins", @@ -93,6 +95,7 @@ var services = mapOf( "servicefabric" to "Service Fabric", "servicefabricmanaged" to "Service Fabric Managed Clusters", "servicebus" to "ServiceBus", + "serviceconnector" to "ServiceConnector", "signalr" to "SignalR", "springcloud" to "Spring Cloud", "storage" to "Storage", diff --git a/CHANGELOG-v2.md b/CHANGELOG-v2.md index dedcf63ee7d0..0c4f2b693619 100644 --- a/CHANGELOG-v2.md +++ b/CHANGELOG-v2.md @@ -4136,7 +4136,7 @@ NOTES: FEATURES: -* **Custom Timeouts:** - all resources within the Azure Provider now allow configuring custom timeouts - please [see Terraform's Timeout documentation](https://www.terraform.io/docs/configuration/resources.html#operation-timeouts) and the documentation in each data source resource for more information. +* **Custom Timeouts:** - all resources within the Azure Provider now allow configuring custom timeouts - please [see Terraform's Timeout documentation](https://www.terraform.io/language/resources/syntax#operation-timeouts) and the documentation in each data source resource for more information. * **Requires Import:** The Azure Provider now checks for the presence of an existing resource prior to creating it - which means that if you try and create a resource which already exists (without importing it) you'll be prompted to import this into the state. * **New Data Source:** `azurerm_app_service_environment` ([#5508](https://github.com/hashicorp/terraform-provider-azurerm/issues/5508)) * **New Data Source:** `azurerm_eventhub_authorization_rule` ([#5805](https://github.com/hashicorp/terraform-provider-azurerm/issues/5805)) diff --git a/CHANGELOG.md b/CHANGELOG.md index 28134090362e..dadef38c51a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,279 @@ -## 3.14.0 (Unreleased) +## 3.21.0 (Unreleased) + +FEATURES: + +* **New Data Source**: `azurerm_monitor_data_collection_endpoint` [GH-17992] +* **New Resource**: `azurerm_app_service_connection` [GH-16907] +* **New Resource**: `azurerm_api_management_gateway_certificate_authority` [GH-17879] +* **New Resource**: `azurerm_api_management_product_tag` [GH-17798] +* **New Resource**: `azurerm_automation_connection_type` [GH-17538] +* **New Resource**: `azurerm_automation_hybrid_runbook_worker_group` [GH-17881] +* **New Resource**: `azurerm_container_registry_task_schedule_run_now` [GH-15120] +* **New Resource**: `azurerm_cosmosdb_sql_dedicated_gateway` [GH-18133] +* **New Resource**: `azurerm_dashboard_grafana` [GH-17840] +* **New Resource**: `azurerm_log_analytics_query_pack_query` [GH-17929] +* **New Resource**: `azurerm_healthcare_medtech_service` [GH-15967] +* **New Resource**: `azurerm_spring_cloud_connection` [GH-16907] +* **New Resource**: `azurerm_search_shared_private_link_service` [GH-17744] +* **New Resource**: `azurerm_sentinel_alert_rule_nrt` [GH-15999] + +ENHANCEMENTS: + +* dependencies: updating to version `v0.20220830.1105041` of `github.com/hashicorp/go-azure-sdk` [GH-18183] +* `azurerm_container_registry` - support for the `azuread_authentication_as_arm_policy_enabled` and `soft_delete_policy` properties [GH-17926] +* `azurerm_hdinsight_kafka_cluster` - add support for the `disk_encryption` property [GH-17351] +* `azurerm_hdinsight_spark_cluster` - add support for the `disk_encryption` property [GH-17351] +* `azurerm_hdinsight_interactive_query_cluster` - add support for the `disk_encryption` property [GH-17351] +* `azurerm_hdinsight_hbase_cluster` - add support for the `disk_encryption` property [GH-17351] +* `azurerm_hdinsight_hadoop_cluster` - add support for the `disk_encryption` property [GH-17351] +* `azurerm_iothub_dps` - support for the `resource_count`, `parallel_deployments`, and `failure_percentage` properties [GH-18151] +* `azurerm_kubernetes_node_pool` - spot node pools can now be upgraded [GH-18124] +* `azurerm_management_group_policy_remediation` - support for the `resource_count`, `parallel_deployments`, and `failure_percentage` properties [GH-17313] +* `azurerm_monitor_diagnostic_setting` - support for the `category_group` property [GH-16367] +* `azurerm_resource_group_policy_remediation` - support for the `resource_count`, `parallel_deployments`, and `failure_percentage` properties [GH-17313] +* `azurerm_resource_policy_remediation` - support for the `resource_count`, `parallel_deployments`, and `failure_percentage` properties [GH-17313] +* `azurerm_servicebus_namespace` - support for the `public_network_access_enabled` and `minimum_tls_version` properties [GH-17805] +* `azurerm_storage_account` - support for the `public_network_access_enabled` property [GH-18005] +* `azurerm_stream_analytics_output_eventhub` - support for the `authentication_mode` property [GH-18096] +* `azurerm_stream_analytics_output_mssql` - support for the `authentication_mode` property [GH-18096] +* `azurerm_stream_analytics_output_servicebus_topic` - support for the `authentication_mode` property [GH-18096] +* `azurerm_stream_analytics_output_powerbi` - support for the `token_user_principal_name` and `token_user_display_name` properties [GH-18117] +* `azurerm_stream_analytics_output_cosmosdb` - support for the `partition_key` property [GH-18120] +* `azurerm_stream_analytics_reference_input_blob` - support for the `authentication_mode` property [GH-18137] +* `azurerm_subscription_policy_remediation` - support for the `resource_count`, `parallel_deployments`, and `failure_percentage` properties [GH-17313] +* Dependencies: `log_analytics` - update to use hashicorp/go-azure-sdk [GH-18098] + +BUG FIXES: + +* `azurerm_kubernetes_cluster` - `kube_config` is now set when AAD is enabled for a v1.24 cluster [GH-18142] +* `azurerm_redis_cache` - will now recreate the cache when downgrading the SKU [GH-17767] +* `azurerm_spring_cloud_service` - ignore default zero value for `read_timeout_seconds` [GH-18161] + +## 3.20.0 (August 25, 2022) + +FEATURES: + +* **Provider:** support for generic OIDC authentication providers ([#18118](https://github.com/hashicorp/terraform-provider-azurerm/issues/18118)) +* **New Resource**: `azurerm_backup_policy_vm_workload` ([#17765](https://github.com/hashicorp/terraform-provider-azurerm/issues/17765)) +* **New Resource**: `azurerm_monitor_scheduled_query_rules_alert_v2` ([#17772](https://github.com/hashicorp/terraform-provider-azurerm/issues/17772)) + +ENHANCEMENTS: + +* Dependencies: update `go-azure-sdk` to `v0.20220824.1090858` ([#18100](https://github.com/hashicorp/terraform-provider-azurerm/issues/18100)) +* Dependencies: `consumption` - updating to use `hashicorp/go-azure-sdk` ([#18101](https://github.com/hashicorp/terraform-provider-azurerm/issues/18101)) +* `azurerm_data_factory_dataset_json` - `filename` and `path` in `azure_blob_storage_location` block can now be empty ([#18061](https://github.com/hashicorp/terraform-provider-azurerm/issues/18061)) + +BUG FIXES: + +* `data.azurerm_kubernetes_cluster` - `kube_config` is now set when AAD is enabled for a v1.24 cluster ([#18131](https://github.com/hashicorp/terraform-provider-azurerm/issues/18131)) +* `azurerm_cosmosdb_sql_database` - prevent panic in autoacale settings ([#18070](https://github.com/hashicorp/terraform-provider-azurerm/issues/18070)) +* `azurerm_kubernetes_cluster_node_pool` - fix a crash in expanding upgrade settings ([#18074](https://github.com/hashicorp/terraform-provider-azurerm/issues/18074)) +* `azurerm_mssql_elastic_pool` - list of values for `maintenance_configuration_name` is now correct ([#18041](https://github.com/hashicorp/terraform-provider-azurerm/issues/18041)) +* `azurerm_postgresql_flexible_server` - `point_in_time_restore_time_in_utc` correctly converts to RFC3339 ([#18106](https://github.com/hashicorp/terraform-provider-azurerm/issues/18106)) + +## 3.19.1 (August 19, 2022) + +BUG FIXES: + +* `azurerm_dns_a_record` - parse resource IDs insensitively in the read functions due to casing on the dnsZones segment ([#18048](https://github.com/hashicorp/terraform-provider-azurerm/issues/18048)) +* `azurerm_dns_aaaa_record` - parse resource IDs insensitively in the read functions due to casing on the dnsZones segment ([#18048](https://github.com/hashicorp/terraform-provider-azurerm/issues/18048)) +* `azurerm_dns_caa_record` - parse resource IDs insensitively in the read functions due to casing on the dnsZones segment ([#18048](https://github.com/hashicorp/terraform-provider-azurerm/issues/18048)) +* `azurerm_dns_cname_record` - parse resource IDs insensitively in the read functions due to casing on the dnsZones segment ([#18048](https://github.com/hashicorp/terraform-provider-azurerm/issues/18048)) +* `azurerm_dns_mx_record` - parse resource IDs insensitively in the read functions due to casing on the dnsZones segment ([#18048](https://github.com/hashicorp/terraform-provider-azurerm/issues/18048)) +* `azurerm_dns_ns_record` - parse resource IDs insensitively in the read functions due to casing on the dnsZones segment ([#18048](https://github.com/hashicorp/terraform-provider-azurerm/issues/18048)) +* `azurerm_dns_ptr_record` - parse resource IDs insensitively in the read functions due to casing on the dnsZones segment ([#18048](https://github.com/hashicorp/terraform-provider-azurerm/issues/18048)) +* `azurerm_dns_srv_record` - parse resource IDs insensitively in the read functions due to casing on the dnsZones segment ([#18048](https://github.com/hashicorp/terraform-provider-azurerm/issues/18048)) +* `azurerm_dns_txt_record` - parse resource IDs insensitively in the read functions due to casing on the dnsZones segment ([#18048](https://github.com/hashicorp/terraform-provider-azurerm/issues/18048)) +* `azurerm_dns_zone` - parse resource IDs insensitively in the read functions due to casing on the dnsZones segment ([#18048](https://github.com/hashicorp/terraform-provider-azurerm/issues/18048)) + +## 3.19.0 (August 18, 2022) + +FEATURES: + +* **New Data Source**: `azurerm_dns_a_record` ([#17477](https://github.com/hashicorp/terraform-provider-azurerm/issues/17477)) +* **New Data Source**: `azurerm_dns_aaaa_record` ([#17477](https://github.com/hashicorp/terraform-provider-azurerm/issues/17477)) +* **New Data Source**: `azurerm_dns_caa_record` ([#17477](https://github.com/hashicorp/terraform-provider-azurerm/issues/17477)) +* **New Data Source**: `azurerm_dns_cname_record` ([#17477](https://github.com/hashicorp/terraform-provider-azurerm/issues/17477)) +* **New Data Source**: `azurerm_dns_mx_record` ([#17477](https://github.com/hashicorp/terraform-provider-azurerm/issues/17477)) +* **New Data Source**: `azurerm_dns_ns_record` ([#17477](https://github.com/hashicorp/terraform-provider-azurerm/issues/17477)) +* **New Data Source**: `azurerm_dns_ptr_record` ([#17477](https://github.com/hashicorp/terraform-provider-azurerm/issues/17477)) +* **New Data Source**: `azurerm_dns_soa_record` ([#17477](https://github.com/hashicorp/terraform-provider-azurerm/issues/17477)) +* **New Data Source**: `azurerm_dns_srv_record` ([#17477](https://github.com/hashicorp/terraform-provider-azurerm/issues/17477)) +* **New Data Source**: `azurerm_dns_txt_record` ([#17477](https://github.com/hashicorp/terraform-provider-azurerm/issues/17477)) +* **New Data Source**: `azurerm_private_dns_a_record` ([#18036](https://github.com/hashicorp/terraform-provider-azurerm/issues/18036)) +* **New Data Source**: `azurerm_private_dns_aaaa_record` ([#18036](https://github.com/hashicorp/terraform-provider-azurerm/issues/18036)) +* **New Data Source**: `azurerm_private_dns_cname_record` ([#18036](https://github.com/hashicorp/terraform-provider-azurerm/issues/18036)) +* **New Data Source**: `azurerm_private_dns_mx_record` ([#18036](https://github.com/hashicorp/terraform-provider-azurerm/issues/18036)) +* **New Data Source**: `azurerm_private_dns_ptr_record` ([#18036](https://github.com/hashicorp/terraform-provider-azurerm/issues/18036)) +* **New Data Source**: `azurerm_private_dns_soa_record` ([#18036](https://github.com/hashicorp/terraform-provider-azurerm/issues/18036)) +* **New Data Source**: `azurerm_private_dns_srv_record` ([#18036](https://github.com/hashicorp/terraform-provider-azurerm/issues/18036)) +* **New Data Source**: `azurerm_private_dns_txt_record` ([#18036](https://github.com/hashicorp/terraform-provider-azurerm/issues/18036)) +* **New Resource**: `azurerm_eventhub_namespace_schema_group` ([#17635](https://github.com/hashicorp/terraform-provider-azurerm/issues/17635)) +* **New Resource**: `azurerm_cdn_frontdoor_firewall_policy` ([#17715](https://github.com/hashicorp/terraform-provider-azurerm/issues/17715)) +* **New Resource**: `azurerm_cdn_frontdoor_security_policy` ([#17715](https://github.com/hashicorp/terraform-provider-azurerm/issues/17715)) +* **New Resource**: `azurerm_data_factory_flowlet_data_flow` ([#16987](https://github.com/hashicorp/terraform-provider-azurerm/issues/16987)) + +ENHANCEMENTS: + +* Dependencies: update `go-azure-helpers` to `v0.39.1` ([#18015](https://github.com/hashicorp/terraform-provider-azurerm/issues/18015)) +* Dependencies: update `go-azure-sdk` to `v0.20220815.1092453` ([#17998](https://github.com/hashicorp/terraform-provider-azurerm/issues/17998)) +* Dependencies: `dedicated_host_*` to use `hashicorp/go-azure-sdk` ([#17616](https://github.com/hashicorp/terraform-provider-azurerm/issues/17616)) +* Dependencies: `dataprotection`: updating to use `hashicorp/go-azure-sdk` ([#17700](https://github.com/hashicorp/terraform-provider-azurerm/issues/17700)) +* Dependencies: `dns` - updating to use `hashicorp/go-azure-sdk` ([#17986](https://github.com/hashicorp/terraform-provider-azurerm/issues/17986)) +* Dependencies: `maintenance` - updating to use `hashicorp/go-azure-sdk` ([#17954](https://github.com/hashicorp/terraform-provider-azurerm/issues/17954)) +* Data Source: `azurerm_images` - now uses a logical id ([#17766](https://github.com/hashicorp/terraform-provider-azurerm/issues/17766)) +* Data Source: `azurerm_management_group` - now exports the `management_group_ids`, `all_management_group_ids`, and `all_subscription_ids` attributes ([#16208](https://github.com/hashicorp/terraform-provider-azurerm/issues/16208)) +* `azurerm_active_directory_domain_service` - support for the `kerberos_armoring_enabled` and `kerberos_rc4_encryption_enabled` properties ([#17853](https://github.com/hashicorp/terraform-provider-azurerm/issues/17853)) +* `azurerm_application_gateway` - support for the `global` block ([#17651](https://github.com/hashicorp/terraform-provider-azurerm/issues/17651)) +* `azurerm_application_gateway` - support for `components` in `rewrite_rule_set.rewrite_rule.url` ([#13899](https://github.com/hashicorp/terraform-provider-azurerm/issues/13899)) +* `azurerm_automation_account` - support for the `private_endpoint_connection` property ([#17934](https://github.com/hashicorp/terraform-provider-azurerm/issues/17934)) +* `azurerm_automation_account` - support for the `encryption` block and `local_authentication_enabled` property ([#17454](https://github.com/hashicorp/terraform-provider-azurerm/issues/17454)) +* `azurerm_batch_account` - support for the `storage_account_authentication_mode`, `storage_account_node_identit`, and `allowed_authentication_modes` properties ([#16758](https://github.com/hashicorp/terraform-provider-azurerm/issues/16758)) +* `azurerm_batch_pool` - support for identity referencees in container registries ([#17416](https://github.com/hashicorp/terraform-provider-azurerm/issues/17416)) +* `azurerm_data_factory_data_flow` - support for the `flowlet` block ([#16987](https://github.com/hashicorp/terraform-provider-azurerm/issues/16987)) +* `azurerm_data_factory_integration_runtime_azure_ssis` - support for the `express_vnet_injection` property ([#17756](https://github.com/hashicorp/terraform-provider-azurerm/issues/17756)) +* `azurerm_firewall_policy_resource` - support for the `private_ranges` and `allow_sql_redirect` properties ([#17842](https://github.com/hashicorp/terraform-provider-azurerm/issues/17842)) +* `azurerm_key_vault` - support for the `public_network_access_enabled` property ([#17552](https://github.com/hashicorp/terraform-provider-azurerm/issues/17552)) +* `azurerm_linux_virtual_machine` - now supports delete Eviction policies ([#17226](https://github.com/hashicorp/terraform-provider-azurerm/issues/17226)) +* `azurerm_linux_virtual_machine_scale_set` - now supports delete Eviction policies ([#17226](https://github.com/hashicorp/terraform-provider-azurerm/issues/17226)) +* `azurerm_mssql_elastic_pool` - support for the `maintenance_configuration_name` property ([#17790](https://github.com/hashicorp/terraform-provider-azurerm/issues/17790)) +* `azurerm_mssql_server` - support `Disabled` for the `minimum_tls_version` property ([#16595](https://github.com/hashicorp/terraform-provider-azurerm/issues/16595)) +* `azurerm_spring_cloud_app` - support the `public_endpoint_enabled` property ([#17630](https://github.com/hashicorp/terraform-provider-azurerm/issues/17630)) +* `azurerm_spring_cloud_gateway_route_config` - support for the `open_api;azurerm_spring_cloud_service` and `log_stream_public_endpoint_enabledread_timeout_seconds` properties ([#17630](https://github.com/hashicorp/terraform-provider-azurerm/issues/17630)) +* `azurerm_shared_image` - support for the `architecture` property ([#17250](https://github.com/hashicorp/terraform-provider-azurerm/issues/17250)) +* `azurerm_storage_account` - support for the `default_to_oauth_authentication` property ([#17116](https://github.com/hashicorp/terraform-provider-azurerm/issues/17116)) +* `azurerm_storage_table_entity` - support for specifying data types on entity properties ([#15782](https://github.com/hashicorp/terraform-provider-azurerm/issues/15782)) +* `azurerm_shared_image_version` - support for `blob_uri` and `storage_account_id` ([#17768](https://github.com/hashicorp/terraform-provider-azurerm/issues/17768)) +* `azurerm_windows_virtual_machine` - now supports delete Eviction policies ([#17226](https://github.com/hashicorp/terraform-provider-azurerm/issues/17226)) +* `azurerm_windows_virtual_machine_scale_set` - now supports delete Eviction policies ([#17226](https://github.com/hashicorp/terraform-provider-azurerm/issues/17226)) +* `azurerm_web_application_firewall_policy` - support for the `excluded_rule_set` property ([#17757](https://github.com/hashicorp/terraform-provider-azurerm/issues/17757)) +* `azurerm_log_analytics_workspace` - support for the `cmk_for_query_forced` property ([#17365](https://github.com/hashicorp/terraform-provider-azurerm/issues/17365)) +* `azurerm_lb_backend_address_pool_address` - support for the `backend_address_ip_configuration_id` property ([#17770](https://github.com/hashicorp/terraform-provider-azurerm/issues/17770)) + +BUG FIXES: + +* Data Source: `azurerm_windows_web_app` - add missing schema definition for 'virtual_network_subnet_id' ([#18028](https://github.com/hashicorp/terraform-provider-azurerm/issues/18028)) +* `azurerm_cdn_endpoint_custom_domain` - deprecating the `key_vault_certificate_id` property in favour of the `key_vault_secret_id` property withing the `user_managed https_allows` block ([#17114](https://github.com/hashicorp/terraform-provider-azurerm/issues/17114)) +* `azurerm_data_protection_backup_policy_postgresql_resource` - prevent a crash when given an empty criteria block ([#17904](https://github.com/hashicorp/terraform-provider-azurerm/issues/17904)) +* `azurerm_disk_encryption_set` - prevent an issue during creation when the disk encryption set and key vault are in different subscriptions ([#17964](https://github.com/hashicorp/terraform-provider-azurerm/issues/17964)) +* `azurerm_windows_function_app` fix a bug with setting values for `WindowsFxString` ([#18014](https://github.com/hashicorp/terraform-provider-azurerm/issues/18014)) +* `azurerm_windows_function_app_slot` - fix a bug with setting values for `WindowsFxString` ([#18014](https://github.com/hashicorp/terraform-provider-azurerm/issues/18014)) +* `azurerm_linux_function_app` - correctly send `WEBSITE_CONTENTSHARE` and `WEBSITE_CONTENTAZUREFILECONNECTIONSTRING` ([#18035](https://github.com/hashicorp/terraform-provider-azurerm/issues/18035)) +* `azurerm_linux_function_app` - fix content settings when `storage_uses_managed_identity` is set to `true` ([#18035](https://github.com/hashicorp/terraform-provider-azurerm/issues/18035)) +* `azurerm_linux_function_app_slot` - correctly send `WEBSITE_CONTENTSHARE` and `WEBSITE_CONTENTAZUREFILECONNECTIONSTRING` ([#18035](https://github.com/hashicorp/terraform-provider-azurerm/issues/18035)) +* `azurerm_linux_function_app_slot` - fix content settings when `storage_uses_managed_identity` is set to `true` ([#18035](https://github.com/hashicorp/terraform-provider-azurerm/issues/18035)) +* `azurerm_windows_function_app` - correctly send `WEBSITE_CONTENTSHARE` and `WEBSITE_CONTENTAZUREFILECONNECTIONSTRING` ([#18035](https://github.com/hashicorp/terraform-provider-azurerm/issues/18035)) +* `azurerm_windows_function_app` - fix content settings when `storage_uses_managed_identity` is set to `true` ([#18035](https://github.com/hashicorp/terraform-provider-azurerm/issues/18035)) +* `azurerm_windows_function_app_slot` - correctly send `WEBSITE_CONTENTSHARE` and `WEBSITE_CONTENTAZUREFILECONNECTIONSTRING` ([#18035](https://github.com/hashicorp/terraform-provider-azurerm/issues/18035)) +* `azurerm_windows_function_app_slot` - fix content settings when `storage_uses_managed_identity` is set to `true` ([#18035](https://github.com/hashicorp/terraform-provider-azurerm/issues/18035)) + +## 3.18.0 (August 11, 2022) + +FEATURES: + +* **New Resource**: `azurerm_monitor_data_collection_endpoint` ([#17684](https://github.com/hashicorp/terraform-provider-azurerm/issues/17684)) + +ENHANCEMENTS: + +* dependencies: updating `github.com/hashicorp/go-azure-sdk` to `v0.20220809.1122626` ([#17905](https://github.com/hashicorp/terraform-provider-azurerm/issues/17905)) +* storage: updating to use API Version `2021-09-01` ([#17523](https://github.com/hashicorp/terraform-provider-azurerm/issues/17523)) +* `azurerm_express_route_circuit_peering` - support for the `ipv4_enabled` and `gateway_manager_etag` properties ([#17338](https://github.com/hashicorp/terraform-provider-azurerm/issues/17338)) +* `azurerm_site_recovery_replicated_vm` - support for the `target_disk_encryption` block ([#15783](https://github.com/hashicorp/terraform-provider-azurerm/issues/15783)) +* `azurerm_subnet` - deprecate `enforce_private_link_endpoint_network_policies` property in favour of `private_endpoint_network_policies_enabled` ([#17464](https://github.com/hashicorp/terraform-provider-azurerm/issues/17464)) +* `azurerm_subnet` - deprecate `enforce_private_link_service_network_policies` property in favour of `private_link_service_network_policies_enabled` ([#17464](https://github.com/hashicorp/terraform-provider-azurerm/issues/17464)) +* `azurerm_servicebus_subscription` - support for the `client_scoped_subscription_enabled` property and the `client_scoped_subscription` block ([#17101](https://github.com/hashicorp/terraform-provider-azurerm/issues/17101)) + +BUG FIXES: + +* `azurerm_backup_policy_vm` - now prevents crash when `frequency` is set to Hourly and, `hour_interval` and `hour_duration`are not set ([#17880](https://github.com/hashicorp/terraform-provider-azurerm/issues/17880)) +* Data Source: `azurerm_blueprint_definition` - Fix `version` property output ([#16299](https://github.com/hashicorp/terraform-provider-azurerm/issues/16299)) + +## 3.17.0 (August 04, 2022) + +ENHANCEMENTS: + +* domainservice: updating to use API Version `2021-05-01` ([#17737](https://github.com/hashicorp/terraform-provider-azurerm/issues/17737)) +* Data Source: `azurerm_proximity_placement_group` - refactoring to use `hashicorp/go-azure-sdk` ([#17776](https://github.com/hashicorp/terraform-provider-azurerm/issues/17776)) +* `azurerm_api_management` - update the `sku_name` property validation to accept newer Premium SKUs ([#17887](https://github.com/hashicorp/terraform-provider-azurerm/issues/17887)) +* `azurerm_firewall` - the property `sku_tier` is now updateable ([#17577](https://github.com/hashicorp/terraform-provider-azurerm/issues/17577)) +* `azurerm_linux_virtual_machine_scale_set` - the property `instances` is now Optional and defaults to `0` ([#17836](https://github.com/hashicorp/terraform-provider-azurerm/issues/17836)) +* `azurerm_log_analytics_cluster` - updated validation for the `size_gb` property ([#17780](https://github.com/hashicorp/terraform-provider-azurerm/issues/17780)) +* `azurerm_proximity_placement_group` - refactoring to use `hashicorp/go-azure-sdk` ([#17776](https://github.com/hashicorp/terraform-provider-azurerm/issues/17776)) +* `azurerm_shared_image` - improved validation for the `publisher`, `offer` and `sku` properties in the `identifier` block ([#17547](https://github.com/hashicorp/terraform-provider-azurerm/issues/17547)) +* `azurerm_subnet` - support for the service delegation `Microsoft.Orbital/orbitalGateway` ([#17854](https://github.com/hashicorp/terraform-provider-azurerm/issues/17854)) +* `azurerm_eventhub_namespace` - support for the `local_authentication_enabled`, `public_network_access_enabled`, and `minimum_tls_version` properties ([#17194](https://github.com/hashicorp/terraform-provider-azurerm/issues/17194)) + +BUG FIXES: + +* Data Source: `azurerm_private_dns_zone` - returning the correct Resource ID when not specifying the `resource_group_name` ([#17729](https://github.com/hashicorp/terraform-provider-azurerm/issues/17729)) + +## 3.16.0 (July 28, 2022) + +FEATURES: + +* **New Resource**: `azurerm_datadog_monitor` ([#16131](https://github.com/hashicorp/terraform-provider-azurerm/issues/16131)) +* **New Resource**: `azurerm_kusto_cluster_managed_private_endpoint` ([#17667](https://github.com/hashicorp/terraform-provider-azurerm/issues/17667)) +* **New Resource**: `azurerm_log_analytics_query_pack` ([#17685](https://github.com/hashicorp/terraform-provider-azurerm/issues/17685)) +* **New Resource**: `azurerm_logz_sub_account_tag_rule` ([#17557](https://github.com/hashicorp/terraform-provider-azurerm/issues/17557)) +* **New Resource**: `azurerm_signalr_shared_private_link_resource` ([#16187](https://github.com/hashicorp/terraform-provider-azurerm/issues/16187)) + +ENHANCEMENTS: + +* dependencies: updating to version `v0.20220725.1163004` of `github.com/hashicorp/go-azure-sdk` ([#17753](https://github.com/hashicorp/terraform-provider-azurerm/issues/17753)) +* automationaccount: updating to use `hashicorp/go-azure-sdk` ([#17347](https://github.com/hashicorp/terraform-provider-azurerm/issues/17347)) +* Data Source: `azurerm_linux_function_app` - support the `virtual_network_subnet_id` property for for vNet integration ([#17494](https://github.com/hashicorp/terraform-provider-azurerm/issues/17494)) +* Data Source: `azurerm_windows_function_app` - support the `virtual_network_subnet_id` property for for vNet integration ([#17572](https://github.com/hashicorp/terraform-provider-azurerm/issues/17572)) +* Data Source: `azurerm_windows_web_app` - support the `virtual_network_subnet_id` property for for vNet integration ([#17576](https://github.com/hashicorp/terraform-provider-azurerm/issues/17576)) +* `eventhub`: updating all data sources/resources onto single API Version `2021-11-01` ([#17719](https://github.com/hashicorp/terraform-provider-azurerm/issues/17719)) +* `azurerm_bot_service_azure_bot` - support for the `streaming_endpoint_enabled` property ([#17423](https://github.com/hashicorp/terraform-provider-azurerm/issues/17423)) +* `azurerm_cognitive_account` - support for the `custom_question_answering_search_service_key` property ([#17683](https://github.com/hashicorp/terraform-provider-azurerm/issues/17683)) +* `asurerm_iothub_dps_certificate` - support for the `is_verified` property ([#17106](https://github.com/hashicorp/terraform-provider-azurerm/issues/17106)) +* `azurerm_linux_web_app`  - the `virtual_network_subnet_id` property is no longer `ForceNew` ([#17584](https://github.com/hashicorp/terraform-provider-azurerm/issues/17584)) +* `azurerm_linux_web_app_slot` - the `virtual_network_subnet_id` property is no longer `ForceNew` ([#17584](https://github.com/hashicorp/terraform-provider-azurerm/issues/17584)) +* `azurerm_linux_function_app` support the `virtual_network_subnet_id` property for for vNet integration ([#17494](https://github.com/hashicorp/terraform-provider-azurerm/issues/17494)) +* `azurerm_linux_function_app_slot` support the `virtual_network_subnet_id` property for for vNet integration ([#17494](https://github.com/hashicorp/terraform-provider-azurerm/issues/17494)) +* `azurerm_stream_analytics_stream_input_eventhub` - support for the `authentication_mode` property ([#17739](https://github.com/hashicorp/terraform-provider-azurerm/issues/17739)) +* `azurerm_windows_function_app` support the `virtual_network_subnet_id` property for for vNet integration ([#17572](https://github.com/hashicorp/terraform-provider-azurerm/issues/17572)) +* `azurerm_windows_function_app_slot` support the `virtual_network_subnet_id` property for for vNet integration ([#17572](https://github.com/hashicorp/terraform-provider-azurerm/issues/17572)) +* `azurerm_windows_web_app` support the `virtual_network_subnet_id` property for for vNet integration ([#17576](https://github.com/hashicorp/terraform-provider-azurerm/issues/17576)) +* `azurerm_windows_web_app_slot` support the `virtual_network_subnet_id` property for for vNet integration ([#17576](https://github.com/hashicorp/terraform-provider-azurerm/issues/17576)) + +BUG FIXES: + +* `azurerm_linux_function_app` - fix casing bug with the `linux_fx_string` property for Node apps ([#17789](https://github.com/hashicorp/terraform-provider-azurerm/issues/17789)) +* `azurerm_linux_function_app_slot` - fix casing bug with the `linux_fx_string` property for Node apps ([#17789](https://github.com/hashicorp/terraform-provider-azurerm/issues/17789)) +* `azurerm_resource_group_template_deployment` - fixing a bug where the same Resource Provider defined in different casings would cause the API Version to not be identified ([#17707](https://github.com/hashicorp/terraform-provider-azurerm/issues/17707)) + +## 3.15.1 (July 25, 2022) + +BUG FIXES: + +* `data.azurerm_servicebus_queue` - fix a regression around `namespace_id` ([#17755](https://github.com/hashicorp/terraform-provider-azurerm/issues/17755)) +* `azurerm_postgresql_aad_administrator` - fix the state migration ([#17732](https://github.com/hashicorp/terraform-provider-azurerm/issues/17732)) +* `azurerm_postgresql_server` - fix a regression around `id` ([#17755](https://github.com/hashicorp/terraform-provider-azurerm/issues/17755)) + +## 3.15.0 (July 21, 2022) + +FEATURES: + +* **New Data Source**: `azurerm_cdn_frontdoor_origin_group` ([#17089](https://github.com/hashicorp/terraform-provider-azurerm/issues/17089)) +* **New Data Source**: `azurerm_cdn_frontdoor_origin` ([#17089](https://github.com/hashicorp/terraform-provider-azurerm/issues/17089)) +* **New Resource**: `azurerm_cdn_frontdoor_origin_group` ([#17089](https://github.com/hashicorp/terraform-provider-azurerm/issues/17089)) +* **New Resource**: `azurerm_cdn_frontdoor_origin` ([#17089](https://github.com/hashicorp/terraform-provider-azurerm/issues/17089)) +* **New Resource**: `azurerm_application_insights_workbook` ([#17368](https://github.com/hashicorp/terraform-provider-azurerm/issues/17368)) +* **New Resource**: `azurerm_monitor_data_collection_rule` ([#17342](https://github.com/hashicorp/terraform-provider-azurerm/issues/17342)) +* **New Resource**: `azurerm_route_server` ([#16578](https://github.com/hashicorp/terraform-provider-azurerm/issues/16578)) +* **New Resource**: `azurerm_route_server_bgp_connection` ([#16578](https://github.com/hashicorp/terraform-provider-azurerm/issues/16578)) +* **New Resource**: `azurerm_web_pubsub_private_link_resource` ([#15550](https://github.com/hashicorp/terraform-provider-azurerm/issues/15550)) ENHANCEMENTS: -* dependencies: updating to `v0.20220715.1071215` of `github.com/hashicorp/go-azure-sdk` [GH-17645] -* servicebus: refactoring to use `hashicorp/go-azure-sdk` [GH-17628] +* dependencies: updating to `v0.20220715.1071215` of `github.com/hashicorp/go-azure-sdk` ([#17645](https://github.com/hashicorp/terraform-provider-azurerm/issues/17645)) +* domainservice: to use `hashicorp/go-azure-sdk` ([#17595](https://github.com/hashicorp/terraform-provider-azurerm/issues/17595)) +* servicebus: refactoring to use `hashicorp/go-azure-sdk` ([#17628](https://github.com/hashicorp/terraform-provider-azurerm/issues/17628)) +* postgres: refactoring to use `hashicorp/go-azure-sdk` ([#17625](https://github.com/hashicorp/terraform-provider-azurerm/issues/17625)) +* `azurerm_kusto_cluster_resource` - support for the `allowed_fqdns`, `allowed_ip_ranges`, and `outbound_network_access_restricted` properties ([#17581](https://github.com/hashicorp/terraform-provider-azurerm/issues/17581)) +* `azurerm_storage_account` - supports for the `change_feed_retention_in_days` property ([#17130](https://github.com/hashicorp/terraform-provider-azurerm/issues/17130)) ## 3.14.0 (July 14, 2022) diff --git a/README.md b/README.md index 764ae6ad4c3e..d3a28291429f 100644 --- a/README.md +++ b/README.md @@ -60,4 +60,4 @@ resource "azurerm_virtual_network" "example" { ## Developing & Contributing to the Provider -The [DEVELOPER.md](DEVELOPER.md) file is a basic outline on how to build and develop the provider while more detailed guides geared towards contributors can be found in the [`/contributing`] (https://github.com/hashicorp/terraform-provider-azurerm/tree/main/contributing) directory of this repository. +The [DEVELOPER.md](DEVELOPER.md) file is a basic outline on how to build and develop the provider while more detailed guides geared towards contributors can be found in the [`/contributing`](https://github.com/hashicorp/terraform-provider-azurerm/tree/main/contributing) directory of this repository. diff --git a/contributing/topics/guide-new-data-source.md b/contributing/topics/guide-new-data-source.md index a74260961805..b6385c92359b 100644 --- a/contributing/topics/guide-new-data-source.md +++ b/contributing/topics/guide-new-data-source.md @@ -588,7 +588,7 @@ In addition to the Arguments listed above - the following Attributes are exporte ## Timeouts -The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/language/resources/syntax#operation-timeouts) for certain actions: * `read` - (Defaults to 5 minutes) Used when retrieving the Resource Group. ``` diff --git a/contributing/topics/guide-new-resource.md b/contributing/topics/guide-new-resource.md index 4e9aaa68531a..a453b82182b6 100644 --- a/contributing/topics/guide-new-resource.md +++ b/contributing/topics/guide-new-resource.md @@ -833,7 +833,7 @@ In addition to the Arguments listed above - the following Attributes are exporte ## Timeouts -The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/language/resources/syntax#operation-timeouts) for certain actions: * `create` - (Defaults to 30 minutes) Used when creating the Resource Group. * `read` - (Defaults to 5 minutes) Used when retrieving the Resource Group. diff --git a/contributing/topics/guide-opening-a-pr.md b/contributing/topics/guide-opening-a-pr.md index a09351ac76e6..bb17d9c196d1 100644 --- a/contributing/topics/guide-opening-a-pr.md +++ b/contributing/topics/guide-opening-a-pr.md @@ -2,7 +2,7 @@ Firstly all contributions are welcome! -There is no change to small for us to accept and minor formatting, consistency and documentation PRs are very welcome! However, before making any large or structural changes it is recommended to seek feedback (preferably by reaching out in our community slack) to prevent wasted time and effort. We may already be working on a solution, or have a different direction we would like to take. +There is no change too small for us to accept and minor formatting, consistency and documentation PRs are very welcome! However, before making any large or structural changes it is recommended to seek feedback (preferably by reaching out in our community slack) to prevent wasted time and effort. We may already be working on a solution, or have a different direction we would like to take. If you are ever unsure please just reach out, we are more than happy to guide you in the right direction! @@ -54,6 +54,7 @@ Examples of good PR titles: - `azurerm_storage_management_policy - Mark rule.filters.blob_type as required` - `azurerm_container_registry - support updating replications on demand` +- `azurerm_automation_account - support for the encrytion, local_authentication_enabled, and tags properties` - `Data Source: azurerm_automation_account - prevent panic (#15474) by adding a nil check` - `Upgrade bot API version from 2021-03-01 to 2021-05-01-preview` - `New Resource: azurerm_managed_disk_sas_token` @@ -68,6 +69,7 @@ Examples of poorly written PR titles: - `upgrade sdk` - `upgrade compute api` - `add cosmos property` +- `support encryption, local_authentication_enabled properties` ### Description @@ -77,4 +79,4 @@ It should also link to any related issues/PRs and include the following for any ``` fixes #1234,#5678 - ``` \ No newline at end of file + ``` diff --git a/examples/app-service/docker-compose/README.md b/examples/app-service/docker-compose/README.md index 8b6110ed6320..fec82c6ee2dd 100644 --- a/examples/app-service/docker-compose/README.md +++ b/examples/app-service/docker-compose/README.md @@ -5,7 +5,7 @@ This example provisions a Linux App Service which runs multiple Docker Container ### Notes * The Container is launched on the first HTTP Request, which can take a while. -* If you're not using App Service Slots and Deployments are handled outside of Terraform - [it's possible to ignore changes to specific fields in the configuration using `ignore_changes` within Terraform's `lifecycle` block](https://www.terraform.io/docs/configuration/resources.html#lifecycle), for example: +* If you're not using App Service Slots and Deployments are handled outside of Terraform - [it's possible to ignore changes to specific fields in the configuration using `ignore_changes` within Terraform's `lifecycle` block](https://www.terraform.io/language/meta-arguments/lifecycle#ignore_changes), for example: ```hcl resource "azurerm_app_service" "test" { diff --git a/examples/app-service/docker-kubernetes/README.md b/examples/app-service/docker-kubernetes/README.md index 412036f32e3f..340f7ef5905f 100644 --- a/examples/app-service/docker-kubernetes/README.md +++ b/examples/app-service/docker-kubernetes/README.md @@ -5,7 +5,7 @@ This example provisions a Linux App Service which runs multiple Docker Container ### Notes * The Container is launched on the first HTTP Request, which can take a while. -* If you're not using App Service Slots and Deployments are handled outside of Terraform - [it's possible to ignore changes to specific fields in the configuration using `ignore_changes` within Terraform's `lifecycle` block](https://www.terraform.io/docs/configuration/resources.html#lifecycle), for example: +* If you're not using App Service Slots and Deployments are handled outside of Terraform - [it's possible to ignore changes to specific fields in the configuration using `ignore_changes` within Terraform's `lifecycle` block](https://www.terraform.io/language/meta-arguments/lifecycle#ignore_changes), for example: ```hcl resource "azurerm_app_service" "test" { diff --git a/examples/private-endpoint/private-link-scope/README.md b/examples/private-endpoint/private-link-scope/README.md new file mode 100644 index 000000000000..e5411e01a7b3 --- /dev/null +++ b/examples/private-endpoint/private-link-scope/README.md @@ -0,0 +1,9 @@ +## Example: Private Endpoint + +This example provisions a Private Endpoint which connects to a Private Link Scope within Azure. + +### Variables + +* `prefix` - (Required) The prefix used for all resources in this example. + +* `location` - (Required) The Azure Region in which all resources in this example should be created. diff --git a/examples/private-endpoint/private-link-scope/main.tf b/examples/private-endpoint/private-link-scope/main.tf new file mode 100644 index 000000000000..a3a3198658f2 --- /dev/null +++ b/examples/private-endpoint/private-link-scope/main.tf @@ -0,0 +1,64 @@ +provider "azurerm" { + features {} +} + +locals { + private_dns_zones_names = toset([ + "privatelink.agentsvc.azure-automation.net", + "privatelink.blob.core.windows.net", + "privatelink.monitor.azure.com", + "privatelink.ods.opinsights.azure.com", + "privatelink.oms.opinsights.azure.com", + ]) +} + +resource "azurerm_resource_group" "example" { + name = "${var.prefix}-resources" + location = var.location +} + +resource "azurerm_virtual_network" "example" { + name = "${var.prefix}-vnet" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name +} + +resource "azurerm_subnet" "example" { + name = "${var.prefix}-subnet" + resource_group_name = azurerm_resource_group.example.name + virtual_network_name = azurerm_virtual_network.example.name + address_prefixes = ["10.0.1.0/24"] + enforce_private_link_service_network_policies = true +} + +resource "azurerm_private_dns_zone" "example" { + for_each = local.private_dns_zones_names + + name = each.value + resource_group_name = azurerm_resource_group.example.name +} + +resource "azurerm_monitor_private_link_scope" "example" { + name = "${var.prefix}-ampls" + resource_group_name = azurerm_resource_group.example.name +} + +resource "azurerm_private_endpoint" "this" { + name = "${var.prefix}-ape" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + subnet_id = azurerm_subnet.example.id + + private_dns_zone_group { + name = "default" + private_dns_zone_ids = [for _, v in azurerm_private_dns_zone.example : v.id] + } + + private_service_connection { + name = "${var.prefix}-psc" + is_manual_connection = false + private_connection_resource_id = azurerm_monitor_private_link_scope.example.id + subresource_names = ["azuremonitor"] + } +} diff --git a/examples/private-endpoint/private-link-scope/variables.tf b/examples/private-endpoint/private-link-scope/variables.tf new file mode 100644 index 000000000000..0e6145faa285 --- /dev/null +++ b/examples/private-endpoint/private-link-scope/variables.tf @@ -0,0 +1,7 @@ +variable "prefix" { + description = "The Prefix used for all resources in this example" +} + +variable "location" { + description = "The Azure Region in which all resources in this example should be created." +} diff --git a/examples/virtual-machines/linux/load-balanced/main.tf b/examples/virtual-machines/linux/load-balanced/main.tf index b1e7bdbbe0d1..6b678c5e71cf 100644 --- a/examples/virtual-machines/linux/load-balanced/main.tf +++ b/examples/virtual-machines/linux/load-balanced/main.tf @@ -72,6 +72,11 @@ resource "azurerm_network_security_group" "webserver" { } } +resource "azurerm_subnet_network_security_group_association" "example" { + subnet_id = azurerm_subnet.internal.id + network_security_group_id = azurerm_network_security_group.webserver.id +} + resource "azurerm_lb" "example" { name = "${var.prefix}-lb" location = azurerm_resource_group.main.location diff --git a/go.mod b/go.mod index 070258b4990f..72ea61c6509a 100644 --- a/go.mod +++ b/go.mod @@ -12,8 +12,8 @@ require ( github.com/gofrs/uuid v4.0.0+incompatible github.com/google/go-cmp v0.5.8 github.com/google/uuid v1.1.2 - github.com/hashicorp/go-azure-helpers v0.37.0 - github.com/hashicorp/go-azure-sdk v0.20220715.1071215 + github.com/hashicorp/go-azure-helpers v0.40.0 + github.com/hashicorp/go-azure-sdk v0.20220830.1105041 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-uuid v1.0.3 github.com/hashicorp/go-version v1.6.0 @@ -23,7 +23,6 @@ require ( github.com/mitchellh/mapstructure v1.5.0 github.com/rickb777/date v1.12.5-0.20200422084442-6300e543c4d9 github.com/sergi/go-diff v1.2.0 - github.com/shopspring/decimal v1.2.0 github.com/tombuildsstuff/giovanni v0.20.0 golang.org/x/crypto v0.0.0-20220517005047-85d78b3ac167 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 diff --git a/go.sum b/go.sum index c7d21e59ece3..c1989567e546 100644 --- a/go.sum +++ b/go.sum @@ -214,10 +214,10 @@ github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brv github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-azure-helpers v0.12.0/go.mod h1:Zc3v4DNeX6PDdy7NljlYpnrdac1++qNW0I4U+ofGwpg= -github.com/hashicorp/go-azure-helpers v0.37.0 h1:6UOoQ9esE4MJ4wHJr21qU81IJQ9zsXQ9FbANYUbeE4U= -github.com/hashicorp/go-azure-helpers v0.37.0/go.mod h1:gcutZ/Hf/O7YN9M3UIvyZ9l0Rxv7Yrc9x5sSfM9cuSw= -github.com/hashicorp/go-azure-sdk v0.20220715.1071215 h1:PZYeATYa/qh1KM5RxKC8eTSKms5/sqbZohSCcemzrJo= -github.com/hashicorp/go-azure-sdk v0.20220715.1071215/go.mod h1:yjQPw8DCOtQR8E8+FNaTxF6yz+tyQGkDNiVAGCNoLOo= +github.com/hashicorp/go-azure-helpers v0.40.0 h1:NjiyF+jN+0mRdFBU894yzZSxu1SNrbvj8l4rEDpCB0A= +github.com/hashicorp/go-azure-helpers v0.40.0/go.mod h1:gcutZ/Hf/O7YN9M3UIvyZ9l0Rxv7Yrc9x5sSfM9cuSw= +github.com/hashicorp/go-azure-sdk v0.20220830.1105041 h1:LNW0aW2CMNmfTyN4u+h6yxXrAsRcQdNSWSL/NVs6ZVY= +github.com/hashicorp/go-azure-sdk v0.20220830.1105041/go.mod h1:jOhjVttoXh2We/glz4BC/0t0Lo8+M9WQBA4sbAPQPMY= github.com/hashicorp/go-checkpoint v0.5.0 h1:MFYpPZCnQqQTE18jFwSII6eUQrD/oxMFp3mlgcqk5mU= github.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuDrwkBuEQsVcpCOgg= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= @@ -347,8 +347,6 @@ github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAm github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= -github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/helpers/validate/float.go b/helpers/validate/float.go index 199505be6f42..7d712ac334a4 100644 --- a/helpers/validate/float.go +++ b/helpers/validate/float.go @@ -25,3 +25,32 @@ func FloatInSlice(valid []float64) func(interface{}, string) ([]string, []error) return warnings, errors } } + +func FloatInRange(start, end float64) func(interface{}, string) ([]string, []error) { + return func(i interface{}, k string) (warnings []string, errors []error) { + v, ok := i.(float64) + if !ok { + errors = append(errors, fmt.Errorf("expected type of %s to be float", i)) + return warnings, errors + } + + if v < start || v > end { + errors = append(errors, fmt.Errorf("expected %s to be in range [%f, %f], got %f", k, start, end, v)) + } + + return warnings, errors + } +} + +func IntegerPositive(i interface{}, k string) (warnings []string, errors []error) { + v, ok := i.(int) + if !ok { + errors = append(errors, fmt.Errorf("expected type of %s to be int", i)) + return + } + if v <= 0 { + errors = append(errors, fmt.Errorf("expected %s to be positive, got %d", k, v)) + return + } + return +} diff --git a/internal/clients/client.go b/internal/clients/client.go index a1db6778fa33..966279125650 100644 --- a/internal/clients/client.go +++ b/internal/clients/client.go @@ -5,6 +5,7 @@ import ( "github.com/Azure/go-autorest/autorest" "github.com/Azure/go-autorest/autorest/validation" + dns_v2018_05_01 "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01" "github.com/hashicorp/terraform-provider-azurerm/internal/common" "github.com/hashicorp/terraform-provider-azurerm/internal/features" aadb2c "github.com/hashicorp/terraform-provider-azurerm/internal/services/aadb2c/client" @@ -32,9 +33,11 @@ import ( cosmosdb "github.com/hashicorp/terraform-provider-azurerm/internal/services/cosmos/client" costmanagement "github.com/hashicorp/terraform-provider-azurerm/internal/services/costmanagement/client" customproviders "github.com/hashicorp/terraform-provider-azurerm/internal/services/customproviders/client" + dashboard "github.com/hashicorp/terraform-provider-azurerm/internal/services/dashboard/client" datamigration "github.com/hashicorp/terraform-provider-azurerm/internal/services/databasemigration/client" databoxedge "github.com/hashicorp/terraform-provider-azurerm/internal/services/databoxedge/client" databricks "github.com/hashicorp/terraform-provider-azurerm/internal/services/databricks/client" + datadog "github.com/hashicorp/terraform-provider-azurerm/internal/services/datadog/client" datafactory "github.com/hashicorp/terraform-provider-azurerm/internal/services/datafactory/client" dataprotection "github.com/hashicorp/terraform-provider-azurerm/internal/services/dataprotection/client" datashare "github.com/hashicorp/terraform-provider-azurerm/internal/services/datashare/client" @@ -96,6 +99,7 @@ import ( securityCenter "github.com/hashicorp/terraform-provider-azurerm/internal/services/securitycenter/client" sentinel "github.com/hashicorp/terraform-provider-azurerm/internal/services/sentinel/client" serviceBus "github.com/hashicorp/terraform-provider-azurerm/internal/services/servicebus/client" + serviceConnector "github.com/hashicorp/terraform-provider-azurerm/internal/services/serviceconnector/client" serviceFabric "github.com/hashicorp/terraform-provider-azurerm/internal/services/servicefabric/client" serviceFabricManaged "github.com/hashicorp/terraform-provider-azurerm/internal/services/servicefabricmanaged/client" signalr "github.com/hashicorp/terraform-provider-azurerm/internal/services/signalr/client" @@ -144,9 +148,11 @@ type Client struct { Cosmos *cosmosdb.Client CostManagement *costmanagement.Client CustomProviders *customproviders.Client + Dashboard *dashboard.Client DatabaseMigration *datamigration.Client DataBricks *databricks.Client DataboxEdge *databoxedge.Client + Datadog *datadog.Client DataFactory *datafactory.Client DataProtection *dataprotection.Client DataShare *datashare.Client @@ -154,7 +160,7 @@ type Client struct { DevTestLabs *devtestlabs.Client DigitalTwins *digitaltwins.Client Disks *disks.Client - Dns *dns.Client + Dns *dns_v2018_05_01.Client DomainServices *domainservices.Client Elastic *elastic.Client EventGrid *eventgrid.Client @@ -208,6 +214,7 @@ type Client struct { SecurityCenter *securityCenter.Client Sentinel *sentinel.Client ServiceBus *serviceBus.Client + ServiceConnector *serviceConnector.Client ServiceFabric *serviceFabric.Client ServiceFabricManaged *serviceFabricManaged.Client SignalR *signalr.Client @@ -258,9 +265,11 @@ func (client *Client) Build(ctx context.Context, o *common.ClientOptions) error client.Cosmos = cosmosdb.NewClient(o) client.CostManagement = costmanagement.NewClient(o) client.CustomProviders = customproviders.NewClient(o) + client.Dashboard = dashboard.NewClient(o) client.DatabaseMigration = datamigration.NewClient(o) client.DataBricks = databricks.NewClient(o) client.DataboxEdge = databoxedge.NewClient(o) + client.Datadog = datadog.NewClient(o) client.DataFactory = datafactory.NewClient(o) client.DataProtection = dataprotection.NewClient(o) client.DataShare = datashare.NewClient(o) @@ -322,6 +331,7 @@ func (client *Client) Build(ctx context.Context, o *common.ClientOptions) error client.SecurityCenter = securityCenter.NewClient(o) client.Sentinel = sentinel.NewClient(o) client.ServiceBus = serviceBus.NewClient(o) + client.ServiceConnector = serviceConnector.NewClient(o) client.ServiceFabric = serviceFabric.NewClient(o) client.ServiceFabricManaged = serviceFabricManaged.NewClient(o) client.SignalR = signalr.NewClient(o) diff --git a/internal/common/client_options.go b/internal/common/client_options.go index b8330a62f929..7fb708fdc141 100644 --- a/internal/common/client_options.go +++ b/internal/common/client_options.go @@ -82,6 +82,7 @@ func setUserAgent(client *autorest.Client, tfVersion, partnerID string, disableT } if partnerID != "" { - client.UserAgent = fmt.Sprintf("%s pid-%s", client.UserAgent, partnerID) + // Tolerate partnerID UUIDs without the "pid-" prefix + client.UserAgent = fmt.Sprintf("%s pid-%s", client.UserAgent, strings.TrimPrefix(partnerID, "pid-")) } } diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 1e6faa4798b6..ed2904c5a569 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -25,6 +25,67 @@ func TestAzureProvider() *schema.Provider { return azureProvider(true) } +func ValidatePartnerID(i interface{}, k string) ([]string, []error) { + // ValidatePartnerID checks if partner_id is any of the following: + // * a valid UUID - will add "pid-" prefix to the ID if it is not already present + // * a valid UUID prefixed with "pid-" + // * a valid UUID prefixed with "pid-" and suffixed with "-partnercenter" + + debugLog := func(f string, v ...interface{}) { + if os.Getenv("TF_LOG") == "" { + return + } + + if os.Getenv("TF_ACC") != "" { + return + } + + log.Printf(f, v...) + } + + v, ok := i.(string) + if !ok { + return nil, []error{fmt.Errorf("expected type of %q to be string", k)} + } + + if v == "" { + return nil, nil + } + + // Check for pid=-partnercenter format + if strings.HasPrefix(v, "pid-") && strings.HasSuffix(v, "-partnercenter") { + g := strings.TrimPrefix(v, "pid-") + g = strings.TrimSuffix(g, "-partnercenter") + + if _, err := validation.IsUUID(g, ""); err != nil { + return nil, []error{fmt.Errorf("expected %q to contain a valid UUID", v)} + } + + debugLog("[DEBUG] %q partner_id matches pid--partnercenter...", v) + return nil, nil + } + + // Check for pid= (without the -partnercenter suffix) + if strings.HasPrefix(v, "pid-") && !strings.HasSuffix(v, "-partnercenter") { + g := strings.TrimPrefix(v, "pid-") + + if _, err := validation.IsUUID(g, ""); err != nil { + return nil, []error{fmt.Errorf("expected %q to be a valid UUID", k)} + } + + debugLog("[DEBUG] %q partner_id matches pid-...", v) + return nil, nil + } + + // Check for straight UUID + if _, err := validation.IsUUID(v, ""); err != nil { + return nil, []error{fmt.Errorf("expected %q to be a valid UUID", k)} + } else { + debugLog("[DEBUG] %q partner_id is an un-prefixed UUID...", v) + return nil, nil + } +} + func azureProvider(supportLegacyTestSuite bool) *schema.Provider { // avoids this showing up in test output debugLog := func(f string, v ...interface{}) { @@ -171,13 +232,20 @@ func azureProvider(supportLegacyTestSuite bool) *schema.Provider { Type: schema.TypeString, Optional: true, DefaultFunc: schema.MultiEnvDefaultFunc([]string{"ARM_OIDC_REQUEST_TOKEN", "ACTIONS_ID_TOKEN_REQUEST_TOKEN"}, ""), - Description: "The bearer token for the request to the OIDC provider. For use When authenticating as a Service Principal using OpenID Connect.", + Description: "The bearer token for the request to the OIDC provider. For use when authenticating as a Service Principal using OpenID Connect.", }, "oidc_request_url": { Type: schema.TypeString, Optional: true, DefaultFunc: schema.MultiEnvDefaultFunc([]string{"ARM_OIDC_REQUEST_URL", "ACTIONS_ID_TOKEN_REQUEST_URL"}, ""), - Description: "The URL for the OIDC provider from which to request an ID token. For use When authenticating as a Service Principal using OpenID Connect.", + Description: "The URL for the OIDC provider from which to request an ID token. For use when authenticating as a Service Principal using OpenID Connect.", + }, + + "oidc_token": { + Type: schema.TypeString, + Optional: true, + DefaultFunc: schema.EnvDefaultFunc("ARM_OIDC_TOKEN", ""), + Description: "The OIDC ID token for use when authenticating as a Service Principal using OpenID Connect.", }, "use_oidc": { @@ -205,7 +273,7 @@ func azureProvider(supportLegacyTestSuite bool) *schema.Provider { "partner_id": { Type: schema.TypeString, Optional: true, - ValidateFunc: validation.Any(validation.IsUUID, validation.StringIsEmpty), + ValidateFunc: validation.Any(ValidatePartnerID, validation.StringIsEmpty), DefaultFunc: schema.EnvDefaultFunc("ARM_PARTNER_ID", ""), Description: "A GUID/UUID that is registered with Microsoft to facilitate partner resource usage attribution.", }, @@ -279,6 +347,7 @@ func providerConfigure(p *schema.Provider) schema.ConfigureContextFunc { ClientCertPath: d.Get("client_certificate_path").(string), IDTokenRequestToken: d.Get("oidc_request_token").(string), IDTokenRequestURL: d.Get("oidc_request_url").(string), + IDToken: d.Get("oidc_token").(string), // Feature Toggles SupportsClientCertAuth: true, diff --git a/internal/provider/provider_test.go b/internal/provider/provider_test.go index 611f97cdf7e7..17323b9ce387 100644 --- a/internal/provider/provider_test.go +++ b/internal/provider/provider_test.go @@ -76,7 +76,15 @@ func TestResourcesSupportCustomTimeouts(t *testing.T) { if resource.Timeouts.Read == nil { t.Fatalf("Resource %q doesn't define a Read timeout", resourceName) } else if *resource.Timeouts.Read > 5*time.Minute { - t.Fatalf("Read timeouts shouldn't be more than 5 minutes, this indicates a bug which needs to be fixed") + exceptionResources := map[string]bool{ + // The key vault item resources have longer read timeout for mitigating issue: https://github.com/hashicorp/terraform-provider-azurerm/issues/11059. + "azurerm_key_vault_key": true, + "azurerm_key_vault_secret": true, + "azurerm_key_vault_certificate": true, + } + if !exceptionResources[resourceName] { + t.Fatalf("Read timeouts shouldn't be more than 5 minutes, this indicates a bug which needs to be fixed") + } } // Optional diff --git a/internal/provider/services.go b/internal/provider/services.go index a0a52d2c40d3..a7e8080fbdf8 100644 --- a/internal/provider/services.go +++ b/internal/provider/services.go @@ -28,9 +28,11 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/internal/services/cosmos" "github.com/hashicorp/terraform-provider-azurerm/internal/services/costmanagement" "github.com/hashicorp/terraform-provider-azurerm/internal/services/customproviders" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/dashboard" "github.com/hashicorp/terraform-provider-azurerm/internal/services/databasemigration" "github.com/hashicorp/terraform-provider-azurerm/internal/services/databoxedge" "github.com/hashicorp/terraform-provider-azurerm/internal/services/databricks" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/datadog" "github.com/hashicorp/terraform-provider-azurerm/internal/services/datafactory" "github.com/hashicorp/terraform-provider-azurerm/internal/services/dataprotection" "github.com/hashicorp/terraform-provider-azurerm/internal/services/datashare" @@ -92,6 +94,7 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/internal/services/securitycenter" "github.com/hashicorp/terraform-provider-azurerm/internal/services/sentinel" "github.com/hashicorp/terraform-provider-azurerm/internal/services/servicebus" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/serviceconnector" "github.com/hashicorp/terraform-provider-azurerm/internal/services/servicefabric" "github.com/hashicorp/terraform-provider-azurerm/internal/services/servicefabricmanaged" "github.com/hashicorp/terraform-provider-azurerm/internal/services/signalr" @@ -116,12 +119,15 @@ func SupportedTypedServices() []sdk.TypedServiceRegistration { appconfiguration.Registration{}, applicationinsights.Registration{}, appservice.Registration{}, + automation.Registration{}, batch.Registration{}, bot.Registration{}, compute.Registration{}, consumption.Registration{}, containers.Registration{}, + cosmos.Registration{}, costmanagement.Registration{}, + dashboard.Registration{}, disks.Registration{}, domainservices.Registration{}, eventhub.Registration{}, @@ -129,12 +135,17 @@ func SupportedTypedServices() []sdk.TypedServiceRegistration { keyvault.Registration{}, loadbalancer.Registration{}, loadtest.Registration{}, + loganalytics.Registration{}, + monitor.Registration{}, mssql.Registration{}, policy.Registration{}, + recoveryservices.Registration{}, resource.Registration{}, sentinel.Registration{}, + serviceconnector.Registration{}, servicefabricmanaged.Registration{}, streamanalytics.Registration{}, + search.Registration{}, web.Registration{}, } } @@ -166,7 +177,9 @@ func SupportedUntypedServices() []sdk.UntypedServiceRegistration { consumption.Registration{}, cosmos.Registration{}, customproviders.Registration{}, + dashboard.Registration{}, databricks.Registration{}, + datadog.Registration{}, datafactory.Registration{}, databasemigration.Registration{}, databoxedge.Registration{}, diff --git a/internal/services/analysisservices/analysis_services_server_resource.go b/internal/services/analysisservices/analysis_services_server_resource.go index cffade59cf1b..ce6723425ff4 100644 --- a/internal/services/analysisservices/analysis_services_server_resource.go +++ b/internal/services/analysisservices/analysis_services_server_resource.go @@ -107,7 +107,7 @@ func resourceAnalysisServicesServer() *pluginsdk.Resource { }, }, }, - Set: hashAnalysisServicesServerIpv4FirewallRule, + Set: hashAnalysisServicesServerIPv4FirewallRule, }, "querypool_connection_mode": { @@ -323,7 +323,7 @@ func expandAnalysisServicesServerProperties(d *pluginsdk.ResourceData) *servers. AsAdministrators: adminUsers, } - serverProperties.IpV4FirewallSettings = expandAnalysisServicesServerFirewallSettings(d) + serverProperties.IPV4FirewallSettings = expandAnalysisServicesServerFirewallSettings(d) if querypoolConnectionMode, ok := d.GetOk("querypool_connection_mode"); ok { connectionMode := servers.ConnectionMode(querypoolConnectionMode.(string)) @@ -344,7 +344,7 @@ func expandAnalysisServicesServerMutableProperties(d *pluginsdk.ResourceData) *s AsAdministrators: adminUsers, } - serverProperties.IpV4FirewallSettings = expandAnalysisServicesServerFirewallSettings(d) + serverProperties.IPV4FirewallSettings = expandAnalysisServicesServerFirewallSettings(d) connectionMode := servers.ConnectionMode(d.Get("querypool_connection_mode").(string)) serverProperties.QuerypoolConnectionMode = &connectionMode @@ -393,11 +393,11 @@ func expandAnalysisServicesServerFirewallSettings(d *pluginsdk.ResourceData) *se } func flattenAnalysisServicesServerFirewallSettings(serverProperties *servers.AnalysisServicesServerProperties) (*bool, *pluginsdk.Set) { - if serverProperties == nil || serverProperties.IpV4FirewallSettings == nil { - return utils.Bool(false), pluginsdk.NewSet(hashAnalysisServicesServerIpv4FirewallRule, make([]interface{}, 0)) + if serverProperties == nil || serverProperties.IPV4FirewallSettings == nil { + return utils.Bool(false), pluginsdk.NewSet(hashAnalysisServicesServerIPv4FirewallRule, make([]interface{}, 0)) } - firewallSettings := serverProperties.IpV4FirewallSettings + firewallSettings := serverProperties.IPV4FirewallSettings enablePowerBi := utils.Bool(false) if firewallSettings.EnablePowerBIService != nil { @@ -424,10 +424,10 @@ func flattenAnalysisServicesServerFirewallSettings(serverProperties *servers.Ana } } - return enablePowerBi, pluginsdk.NewSet(hashAnalysisServicesServerIpv4FirewallRule, fwRules) + return enablePowerBi, pluginsdk.NewSet(hashAnalysisServicesServerIPv4FirewallRule, fwRules) } -func hashAnalysisServicesServerIpv4FirewallRule(v interface{}) int { +func hashAnalysisServicesServerIPv4FirewallRule(v interface{}) int { var buf bytes.Buffer m := v.(map[string]interface{}) diff --git a/internal/services/apimanagement/api_management_gateway_certificate_authority_resource.go b/internal/services/apimanagement/api_management_gateway_certificate_authority_resource.go new file mode 100644 index 000000000000..4fa00c2e78af --- /dev/null +++ b/internal/services/apimanagement/api_management_gateway_certificate_authority_resource.go @@ -0,0 +1,151 @@ +package apimanagement + +import ( + "fmt" + "log" + "time" + + "github.com/Azure/azure-sdk-for-go/services/apimanagement/mgmt/2021-08-01/apimanagement" + "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/apimanagement/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/apimanagement/schemaz" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/apimanagement/validate" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +func resourceApiManagementGatewayCertificateAuthority() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Create: resourceApiManagementGatewayCertificateAuthorityCreateUpdate, + Read: resourceApiManagementGatewayCertificateAuthorityRead, + Update: resourceApiManagementGatewayCertificateAuthorityCreateUpdate, + Delete: resourceApiManagementGatewayCertificateAuthorityDelete, + + Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { + _, err := parse.GatewayCertificateAuthorityID(id) + return err + }), + + Timeouts: &pluginsdk.ResourceTimeout{ + Create: pluginsdk.DefaultTimeout(30 * time.Minute), + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + Update: pluginsdk.DefaultTimeout(30 * time.Minute), + Delete: pluginsdk.DefaultTimeout(30 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "api_management_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.ApiManagementID, + }, + + "certificate_name": schemaz.SchemaApiManagementChildName(), + + "gateway_name": schemaz.SchemaApiManagementChildName(), + + "is_trusted": { + Type: pluginsdk.TypeBool, + Optional: true, + }, + }, + } +} + +func resourceApiManagementGatewayCertificateAuthorityCreateUpdate(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).ApiManagement.GatewayCertificateAuthorityClient + ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + + apimId, err := parse.ApiManagementID(d.Get("api_management_id").(string)) + if err != nil { + return fmt.Errorf("parsing `api_management_id`: %v", err) + } + + id := parse.NewGatewayCertificateAuthorityID(apimId.SubscriptionId, apimId.ResourceGroup, apimId.ServiceName, d.Get("gateway_name").(string), d.Get("certificate_name").(string)) + + if d.IsNewResource() { + existing, err := client.Get(ctx, id.ResourceGroup, id.ServiceName, id.GatewayName, d.Get("certificate_name").(string)) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("checking for presence of existing %s: %s", id, err) + } + } + + if !utils.ResponseWasNotFound(existing.Response) { + return tf.ImportAsExistsError("azurerm_api_management_gateway_certificate_authority", id.ID()) + } + } + + parameters := apimanagement.GatewayCertificateAuthorityContract{ + GatewayCertificateAuthorityContractProperties: &apimanagement.GatewayCertificateAuthorityContractProperties{ + IsTrusted: utils.Bool(d.Get("is_trusted").(bool)), + }, + } + + resp, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.ServiceName, d.Get("gateway_name").(string), d.Get("certificate_name").(string), parameters, "") + if err != nil { + return fmt.Errorf("creating or updating %s: %+v", id, err) + } + + d.SetId(*resp.ID) + + return resourceApiManagementGatewayCertificateAuthorityRead(d, meta) +} + +func resourceApiManagementGatewayCertificateAuthorityRead(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).ApiManagement.GatewayCertificateAuthorityClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.GatewayCertificateAuthorityID(d.Id()) + if err != nil { + return err + } + + resp, err := client.Get(ctx, id.ResourceGroup, id.ServiceName, id.GatewayName, id.CertificateAuthorityName) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("%s was not found - removing from state!", *id) + d.SetId("") + return nil + } + + return fmt.Errorf("making read request for %s: %+v", *id, err) + } + + apimId := parse.NewApiManagementID(id.SubscriptionId, id.ResourceGroup, id.ServiceName) + + d.Set("certificate_name", resp.Name) + d.Set("api_management_id", apimId.ID()) + d.Set("gateway_name", id.GatewayName) + + if properties := resp.GatewayCertificateAuthorityContractProperties; properties != nil { + d.Set("is_trusted", properties.IsTrusted) + } + + return nil +} + +func resourceApiManagementGatewayCertificateAuthorityDelete(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).ApiManagement.GatewayCertificateAuthorityClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.GatewayCertificateAuthorityID(d.Id()) + if err != nil { + return err + } + + log.Printf("[DEBUG] Deleting %s", *id) + if resp, err := client.Delete(ctx, id.ResourceGroup, id.ServiceName, id.GatewayName, id.CertificateAuthorityName, ""); err != nil { + if !utils.ResponseWasNotFound(resp) { + return fmt.Errorf("deleting %s: %+v", *id, err) + } + } + + return nil +} diff --git a/internal/services/apimanagement/api_management_gateway_certificate_authority_resource_test.go b/internal/services/apimanagement/api_management_gateway_certificate_authority_resource_test.go new file mode 100644 index 000000000000..5b162c86518d --- /dev/null +++ b/internal/services/apimanagement/api_management_gateway_certificate_authority_resource_test.go @@ -0,0 +1,254 @@ +package apimanagement_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/apimanagement/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type ApiManagementGatewayCertificateAuthorityResource struct{} + +func TestAccApiManagementGatewayCertificateAuthority_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_api_management_gateway_certificate_authority", "test") + r := ApiManagementGatewayCertificateAuthorityResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccApiManagementGatewayCertificateAuthority_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_api_management_gateway_certificate_authority", "test") + r := ApiManagementGatewayCertificateAuthorityResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func TestAccApiManagementGatewayCertificateAuthority_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_api_management_gateway_certificate_authority", "test") + r := ApiManagementGatewayCertificateAuthorityResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccApiManagementGatewayCertificateAuthority_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_api_management_gateway_certificate_authority", "test") + r := ApiManagementGatewayCertificateAuthorityResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + { + Config: r.update(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + }) +} + +func (ApiManagementGatewayCertificateAuthorityResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + id, err := parse.GatewayCertificateAuthorityID(state.ID) + if err != nil { + return nil, err + } + + resp, err := clients.ApiManagement.GatewayCertificateAuthorityClient.Get(ctx, id.ResourceGroup, id.ServiceName, id.GatewayName, id.CertificateAuthorityName) + if err != nil { + return nil, fmt.Errorf("reading Api Management Gateway Certificate Authority (%s): %+v", id, err) + } + + return utils.Bool(resp.ID != nil), nil +} + +func (ApiManagementGatewayCertificateAuthorityResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_api_management" "test" { + name = "acctestAM-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + publisher_name = "pub1" + publisher_email = "pub1@email.com" + + sku_name = "Developer_1" +} + +resource "azurerm_api_management_gateway" "test" { + name = "acctestAMGateway-%d" + api_management_id = azurerm_api_management.test.id + + location_data { + name = "test" + } +} + +resource "azurerm_api_management_certificate" "test" { + name = "example-cert" + api_management_name = azurerm_api_management.test.name + resource_group_name = azurerm_resource_group.test.name + data = filebase64("testdata/keyvaultcert.pfx") + password = "" +} + +resource "azurerm_api_management_gateway_certificate_authority" "test" { + api_management_id = azurerm_api_management.test.id + certificate_name = azurerm_api_management_certificate.test.name + gateway_name = azurerm_api_management_gateway.test.name +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} + +func (r ApiManagementGatewayCertificateAuthorityResource) requiresImport(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_api_management_gateway_certificate_authority" "import" { + api_management_id = azurerm_api_management_gateway_certificate_authority.test.api_management_id + certificate_name = azurerm_api_management_gateway_certificate_authority.test.certificate_name + gateway_name = azurerm_api_management_gateway_certificate_authority.test.gateway_name +} +`, r.basic(data)) +} + +func (ApiManagementGatewayCertificateAuthorityResource) update(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_api_management" "test" { + name = "acctestAM-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + publisher_name = "pub1" + publisher_email = "pub1@email.com" + + sku_name = "Developer_1" +} + +resource "azurerm_api_management_gateway" "test" { + name = "acctestAMGateway-%d" + api_management_id = azurerm_api_management.test.id + + location_data { + name = "test" + } +} + +resource "azurerm_api_management_certificate" "test" { + name = "example-cert" + api_management_name = azurerm_api_management.test.name + resource_group_name = azurerm_resource_group.test.name + data = filebase64("testdata/keyvaultcert.pfx") + password = "" +} + +resource "azurerm_api_management_gateway_certificate_authority" "test" { + api_management_id = azurerm_api_management.test.id + certificate_name = azurerm_api_management_certificate.test.name + gateway_name = azurerm_api_management_gateway.test.name + is_trusted = true +} + +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} + +func (ApiManagementGatewayCertificateAuthorityResource) complete(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_api_management" "test" { + name = "acctestAM-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + publisher_name = "pub1" + publisher_email = "pub1@email.com" + + sku_name = "Developer_1" +} + +resource "azurerm_api_management_gateway" "test" { + name = "acctestAMGateway-%d" + api_management_id = azurerm_api_management.test.id + + location_data { + name = "test" + } +} + +resource "azurerm_api_management_certificate" "test" { + name = "example-cert" + api_management_name = azurerm_api_management.test.name + resource_group_name = azurerm_resource_group.test.name + data = filebase64("testdata/keyvaultcert.pfx") + password = "" +} + +resource "azurerm_api_management_gateway_certificate_authority" "test" { + api_management_id = azurerm_api_management.test.id + certificate_name = azurerm_api_management_certificate.test.name + gateway_name = azurerm_api_management_gateway.test.name + is_trusted = false +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} diff --git a/internal/services/apimanagement/api_management_product_tag_resource.go b/internal/services/apimanagement/api_management_product_tag_resource.go new file mode 100644 index 000000000000..5533c1e1922a --- /dev/null +++ b/internal/services/apimanagement/api_management_product_tag_resource.go @@ -0,0 +1,130 @@ +package apimanagement + +import ( + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" + "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/apimanagement/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/apimanagement/schemaz" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +func resourceApiManagementProductTag() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Create: resourceApiManagementProductTagCreate, + Read: resourceApiManagementProductTagRead, + Delete: resourceApiManagementProductTagDelete, + Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { + _, err := parse.ProductTagID(id) + return err + }), + + Timeouts: &pluginsdk.ResourceTimeout{ + Create: pluginsdk.DefaultTimeout(30 * time.Minute), + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + Update: pluginsdk.DefaultTimeout(30 * time.Minute), + Delete: pluginsdk.DefaultTimeout(30 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "api_management_product_id": schemaz.SchemaApiManagementChildName(), + + "api_management_name": schemaz.SchemaApiManagementName(), + + "resource_group_name": azure.SchemaResourceGroupName(), + + "name": schemaz.SchemaApiManagementChildName(), + }, + } +} + +func resourceApiManagementProductTagCreate(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).ApiManagement.TagClient + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + + id := parse.NewProductTagID(subscriptionId, d.Get("resource_group_name").(string), d.Get("api_management_name").(string), d.Get("api_management_product_id").(string), d.Get("name").(string)) + + if d.IsNewResource() { + existing, err := client.GetByProduct(ctx, id.ResourceGroup, id.ServiceName, id.ProductName, id.TagName) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("checking for presence of existing %s: %s", id, err) + } + } + + if !utils.ResponseWasNotFound(existing.Response) { + return tf.ImportAsExistsError("azurerm_api_management_product_tag", id.ID()) + } + } + + resp, err := client.AssignToProduct(ctx, id.ResourceGroup, id.ServiceName, id.ProductName, id.TagName) + if err != nil { + return fmt.Errorf(" creating product tag (id : %s): %+v", id, err) + } + d.SetId(*resp.ID) + + return resourceApiManagementProductTagRead(d, meta) +} + +func resourceApiManagementProductTagRead(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).ApiManagement.TagClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.ProductTagID(d.Id()) + if err != nil { + return err + } + + resp, err := client.GetByProduct(ctx, id.ResourceGroup, id.ServiceName, id.ProductName, id.TagName) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("%s was not found - removing from state!", *id) + d.SetId("") + return nil + } + + return fmt.Errorf("making Read request on %s: %+v", *id, err) + } + + productTagId, err := parse.ProductTagID(*resp.ID) + if err != nil { + return err + } + + d.Set("api_management_product_id", productTagId.ProductName) + d.Set("api_management_name", productTagId.ServiceName) + d.Set("resource_group_name", productTagId.ResourceGroup) + d.Set("name", productTagId.TagName) + + return nil +} + +func resourceApiManagementProductTagDelete(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).ApiManagement.TagClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.ProductTagID(d.Id()) + if err != nil { + return err + } + + log.Printf("[DEBUG] Deleting %s", *id) + resp, err := client.DetachFromProduct(ctx, id.ResourceGroup, id.ServiceName, id.ProductName, id.TagName) + if err != nil { + if !utils.ResponseWasNotFound(resp) { + return fmt.Errorf("deleting %s: %+v", *id, err) + } + } + + return nil +} diff --git a/internal/services/apimanagement/api_management_product_tag_resource_test.go b/internal/services/apimanagement/api_management_product_tag_resource_test.go new file mode 100644 index 000000000000..080b8c08de4e --- /dev/null +++ b/internal/services/apimanagement/api_management_product_tag_resource_test.go @@ -0,0 +1,121 @@ +package apimanagement_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/apimanagement/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type ApiManagementProductTagResource struct{} + +func TestAccApiManagementProductTag_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_api_management_product_tag", "test") + r := ApiManagementProductTagResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("api_management_product_id").Exists(), + check.That(data.ResourceName).Key("api_management_name").Exists(), + check.That(data.ResourceName).Key("resource_group_name").Exists(), + check.That(data.ResourceName).Key("name").Exists(), + ), + }, + data.ImportStep(), + }) +} + +func TestAccApiManagementProductTag_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_api_management_product_tag", "test") + r := ApiManagementProductTagResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func (ApiManagementProductTagResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + id, err := parse.ProductTagID(state.ID) + if err != nil { + return nil, err + } + + resp, err := clients.ApiManagement.TagClient.GetByProduct(ctx, id.ResourceGroup, id.ServiceName, id.ProductName, id.TagName) + if err != nil { + return nil, fmt.Errorf("reading %s: %+v", *id, err) + } + + return utils.Bool(resp.ID != nil), nil +} + +func (ApiManagementProductTagResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_api_management" "test" { + name = "acctestAM-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + publisher_name = "pub1" + publisher_email = "pub1@email.com" + + sku_name = "Consumption_0" +} + +resource "azurerm_api_management_product" "test" { + product_id = "test-product" + api_management_name = azurerm_api_management.test.name + resource_group_name = azurerm_resource_group.test.name + display_name = "Test Product" + subscription_required = false + published = false +} + +resource "azurerm_api_management_tag" "test" { + api_management_id = azurerm_api_management.test.id + name = "acctestTag-%d" +} + +resource "azurerm_api_management_product_tag" "test" { + api_management_product_id = azurerm_api_management_product.test.product_id + api_management_name = azurerm_api_management.test.name + resource_group_name = azurerm_resource_group.test.name + name = azurerm_api_management_tag.test.name +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} + +func (r ApiManagementProductTagResource) requiresImport(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_api_management_product_tag" "import" { + api_management_product_id = azurerm_api_management_product_tag.test.api_management_product_id + api_management_name = azurerm_api_management_product_tag.test.api_management_name + resource_group_name = azurerm_api_management_product_tag.test.resource_group_name + name = azurerm_api_management_product_tag.test.name +} +`, r.basic(data)) +} diff --git a/internal/services/apimanagement/client/client.go b/internal/services/apimanagement/client/client.go index 12c09025c667..8fb138b155cb 100644 --- a/internal/services/apimanagement/client/client.go +++ b/internal/services/apimanagement/client/client.go @@ -6,43 +6,44 @@ import ( ) type Client struct { - ApiClient *apimanagement.APIClient - ApiDiagnosticClient *apimanagement.APIDiagnosticClient - ApiPoliciesClient *apimanagement.APIPolicyClient - ApiOperationsClient *apimanagement.APIOperationClient - ApiOperationPoliciesClient *apimanagement.APIOperationPolicyClient - ApiReleasesClient *apimanagement.APIReleaseClient - ApiSchemasClient *apimanagement.APISchemaClient - ApiVersionSetClient *apimanagement.APIVersionSetClient - AuthorizationServersClient *apimanagement.AuthorizationServerClient - BackendClient *apimanagement.BackendClient - CacheClient *apimanagement.CacheClient - CertificatesClient *apimanagement.CertificateClient - DiagnosticClient *apimanagement.DiagnosticClient - DeletedServicesClient *apimanagement.DeletedServicesClient - EmailTemplateClient *apimanagement.EmailTemplateClient - GatewayClient *apimanagement.GatewayClient - GatewayApisClient *apimanagement.GatewayAPIClient - GroupClient *apimanagement.GroupClient - GroupUsersClient *apimanagement.GroupUserClient - IdentityProviderClient *apimanagement.IdentityProviderClient - LoggerClient *apimanagement.LoggerClient - NamedValueClient *apimanagement.NamedValueClient - NotificationRecipientEmailClient *apimanagement.NotificationRecipientEmailClient - NotificationRecipientUserClient *apimanagement.NotificationRecipientUserClient - OpenIdConnectClient *apimanagement.OpenIDConnectProviderClient - PolicyClient *apimanagement.PolicyClient - ProductsClient *apimanagement.ProductClient - ProductApisClient *apimanagement.ProductAPIClient - ProductGroupsClient *apimanagement.ProductGroupClient - ProductPoliciesClient *apimanagement.ProductPolicyClient - ServiceClient *apimanagement.ServiceClient - SignInClient *apimanagement.SignInSettingsClient - SignUpClient *apimanagement.SignUpSettingsClient - SubscriptionsClient *apimanagement.SubscriptionClient - TagClient *apimanagement.TagClient - TenantAccessClient *apimanagement.TenantAccessClient - UsersClient *apimanagement.UserClient + ApiClient *apimanagement.APIClient + ApiDiagnosticClient *apimanagement.APIDiagnosticClient + ApiPoliciesClient *apimanagement.APIPolicyClient + ApiOperationsClient *apimanagement.APIOperationClient + ApiOperationPoliciesClient *apimanagement.APIOperationPolicyClient + ApiReleasesClient *apimanagement.APIReleaseClient + ApiSchemasClient *apimanagement.APISchemaClient + ApiVersionSetClient *apimanagement.APIVersionSetClient + AuthorizationServersClient *apimanagement.AuthorizationServerClient + BackendClient *apimanagement.BackendClient + CacheClient *apimanagement.CacheClient + CertificatesClient *apimanagement.CertificateClient + DiagnosticClient *apimanagement.DiagnosticClient + DeletedServicesClient *apimanagement.DeletedServicesClient + EmailTemplateClient *apimanagement.EmailTemplateClient + GatewayClient *apimanagement.GatewayClient + GatewayCertificateAuthorityClient *apimanagement.GatewayCertificateAuthorityClient + GatewayApisClient *apimanagement.GatewayAPIClient + GroupClient *apimanagement.GroupClient + GroupUsersClient *apimanagement.GroupUserClient + IdentityProviderClient *apimanagement.IdentityProviderClient + LoggerClient *apimanagement.LoggerClient + NamedValueClient *apimanagement.NamedValueClient + NotificationRecipientEmailClient *apimanagement.NotificationRecipientEmailClient + NotificationRecipientUserClient *apimanagement.NotificationRecipientUserClient + OpenIdConnectClient *apimanagement.OpenIDConnectProviderClient + PolicyClient *apimanagement.PolicyClient + ProductsClient *apimanagement.ProductClient + ProductApisClient *apimanagement.ProductAPIClient + ProductGroupsClient *apimanagement.ProductGroupClient + ProductPoliciesClient *apimanagement.ProductPolicyClient + ServiceClient *apimanagement.ServiceClient + SignInClient *apimanagement.SignInSettingsClient + SignUpClient *apimanagement.SignUpSettingsClient + SubscriptionsClient *apimanagement.SubscriptionClient + TagClient *apimanagement.TagClient + TenantAccessClient *apimanagement.TenantAccessClient + UsersClient *apimanagement.UserClient } func NewClient(o *common.ClientOptions) *Client { @@ -94,6 +95,9 @@ func NewClient(o *common.ClientOptions) *Client { gatewayClient := apimanagement.NewGatewayClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&gatewayClient.Client, o.ResourceManagerAuthorizer) + gatewayCertificateAuthorityClient := apimanagement.NewGatewayCertificateAuthorityClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&gatewayCertificateAuthorityClient.Client, o.ResourceManagerAuthorizer) + gatewayApisClient := apimanagement.NewGatewayAPIClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&gatewayApisClient.Client, o.ResourceManagerAuthorizer) @@ -158,42 +162,43 @@ func NewClient(o *common.ClientOptions) *Client { o.ConfigureClient(&usersClient.Client, o.ResourceManagerAuthorizer) return &Client{ - ApiClient: &apiClient, - ApiDiagnosticClient: &apiDiagnosticClient, - ApiPoliciesClient: &apiPoliciesClient, - ApiOperationsClient: &apiOperationsClient, - ApiOperationPoliciesClient: &apiOperationPoliciesClient, - ApiReleasesClient: &apiReleasesClient, - ApiSchemasClient: &apiSchemasClient, - ApiVersionSetClient: &apiVersionSetClient, - AuthorizationServersClient: &authorizationServersClient, - BackendClient: &backendClient, - CacheClient: &cacheClient, - CertificatesClient: &certificatesClient, - DiagnosticClient: &diagnosticClient, - DeletedServicesClient: &deletedServicesClient, - EmailTemplateClient: &emailTemplateClient, - GatewayClient: &gatewayClient, - GatewayApisClient: &gatewayApisClient, - GroupClient: &groupClient, - GroupUsersClient: &groupUsersClient, - IdentityProviderClient: &identityProviderClient, - LoggerClient: &loggerClient, - NamedValueClient: &namedValueClient, - NotificationRecipientEmailClient: ¬ificationRecipientEmailClient, - NotificationRecipientUserClient: ¬ificationRecipientUserClient, - OpenIdConnectClient: &openIdConnectClient, - PolicyClient: &policyClient, - ProductsClient: &productsClient, - ProductApisClient: &productApisClient, - ProductGroupsClient: &productGroupsClient, - ProductPoliciesClient: &productPoliciesClient, - ServiceClient: &serviceClient, - SignInClient: &signInClient, - SignUpClient: &signUpClient, - SubscriptionsClient: &subscriptionsClient, - TagClient: &tagClient, - TenantAccessClient: &tenantAccessClient, - UsersClient: &usersClient, + ApiClient: &apiClient, + ApiDiagnosticClient: &apiDiagnosticClient, + ApiPoliciesClient: &apiPoliciesClient, + ApiOperationsClient: &apiOperationsClient, + ApiOperationPoliciesClient: &apiOperationPoliciesClient, + ApiReleasesClient: &apiReleasesClient, + ApiSchemasClient: &apiSchemasClient, + ApiVersionSetClient: &apiVersionSetClient, + AuthorizationServersClient: &authorizationServersClient, + BackendClient: &backendClient, + CacheClient: &cacheClient, + CertificatesClient: &certificatesClient, + DiagnosticClient: &diagnosticClient, + DeletedServicesClient: &deletedServicesClient, + EmailTemplateClient: &emailTemplateClient, + GatewayClient: &gatewayClient, + GatewayCertificateAuthorityClient: &gatewayCertificateAuthorityClient, + GatewayApisClient: &gatewayApisClient, + GroupClient: &groupClient, + GroupUsersClient: &groupUsersClient, + IdentityProviderClient: &identityProviderClient, + LoggerClient: &loggerClient, + NamedValueClient: &namedValueClient, + NotificationRecipientEmailClient: ¬ificationRecipientEmailClient, + NotificationRecipientUserClient: ¬ificationRecipientUserClient, + OpenIdConnectClient: &openIdConnectClient, + PolicyClient: &policyClient, + ProductsClient: &productsClient, + ProductApisClient: &productApisClient, + ProductGroupsClient: &productGroupsClient, + ProductPoliciesClient: &productPoliciesClient, + ServiceClient: &serviceClient, + SignInClient: &signInClient, + SignUpClient: &signUpClient, + SubscriptionsClient: &subscriptionsClient, + TagClient: &tagClient, + TenantAccessClient: &tenantAccessClient, + UsersClient: &usersClient, } } diff --git a/internal/services/apimanagement/parse/gateway_certificate_authority.go b/internal/services/apimanagement/parse/gateway_certificate_authority.go new file mode 100644 index 000000000000..d8a8f530f78d --- /dev/null +++ b/internal/services/apimanagement/parse/gateway_certificate_authority.go @@ -0,0 +1,81 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + "strings" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +type GatewayCertificateAuthorityId struct { + SubscriptionId string + ResourceGroup string + ServiceName string + GatewayName string + CertificateAuthorityName string +} + +func NewGatewayCertificateAuthorityID(subscriptionId, resourceGroup, serviceName, gatewayName, certificateAuthorityName string) GatewayCertificateAuthorityId { + return GatewayCertificateAuthorityId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + ServiceName: serviceName, + GatewayName: gatewayName, + CertificateAuthorityName: certificateAuthorityName, + } +} + +func (id GatewayCertificateAuthorityId) String() string { + segments := []string{ + fmt.Sprintf("Certificate Authority Name %q", id.CertificateAuthorityName), + fmt.Sprintf("Gateway Name %q", id.GatewayName), + fmt.Sprintf("Service Name %q", id.ServiceName), + fmt.Sprintf("Resource Group %q", id.ResourceGroup), + } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "Gateway Certificate Authority", segmentsStr) +} + +func (id GatewayCertificateAuthorityId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.ApiManagement/service/%s/gateways/%s/certificateAuthorities/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.ServiceName, id.GatewayName, id.CertificateAuthorityName) +} + +// GatewayCertificateAuthorityID parses a GatewayCertificateAuthority ID into an GatewayCertificateAuthorityId struct +func GatewayCertificateAuthorityID(input string) (*GatewayCertificateAuthorityId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := GatewayCertificateAuthorityId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + if resourceId.ServiceName, err = id.PopSegment("service"); err != nil { + return nil, err + } + if resourceId.GatewayName, err = id.PopSegment("gateways"); err != nil { + return nil, err + } + if resourceId.CertificateAuthorityName, err = id.PopSegment("certificateAuthorities"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} diff --git a/internal/services/apimanagement/parse/gateway_certificate_authority_test.go b/internal/services/apimanagement/parse/gateway_certificate_authority_test.go new file mode 100644 index 000000000000..ab5b9ab7fbf7 --- /dev/null +++ b/internal/services/apimanagement/parse/gateway_certificate_authority_test.go @@ -0,0 +1,144 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "testing" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +var _ resourceids.Id = GatewayCertificateAuthorityId{} + +func TestGatewayCertificateAuthorityIDFormatter(t *testing.T) { + actual := NewGatewayCertificateAuthorityID("12345678-1234-9876-4563-123456789012", "resGroup1", "service1", "gateway1", "cert1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/gateways/gateway1/certificateAuthorities/cert1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestGatewayCertificateAuthorityID(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *GatewayCertificateAuthorityId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing ServiceName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/", + Error: true, + }, + + { + // missing value for ServiceName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/", + Error: true, + }, + + { + // missing GatewayName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/", + Error: true, + }, + + { + // missing value for GatewayName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/gateways/", + Error: true, + }, + + { + // missing CertificateAuthorityName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/gateways/gateway1/", + Error: true, + }, + + { + // missing value for CertificateAuthorityName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/gateways/gateway1/certificateAuthorities/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/gateways/gateway1/certificateAuthorities/cert1", + Expected: &GatewayCertificateAuthorityId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ServiceName: "service1", + GatewayName: "gateway1", + CertificateAuthorityName: "cert1", + }, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.APIMANAGEMENT/SERVICE/SERVICE1/GATEWAYS/GATEWAY1/CERTIFICATEAUTHORITIES/CERT1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := GatewayCertificateAuthorityID(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.ServiceName != v.Expected.ServiceName { + t.Fatalf("Expected %q but got %q for ServiceName", v.Expected.ServiceName, actual.ServiceName) + } + if actual.GatewayName != v.Expected.GatewayName { + t.Fatalf("Expected %q but got %q for GatewayName", v.Expected.GatewayName, actual.GatewayName) + } + if actual.CertificateAuthorityName != v.Expected.CertificateAuthorityName { + t.Fatalf("Expected %q but got %q for CertificateAuthorityName", v.Expected.CertificateAuthorityName, actual.CertificateAuthorityName) + } + } +} diff --git a/internal/services/apimanagement/parse/product_tag.go b/internal/services/apimanagement/parse/product_tag.go new file mode 100644 index 000000000000..799a0a3cd5ea --- /dev/null +++ b/internal/services/apimanagement/parse/product_tag.go @@ -0,0 +1,81 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + "strings" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +type ProductTagId struct { + SubscriptionId string + ResourceGroup string + ServiceName string + ProductName string + TagName string +} + +func NewProductTagID(subscriptionId, resourceGroup, serviceName, productName, tagName string) ProductTagId { + return ProductTagId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + ServiceName: serviceName, + ProductName: productName, + TagName: tagName, + } +} + +func (id ProductTagId) String() string { + segments := []string{ + fmt.Sprintf("Tag Name %q", id.TagName), + fmt.Sprintf("Product Name %q", id.ProductName), + fmt.Sprintf("Service Name %q", id.ServiceName), + fmt.Sprintf("Resource Group %q", id.ResourceGroup), + } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "Product Tag", segmentsStr) +} + +func (id ProductTagId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.ApiManagement/service/%s/products/%s/tags/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.ServiceName, id.ProductName, id.TagName) +} + +// ProductTagID parses a ProductTag ID into an ProductTagId struct +func ProductTagID(input string) (*ProductTagId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := ProductTagId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + if resourceId.ServiceName, err = id.PopSegment("service"); err != nil { + return nil, err + } + if resourceId.ProductName, err = id.PopSegment("products"); err != nil { + return nil, err + } + if resourceId.TagName, err = id.PopSegment("tags"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} diff --git a/internal/services/apimanagement/parse/product_tag_test.go b/internal/services/apimanagement/parse/product_tag_test.go new file mode 100644 index 000000000000..90a6dc472ca8 --- /dev/null +++ b/internal/services/apimanagement/parse/product_tag_test.go @@ -0,0 +1,144 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "testing" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +var _ resourceids.Id = ProductTagId{} + +func TestProductTagIDFormatter(t *testing.T) { + actual := NewProductTagID("12345678-1234-9876-4563-123456789012", "resGroup1", "service1", "product1", "tagId1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/products/product1/tags/tagId1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestProductTagID(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *ProductTagId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing ServiceName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/", + Error: true, + }, + + { + // missing value for ServiceName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/", + Error: true, + }, + + { + // missing ProductName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/", + Error: true, + }, + + { + // missing value for ProductName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/products/", + Error: true, + }, + + { + // missing TagName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/products/product1/", + Error: true, + }, + + { + // missing value for TagName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/products/product1/tags/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/products/product1/tags/tagId1", + Expected: &ProductTagId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ServiceName: "service1", + ProductName: "product1", + TagName: "tagId1", + }, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.APIMANAGEMENT/SERVICE/SERVICE1/PRODUCTS/PRODUCT1/TAGS/TAGID1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := ProductTagID(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.ServiceName != v.Expected.ServiceName { + t.Fatalf("Expected %q but got %q for ServiceName", v.Expected.ServiceName, actual.ServiceName) + } + if actual.ProductName != v.Expected.ProductName { + t.Fatalf("Expected %q but got %q for ProductName", v.Expected.ProductName, actual.ProductName) + } + if actual.TagName != v.Expected.TagName { + t.Fatalf("Expected %q but got %q for TagName", v.Expected.TagName, actual.TagName) + } + } +} diff --git a/internal/services/apimanagement/registration.go b/internal/services/apimanagement/registration.go index c743a0563791..272ef9c4e33b 100644 --- a/internal/services/apimanagement/registration.go +++ b/internal/services/apimanagement/registration.go @@ -41,45 +41,47 @@ func (r Registration) SupportedDataSources() map[string]*pluginsdk.Resource { // SupportedResources returns the supported Resources supported by this Service func (r Registration) SupportedResources() map[string]*pluginsdk.Resource { return map[string]*pluginsdk.Resource{ - "azurerm_api_management": resourceApiManagementService(), - "azurerm_api_management_api": resourceApiManagementApi(), - "azurerm_api_management_api_diagnostic": resourceApiManagementApiDiagnostic(), - "azurerm_api_management_api_operation": resourceApiManagementApiOperation(), - "azurerm_api_management_api_operation_tag": resourceApiManagementApiOperationTag(), - "azurerm_api_management_api_operation_policy": resourceApiManagementApiOperationPolicy(), - "azurerm_api_management_api_policy": resourceApiManagementApiPolicy(), - "azurerm_api_management_api_release": resourceApiManagementApiRelease(), - "azurerm_api_management_api_schema": resourceApiManagementApiSchema(), - "azurerm_api_management_api_tag": resourceApiManagementApiTag(), - "azurerm_api_management_api_version_set": resourceApiManagementApiVersionSet(), - "azurerm_api_management_authorization_server": resourceApiManagementAuthorizationServer(), - "azurerm_api_management_backend": resourceApiManagementBackend(), - "azurerm_api_management_certificate": resourceApiManagementCertificate(), - "azurerm_api_management_custom_domain": resourceApiManagementCustomDomain(), - "azurerm_api_management_diagnostic": resourceApiManagementDiagnostic(), - "azurerm_api_management_email_template": resourceApiManagementEmailTemplate(), - "azurerm_api_management_gateway": resourceApiManagementGateway(), - "azurerm_api_management_gateway_api": resourceApiManagementGatewayApi(), - "azurerm_api_management_group": resourceApiManagementGroup(), - "azurerm_api_management_group_user": resourceApiManagementGroupUser(), - "azurerm_api_management_identity_provider_aad": resourceApiManagementIdentityProviderAAD(), - "azurerm_api_management_identity_provider_aadb2c": resourceArmApiManagementIdentityProviderAADB2C(), - "azurerm_api_management_identity_provider_facebook": resourceApiManagementIdentityProviderFacebook(), - "azurerm_api_management_identity_provider_google": resourceApiManagementIdentityProviderGoogle(), - "azurerm_api_management_identity_provider_microsoft": resourceApiManagementIdentityProviderMicrosoft(), - "azurerm_api_management_identity_provider_twitter": resourceApiManagementIdentityProviderTwitter(), - "azurerm_api_management_logger": resourceApiManagementLogger(), - "azurerm_api_management_named_value": resourceApiManagementNamedValue(), - "azurerm_api_management_openid_connect_provider": resourceApiManagementOpenIDConnectProvider(), - "azurerm_api_management_policy": resourceApiManagementPolicy(), - "azurerm_api_management_product": resourceApiManagementProduct(), - "azurerm_api_management_product_api": resourceApiManagementProductApi(), - "azurerm_api_management_product_group": resourceApiManagementProductGroup(), - "azurerm_api_management_product_policy": resourceApiManagementProductPolicy(), - "azurerm_api_management_redis_cache": resourceApiManagementRedisCache(), - "azurerm_api_management_subscription": resourceApiManagementSubscription(), - "azurerm_api_management_tag": resourceApiManagementTag(), - "azurerm_api_management_user": resourceApiManagementUser(), + "azurerm_api_management": resourceApiManagementService(), + "azurerm_api_management_api": resourceApiManagementApi(), + "azurerm_api_management_api_diagnostic": resourceApiManagementApiDiagnostic(), + "azurerm_api_management_api_operation": resourceApiManagementApiOperation(), + "azurerm_api_management_api_operation_tag": resourceApiManagementApiOperationTag(), + "azurerm_api_management_api_operation_policy": resourceApiManagementApiOperationPolicy(), + "azurerm_api_management_api_policy": resourceApiManagementApiPolicy(), + "azurerm_api_management_api_release": resourceApiManagementApiRelease(), + "azurerm_api_management_api_schema": resourceApiManagementApiSchema(), + "azurerm_api_management_api_tag": resourceApiManagementApiTag(), + "azurerm_api_management_api_version_set": resourceApiManagementApiVersionSet(), + "azurerm_api_management_authorization_server": resourceApiManagementAuthorizationServer(), + "azurerm_api_management_backend": resourceApiManagementBackend(), + "azurerm_api_management_certificate": resourceApiManagementCertificate(), + "azurerm_api_management_custom_domain": resourceApiManagementCustomDomain(), + "azurerm_api_management_diagnostic": resourceApiManagementDiagnostic(), + "azurerm_api_management_email_template": resourceApiManagementEmailTemplate(), + "azurerm_api_management_gateway": resourceApiManagementGateway(), + "azurerm_api_management_gateway_api": resourceApiManagementGatewayApi(), + "azurerm_api_management_gateway_certificate_authority": resourceApiManagementGatewayCertificateAuthority(), + "azurerm_api_management_group": resourceApiManagementGroup(), + "azurerm_api_management_group_user": resourceApiManagementGroupUser(), + "azurerm_api_management_identity_provider_aad": resourceApiManagementIdentityProviderAAD(), + "azurerm_api_management_identity_provider_aadb2c": resourceArmApiManagementIdentityProviderAADB2C(), + "azurerm_api_management_identity_provider_facebook": resourceApiManagementIdentityProviderFacebook(), + "azurerm_api_management_identity_provider_google": resourceApiManagementIdentityProviderGoogle(), + "azurerm_api_management_identity_provider_microsoft": resourceApiManagementIdentityProviderMicrosoft(), + "azurerm_api_management_identity_provider_twitter": resourceApiManagementIdentityProviderTwitter(), + "azurerm_api_management_logger": resourceApiManagementLogger(), + "azurerm_api_management_named_value": resourceApiManagementNamedValue(), + "azurerm_api_management_openid_connect_provider": resourceApiManagementOpenIDConnectProvider(), + "azurerm_api_management_policy": resourceApiManagementPolicy(), + "azurerm_api_management_product": resourceApiManagementProduct(), + "azurerm_api_management_product_tag": resourceApiManagementProductTag(), + "azurerm_api_management_product_api": resourceApiManagementProductApi(), + "azurerm_api_management_product_group": resourceApiManagementProductGroup(), + "azurerm_api_management_product_policy": resourceApiManagementProductPolicy(), + "azurerm_api_management_redis_cache": resourceApiManagementRedisCache(), + "azurerm_api_management_subscription": resourceApiManagementSubscription(), + "azurerm_api_management_tag": resourceApiManagementTag(), + "azurerm_api_management_user": resourceApiManagementUser(), } } diff --git a/internal/services/apimanagement/resourceids.go b/internal/services/apimanagement/resourceids.go index 23a8c7fe2898..a9cfc97f3952 100644 --- a/internal/services/apimanagement/resourceids.go +++ b/internal/services/apimanagement/resourceids.go @@ -30,6 +30,7 @@ package apimanagement //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ProductApi -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/products/product1/apis/api1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ProductGroup -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/products/product1/groups/group1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ProductPolicy -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/products/product1/policies/policy1 +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ProductTag -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/products/product1/tags/tagId1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Property -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/namedValues/namedvalue1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Subscription -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/subscriptions/subscription1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=User -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/users/user1 @@ -37,3 +38,4 @@ package apimanagement //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ApiRelease -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/apis/api1/releases/release1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Tag -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/tags/tag1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ApiTag -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/apis/api1/tags/tag1 +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=GatewayCertificateAuthority -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/gateways/gateway1/certificateAuthorities/cert1 diff --git a/internal/services/apimanagement/validate/api_management_sku.go b/internal/services/apimanagement/validate/api_management_sku.go index e73eab348767..0616c65f6a82 100644 --- a/internal/services/apimanagement/validate/api_management_sku.go +++ b/internal/services/apimanagement/validate/api_management_sku.go @@ -9,7 +9,7 @@ import ( func ApimSkuName() pluginsdk.SchemaValidateFunc { return validation.StringMatch( - regexp.MustCompile(`^Consumption_0$|^Basic_(1|2)$|^Developer_1$|^Premium_([1-9]|10)$|^Standard_[1-4]$`), + regexp.MustCompile(`^Consumption_0$|^Basic_(1|2)$|^Developer_1$|^Premium_([1-9][0-9]{0,1})$|^Standard_[1-4]$`), `This is not a valid Api Management sku name.`, ) } diff --git a/internal/services/apimanagement/validate/api_management_sku_test.go b/internal/services/apimanagement/validate/api_management_sku_test.go index fdac8f2a6786..8ae2e7a74d01 100644 --- a/internal/services/apimanagement/validate/api_management_sku_test.go +++ b/internal/services/apimanagement/validate/api_management_sku_test.go @@ -39,10 +39,20 @@ func TestApimSkuName(t *testing.T) { valid: false, }, { - name: "Premium_11", - input: "Premium_11", + name: "Premium_101", + input: "Premium_101", valid: false, }, + { + name: "Premium_10", + input: "Premium_10", + valid: true, + }, + { + name: "Premium_12", + input: "Premium_12", + valid: true, + }, { name: "Premium_7", input: "Premium_7", diff --git a/internal/services/apimanagement/validate/gateway_certificate_authority_id.go b/internal/services/apimanagement/validate/gateway_certificate_authority_id.go new file mode 100644 index 000000000000..f12688afa3fe --- /dev/null +++ b/internal/services/apimanagement/validate/gateway_certificate_authority_id.go @@ -0,0 +1,23 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + + "github.com/hashicorp/terraform-provider-azurerm/internal/services/apimanagement/parse" +) + +func GatewayCertificateAuthorityID(input interface{}, key string) (warnings []string, errors []error) { + v, ok := input.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected %q to be a string", key)) + return + } + + if _, err := parse.GatewayCertificateAuthorityID(v); err != nil { + errors = append(errors, err) + } + + return +} diff --git a/internal/services/apimanagement/validate/gateway_certificate_authority_id_test.go b/internal/services/apimanagement/validate/gateway_certificate_authority_id_test.go new file mode 100644 index 000000000000..a467e6f53c6f --- /dev/null +++ b/internal/services/apimanagement/validate/gateway_certificate_authority_id_test.go @@ -0,0 +1,100 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import "testing" + +func TestGatewayCertificateAuthorityID(t *testing.T) { + cases := []struct { + Input string + Valid bool + }{ + + { + // empty + Input: "", + Valid: false, + }, + + { + // missing SubscriptionId + Input: "/", + Valid: false, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Valid: false, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Valid: false, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Valid: false, + }, + + { + // missing ServiceName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/", + Valid: false, + }, + + { + // missing value for ServiceName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/", + Valid: false, + }, + + { + // missing GatewayName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/", + Valid: false, + }, + + { + // missing value for GatewayName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/gateways/", + Valid: false, + }, + + { + // missing CertificateAuthorityName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/gateways/gateway1/", + Valid: false, + }, + + { + // missing value for CertificateAuthorityName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/gateways/gateway1/certificateAuthorities/", + Valid: false, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/gateways/gateway1/certificateAuthorities/cert1", + Valid: true, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.APIMANAGEMENT/SERVICE/SERVICE1/GATEWAYS/GATEWAY1/CERTIFICATEAUTHORITIES/CERT1", + Valid: false, + }, + } + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.Input) + _, errors := GatewayCertificateAuthorityID(tc.Input, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} diff --git a/internal/services/apimanagement/validate/product_tag_id.go b/internal/services/apimanagement/validate/product_tag_id.go new file mode 100644 index 000000000000..9827d25af5b5 --- /dev/null +++ b/internal/services/apimanagement/validate/product_tag_id.go @@ -0,0 +1,23 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + + "github.com/hashicorp/terraform-provider-azurerm/internal/services/apimanagement/parse" +) + +func ProductTagID(input interface{}, key string) (warnings []string, errors []error) { + v, ok := input.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected %q to be a string", key)) + return + } + + if _, err := parse.ProductTagID(v); err != nil { + errors = append(errors, err) + } + + return +} diff --git a/internal/services/apimanagement/validate/product_tag_id_test.go b/internal/services/apimanagement/validate/product_tag_id_test.go new file mode 100644 index 000000000000..75d10408ab8f --- /dev/null +++ b/internal/services/apimanagement/validate/product_tag_id_test.go @@ -0,0 +1,100 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import "testing" + +func TestProductTagID(t *testing.T) { + cases := []struct { + Input string + Valid bool + }{ + + { + // empty + Input: "", + Valid: false, + }, + + { + // missing SubscriptionId + Input: "/", + Valid: false, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Valid: false, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Valid: false, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Valid: false, + }, + + { + // missing ServiceName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/", + Valid: false, + }, + + { + // missing value for ServiceName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/", + Valid: false, + }, + + { + // missing ProductName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/", + Valid: false, + }, + + { + // missing value for ProductName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/products/", + Valid: false, + }, + + { + // missing TagName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/products/product1/", + Valid: false, + }, + + { + // missing value for TagName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/products/product1/tags/", + Valid: false, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/products/product1/tags/tagId1", + Valid: true, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.APIMANAGEMENT/SERVICE/SERVICE1/PRODUCTS/PRODUCT1/TAGS/TAGID1", + Valid: false, + }, + } + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.Input) + _, errors := ProductTagID(tc.Input, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} diff --git a/internal/services/appconfiguration/app_configuration_data_source.go b/internal/services/appconfiguration/app_configuration_data_source.go index 8b4e22355910..ad4feb0ac044 100644 --- a/internal/services/appconfiguration/app_configuration_data_source.go +++ b/internal/services/appconfiguration/app_configuration_data_source.go @@ -44,6 +44,11 @@ func dataSourceAppConfiguration() *pluginsdk.Resource { Computed: true, }, + "public_network_access": { + Type: pluginsdk.TypeString, + Computed: true, + }, + "primary_read_key": { Type: pluginsdk.TypeList, Computed: true, @@ -177,6 +182,7 @@ func dataSourceAppConfigurationRead(d *pluginsdk.ResourceData, meta interface{}) if props := model.Properties; props != nil { d.Set("endpoint", props.Endpoint) + d.Set("public_network_access", props.PublicNetworkAccess) } accessKeys := flattenAppConfigurationAccessKeys(resultPage.Items) diff --git a/internal/services/appconfiguration/app_configuration_data_source_test.go b/internal/services/appconfiguration/app_configuration_data_source_test.go index df74ffc04ae3..922a6da7900f 100644 --- a/internal/services/appconfiguration/app_configuration_data_source_test.go +++ b/internal/services/appconfiguration/app_configuration_data_source_test.go @@ -30,6 +30,7 @@ func TestAccAppConfigurationDataSource_basic(t *testing.T) { check.That(data.ResourceName).Key("primary_write_key.0.connection_string").Exists(), check.That(data.ResourceName).Key("primary_write_key.0.id").Exists(), check.That(data.ResourceName).Key("primary_write_key.0.secret").Exists(), + check.That(data.ResourceName).Key("public_network_access").Exists(), check.That(data.ResourceName).Key("secondary_read_key.0.connection_string").Exists(), check.That(data.ResourceName).Key("secondary_read_key.0.id").Exists(), check.That(data.ResourceName).Key("secondary_read_key.0.secret").Exists(), diff --git a/internal/services/appconfiguration/app_configuration_resource.go b/internal/services/appconfiguration/app_configuration_resource.go index ce4b3054605d..9261f7333176 100644 --- a/internal/services/appconfiguration/app_configuration_resource.go +++ b/internal/services/appconfiguration/app_configuration_resource.go @@ -69,6 +69,13 @@ func resourceAppConfiguration() *pluginsdk.Resource { Computed: true, }, + "public_network_access": { + Type: pluginsdk.TypeString, + Optional: true, + Default: nil, + ValidateFunc: validation.StringInSlice(configurationstores.PossibleValuesForPublicNetworkAccess(), true), + }, + "primary_read_key": { Type: pluginsdk.TypeList, Computed: true, @@ -199,6 +206,20 @@ func resourceAppConfigurationCreate(d *pluginsdk.ResourceData, meta interface{}) Tags: tags.Expand(d.Get("tags").(map[string]interface{})), } + publicNetworkAccessValue, publicNetworkAccessNotEmpty := d.GetOk("public_network_access") + + if publicNetworkAccessNotEmpty { + + publicNetworkAccess, err := parsePublicNetworkAccess(publicNetworkAccessValue.(string)) + if err != nil { + return fmt.Errorf("unable to parse public_network_access: %+v", err) + } + properties := &configurationstores.ConfigurationStoreProperties{ + PublicNetworkAccess: publicNetworkAccess, + } + parameters.Properties = properties + } + identity, err := identity.ExpandSystemAndUserAssignedMap(d.Get("identity").([]interface{})) if err != nil { return fmt.Errorf("expanding `identity`: %+v", err) @@ -231,6 +252,18 @@ func resourceAppConfigurationUpdate(d *pluginsdk.ResourceData, meta interface{}) Tags: tags.Expand(d.Get("tags").(map[string]interface{})), } + publicNetworkAccessValue, publicNetworkAccessNotEmpty := d.GetOk("public_network_access") + if publicNetworkAccessNotEmpty { + publicNetworkAccess, err := parsePublicNetworkAccess(publicNetworkAccessValue.(string)) + if err != nil { + return fmt.Errorf("unable to parse public_network_access: %+v", err) + } + properties := &configurationstores.ConfigurationStorePropertiesUpdateParameters{ + PublicNetworkAccess: publicNetworkAccess, + } + parameters.Properties = properties + } + if d.HasChange("identity") { identity, err := identity.ExpandSystemAndUserAssignedMap(d.Get("identity").([]interface{})) if err != nil { @@ -280,6 +313,7 @@ func resourceAppConfigurationRead(d *pluginsdk.ResourceData, meta interface{}) e if props := model.Properties; props != nil { d.Set("endpoint", props.Endpoint) + d.Set("public_network_access", props.PublicNetworkAccess) } accessKeys := flattenAppConfigurationAccessKeys(resultPage.Items) @@ -388,3 +422,17 @@ func flattenAppConfigurationAccessKey(input configurationstores.ApiKey) []interf }, } } + +func parsePublicNetworkAccess(input string) (*configurationstores.PublicNetworkAccess, error) { + vals := map[string]configurationstores.PublicNetworkAccess{ + "disabled": configurationstores.PublicNetworkAccessDisabled, + "enabled": configurationstores.PublicNetworkAccessEnabled, + } + if v, ok := vals[strings.ToLower(input)]; ok { + return &v, nil + } + + // otherwise presume it's an undefined value and best-effort it + out := configurationstores.PublicNetworkAccess(input) + return &out, nil +} diff --git a/internal/services/appconfiguration/app_configuration_resource_test.go b/internal/services/appconfiguration/app_configuration_resource_test.go index 053e7f7a8098..d457bfcd697a 100644 --- a/internal/services/appconfiguration/app_configuration_resource_test.go +++ b/internal/services/appconfiguration/app_configuration_resource_test.go @@ -203,10 +203,11 @@ resource "azurerm_resource_group" "test" { } resource "azurerm_app_configuration" "test" { - name = "testaccappconf%d" - resource_group_name = azurerm_resource_group.test.name - location = azurerm_resource_group.test.location - sku = "standard" + name = "testaccappconf%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + public_network_access = "Disabled" + sku = "standard" } `, data.RandomInteger, data.Locations.Primary, data.RandomInteger) } @@ -237,10 +238,11 @@ resource "azurerm_resource_group" "test" { } resource "azurerm_app_configuration" "test" { - name = "testaccappconf%d" - resource_group_name = azurerm_resource_group.test.name - location = azurerm_resource_group.test.location - sku = "standard" + name = "testaccappconf%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + public_network_access = "Disabled" + sku = "standard" tags = { environment = "development" @@ -261,10 +263,11 @@ resource "azurerm_resource_group" "test" { } resource "azurerm_app_configuration" "test" { - name = "testaccappconf%d" - resource_group_name = azurerm_resource_group.test.name - location = azurerm_resource_group.test.location - sku = "standard" + name = "testaccappconf%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + public_network_access = "Disabled" + sku = "standard" identity { type = "SystemAssigned" @@ -295,10 +298,11 @@ resource "azurerm_user_assigned_identity" "test" { } resource "azurerm_app_configuration" "test" { - name = "testaccappconf%d" - resource_group_name = azurerm_resource_group.test.name - location = azurerm_resource_group.test.location - sku = "standard" + name = "testaccappconf%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + public_network_access = "Disabled" + sku = "standard" identity { type = "UserAssigned" @@ -326,10 +330,11 @@ resource "azurerm_resource_group" "test" { } resource "azurerm_app_configuration" "test" { - name = "testaccappconf%d" - resource_group_name = azurerm_resource_group.test.name - location = azurerm_resource_group.test.location - sku = "standard" + name = "testaccappconf%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + public_network_access = "Disabled" + sku = "standard" tags = { Environment = "Production" diff --git a/internal/services/applicationinsights/application_insights_workbook_resource.go b/internal/services/applicationinsights/application_insights_workbook_resource.go new file mode 100644 index 000000000000..51fbb666fc4b --- /dev/null +++ b/internal/services/applicationinsights/application_insights_workbook_resource.go @@ -0,0 +1,331 @@ +package applicationinsights + +import ( + "context" + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/identity" + "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + workbooks "github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2022-04-01/workbooksapis" + "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/applicationinsights/validate" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type ApplicationInsightsWorkbookModel struct { + Name string `tfschema:"name"` + ResourceGroupName string `tfschema:"resource_group_name"` + Category string `tfschema:"category"` + Description string `tfschema:"description"` + DisplayName string `tfschema:"display_name"` + Location string `tfschema:"location"` + DataJson string `tfschema:"data_json"` + SourceId string `tfschema:"source_id"` + StorageContainerId string `tfschema:"storage_container_id"` + Tags map[string]string `tfschema:"tags"` +} + +type ApplicationInsightsWorkbookResource struct{} + +var _ sdk.ResourceWithUpdate = ApplicationInsightsWorkbookResource{} + +func (r ApplicationInsightsWorkbookResource) ResourceType() string { + return "azurerm_application_insights_workbook" +} + +func (r ApplicationInsightsWorkbookResource) ModelObject() interface{} { + return &ApplicationInsightsWorkbookModel{} +} + +func (r ApplicationInsightsWorkbookResource) IDValidationFunc() pluginsdk.SchemaValidateFunc { + return workbooks.ValidateWorkbookID +} + +func (r ApplicationInsightsWorkbookResource) Arguments() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.All( + validation.IsUUID, + validate.StringDoesNotContainUpperCaseLetter, + ), + }, + + "resource_group_name": commonschema.ResourceGroupName(), + + "location": commonschema.Location(), + + "display_name": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "data_json": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringIsJSON, + DiffSuppressFunc: pluginsdk.SuppressJsonDiff, + }, + + "source_id": { + Type: pluginsdk.TypeString, + Optional: true, + Default: "azure monitor", + ValidateFunc: validate.StringDoesNotContainUpperCaseLetter, + }, + + "category": { + Type: pluginsdk.TypeString, + Optional: true, + Default: "workbook", + ValidateFunc: validation.StringIsNotEmpty, + }, + + "description": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "identity": commonschema.SystemAssignedUserAssignedIdentityOptionalForceNew(), + + "storage_container_id": { + Type: pluginsdk.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringIsNotEmpty, + RequiredWith: []string{ + "identity", + }, + }, + + "tags": { + Type: pluginsdk.TypeMap, + Optional: true, + ValidateFunc: validate.WorkbookTags, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + }, + }, + } +} + +func (r ApplicationInsightsWorkbookResource) Attributes() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{} +} + +func (r ApplicationInsightsWorkbookResource) Create() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + var model ApplicationInsightsWorkbookModel + if err := metadata.Decode(&model); err != nil { + return fmt.Errorf("decoding: %+v", err) + } + + client := metadata.Client.AppInsights.WorkbookClient + subscriptionId := metadata.Client.Account.SubscriptionId + id := workbooks.NewWorkbookID(subscriptionId, model.ResourceGroupName, model.Name) + existing, err := client.WorkbooksGet(ctx, id, workbooks.WorkbooksGetOperationOptions{CanFetchContent: utils.Bool(true)}) + if err != nil && !response.WasNotFound(existing.HttpResponse) { + return fmt.Errorf("checking for existing %s: %+v", id, err) + } + + if !response.WasNotFound(existing.HttpResponse) { + return metadata.ResourceRequiresImport(r.ResourceType(), id) + } + + identityValue, err := identity.ExpandLegacySystemAndUserAssignedMap(metadata.ResourceData.Get("identity").([]interface{})) + if err != nil { + return fmt.Errorf("expanding `identity`: %+v", err) + } + + kindValue := workbooks.WorkbookSharedTypeKindShared + properties := &workbooks.Workbook{ + Identity: identityValue, + Kind: &kindValue, + Location: utils.String(location.Normalize(model.Location)), + Properties: &workbooks.WorkbookProperties{ + Category: model.Category, + DisplayName: model.DisplayName, + SerializedData: model.DataJson, + SourceId: &model.SourceId, + }, + + Tags: &model.Tags, + } + + if model.Description != "" { + properties.Properties.Description = &model.Description + } + + if model.StorageContainerId != "" { + properties.Properties.StorageUri = &model.StorageContainerId + } + + if _, err := client.WorkbooksCreateOrUpdate(ctx, id, *properties, workbooks.WorkbooksCreateOrUpdateOperationOptions{SourceId: &model.SourceId}); err != nil { + return fmt.Errorf("creating %s: %+v", id, err) + } + + metadata.SetID(id) + return nil + }, + } +} + +func (r ApplicationInsightsWorkbookResource) Update() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.AppInsights.WorkbookClient + + id, err := workbooks.ParseWorkbookID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + var model ApplicationInsightsWorkbookModel + if err := metadata.Decode(&model); err != nil { + return fmt.Errorf("decoding: %+v", err) + } + + resp, err := client.WorkbooksGet(ctx, *id, workbooks.WorkbooksGetOperationOptions{CanFetchContent: utils.Bool(true)}) + if err != nil { + return fmt.Errorf("retrieving %s: %+v", *id, err) + } + + properties := resp.Model + if properties == nil { + return fmt.Errorf("retrieving %s: properties was nil", id) + } + + if metadata.ResourceData.HasChange("category") { + properties.Properties.Category = model.Category + } + + if metadata.ResourceData.HasChange("description") { + properties.Properties.Description = &model.Description + } + + if metadata.ResourceData.HasChange("display_name") { + properties.Properties.DisplayName = model.DisplayName + } + + if metadata.ResourceData.HasChange("data_json") { + properties.Properties.SerializedData = model.DataJson + } + + if metadata.ResourceData.HasChange("tags") { + properties.Tags = &model.Tags + } + + if _, err := client.WorkbooksCreateOrUpdate(ctx, *id, *properties, workbooks.WorkbooksCreateOrUpdateOperationOptions{SourceId: &model.SourceId}); err != nil { + return fmt.Errorf("updating %s: %+v", *id, err) + } + + return nil + }, + } +} + +func (r ApplicationInsightsWorkbookResource) Read() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 5 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.AppInsights.WorkbookClient + + id, err := workbooks.ParseWorkbookID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + resp, err := client.WorkbooksGet(ctx, *id, workbooks.WorkbooksGetOperationOptions{CanFetchContent: utils.Bool(true)}) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return metadata.MarkAsGone(id) + } + + return fmt.Errorf("retrieving %s: %+v", *id, err) + } + + model := resp.Model + if model == nil { + return fmt.Errorf("retrieving %s: model was nil", id) + } + + state := ApplicationInsightsWorkbookModel{ + Name: id.ResourceName, + ResourceGroupName: id.ResourceGroupName, + Location: location.NormalizeNilable(model.Location), + } + + identityValue, err := identity.FlattenLegacySystemAndUserAssignedMap(model.Identity) + if err != nil { + return fmt.Errorf("flattening `identity`: %+v", err) + } + + if err := metadata.ResourceData.Set("identity", identityValue); err != nil { + return fmt.Errorf("setting `identity`: %+v", err) + } + + if properties := model.Properties; properties != nil { + state.Category = properties.Category + + if properties.Description != nil { + state.Description = *properties.Description + } + + state.DisplayName = properties.DisplayName + + state.DataJson = properties.SerializedData + + if properties.SourceId != nil { + state.SourceId = *properties.SourceId + } + + if properties.StorageUri != nil { + state.StorageContainerId = *properties.StorageUri + } + } + + if model.Tags != nil { + // The backend returns a tags with key `hidden-title` by default. Since it has the same value with `display_name` and will cause inconsistency with user's configuration, remove it as a workaround. + if _, ok := (*model.Tags)["hidden-title"]; ok { + delete(*model.Tags, "hidden-title") + } + + state.Tags = *model.Tags + } + + return metadata.Encode(&state) + }, + } +} + +func (r ApplicationInsightsWorkbookResource) Delete() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.AppInsights.WorkbookClient + + id, err := workbooks.ParseWorkbookID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + if _, err := client.WorkbooksDelete(ctx, *id); err != nil { + return fmt.Errorf("deleting %s: %+v", id, err) + } + + return nil + }, + } +} diff --git a/internal/services/applicationinsights/application_insights_workbook_resource_test.go b/internal/services/applicationinsights/application_insights_workbook_resource_test.go new file mode 100644 index 000000000000..dab1fdc98ea3 --- /dev/null +++ b/internal/services/applicationinsights/application_insights_workbook_resource_test.go @@ -0,0 +1,352 @@ +package applicationinsights_test + +import ( + "context" + "fmt" + "regexp" + "testing" + + "github.com/hashicorp/go-azure-helpers/lang/response" + workbooks "github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2022-04-01/workbooksapis" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type ApplicationInsightsWorkbookResource struct{} + +func TestAccApplicationInsightsWorkbook_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_application_insights_workbook", "test") + r := ApplicationInsightsWorkbookResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccApplicationInsightsWorkbook_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_application_insights_workbook", "test") + r := ApplicationInsightsWorkbookResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func TestAccApplicationInsightsWorkbook_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_application_insights_workbook", "test") + r := ApplicationInsightsWorkbookResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccApplicationInsightsWorkbook_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_application_insights_workbook", "test") + r := ApplicationInsightsWorkbookResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.update(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccApplicationInsightsWorkbook_hiddenTitleInTags(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_application_insights_workbook", "test") + r := ApplicationInsightsWorkbookResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.hiddenTitleInTags(data), + ExpectError: regexp.MustCompile("a tag with the key `hidden-title` should not be used to set the display name. Please Use `display_name` instead"), + }, + }) +} + +func (r ApplicationInsightsWorkbookResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + id, err := workbooks.ParseWorkbookID(state.ID) + if err != nil { + return nil, err + } + + client := clients.AppInsights.WorkbookClient + resp, err := client.WorkbooksGet(ctx, *id, workbooks.WorkbooksGetOperationOptions{CanFetchContent: utils.Bool(true)}) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return utils.Bool(false), nil + } + return nil, fmt.Errorf("retrieving %s: %+v", id, err) + } + return utils.Bool(resp.Model != nil), nil +} + +func (r ApplicationInsightsWorkbookResource) template(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctest-rg-%d" + location = "%s" +} +`, data.RandomInteger, data.Locations.Primary) +} + +func (r ApplicationInsightsWorkbookResource) basic(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` + %s + +resource "azurerm_application_insights_workbook" "test" { + name = "be1ad266-d329-4454-b693-8287e4d3b35d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + display_name = "acctest-amw-%d" + data_json = jsonencode({ + "version" = "Notebook/1.0", + "items" = [ + { + "type" = 1, + "content" = { + "json" = "Test2022" + }, + "name" = "text - 0" + } + ], + "isLocked" = false, + "fallbackResourceIds" = [ + "Azure Monitor" + ] + }) +} +`, template, data.RandomInteger) +} + +func (r ApplicationInsightsWorkbookResource) hiddenTitleInTags(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_application_insights_workbook" "test" { + name = "be1ad266-d329-4454-b693-8287e4d3b35d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + display_name = "acctest-amw-%d" + data_json = jsonencode({ + "version" = "Notebook/1.0", + "items" = [ + { + "type" = 1, + "content" = { + "json" = "Test2022" + }, + "name" = "text - 0" + } + ], + "isLocked" = false, + "fallbackResourceIds" = [ + "Azure Monitor" + ] + }) + tags = { + hidden-title = "Test Display Name" + } +} +`, template, data.RandomInteger) +} + +func (r ApplicationInsightsWorkbookResource) requiresImport(data acceptance.TestData) string { + config := r.basic(data) + return fmt.Sprintf(` + %s + +resource "azurerm_application_insights_workbook" "import" { + name = azurerm_application_insights_workbook.test.name + resource_group_name = azurerm_application_insights_workbook.test.resource_group_name + location = azurerm_application_insights_workbook.test.location + category = azurerm_application_insights_workbook.test.category + display_name = azurerm_application_insights_workbook.test.display_name + source_id = azurerm_application_insights_workbook.test.source_id + data_json = azurerm_application_insights_workbook.test.data_json +} +`, config) +} + +func (r ApplicationInsightsWorkbookResource) complete(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` + %s + +resource "azurerm_user_assigned_identity" "test" { + name = "acctestUAI-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_storage_account" "test" { + name = "acctestsads%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + account_tier = "Standard" + account_replication_type = "LRS" +} + +resource "azurerm_storage_container" "test" { + name = "test" + storage_account_name = azurerm_storage_account.test.name + container_access_type = "private" +} + +resource "azurerm_role_assignment" "test" { + scope = azurerm_storage_account.test.id + role_definition_name = "Storage Blob Data Owner" + principal_id = azurerm_user_assigned_identity.test.principal_id +} + +resource "azurerm_application_insights_workbook" "test" { + name = "0f498fab-2989-4395-b084-fc092d83a6b1" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + display_name = "acctest-amw-1" + source_id = lower(azurerm_resource_group.test.id) + category = "workbook1" + description = "description1" + storage_container_id = azurerm_storage_container.test.resource_manager_id + + identity { + type = "UserAssigned" + identity_ids = [ + azurerm_user_assigned_identity.test.id + ] + } + + data_json = jsonencode({ + "version" = "Notebook/1.0", + "items" = [ + { + "type" = 1, + "content" = { + "json" = "Test2021" + }, + "name" = "text - 0" + } + ], + "isLocked" = false, + "fallbackResourceIds" = [ + "Azure Monitor" + ] + }) + tags = { + env = "test" + } + + depends_on = [ + azurerm_role_assignment.test, + ] +} +`, template, data.RandomInteger, data.RandomString) +} + +func (r ApplicationInsightsWorkbookResource) update(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` + %s + +resource "azurerm_user_assigned_identity" "test" { + name = "acctestUAI-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_storage_account" "test" { + name = "acctestsads%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + account_tier = "Standard" + account_replication_type = "LRS" +} + +resource "azurerm_storage_container" "test" { + name = "test" + storage_account_name = azurerm_storage_account.test.name + container_access_type = "private" +} + +resource "azurerm_role_assignment" "test" { + scope = azurerm_storage_account.test.id + role_definition_name = "Storage Blob Data Owner" + principal_id = azurerm_user_assigned_identity.test.principal_id +} + +resource "azurerm_application_insights_workbook" "test" { + name = "0f498fab-2989-4395-b084-fc092d83a6b1" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + display_name = "acctest-amw-2" + source_id = "azure monitor" + category = "workbook2" + description = "description2" + storage_container_id = azurerm_storage_container.test.resource_manager_id + + identity { + type = "UserAssigned" + identity_ids = [ + azurerm_user_assigned_identity.test.id + ] + } + + data_json = jsonencode({ + "version" = "Notebook/1.0", + "items" = [ + { + "type" = 1, + "content" = { + "json" = "Test2022" + }, + "name" = "text - 0" + } + ], + "isLocked" = false, + "fallbackResourceIds" = [ + "Azure Monitor" + ] + }) + tags = { + env = "test2" + } + + depends_on = [ + azurerm_role_assignment.test, + ] +} +`, template, data.RandomInteger, data.RandomString) +} diff --git a/internal/services/applicationinsights/application_insights_workbook_template_resource.go b/internal/services/applicationinsights/application_insights_workbook_template_resource.go index d984bd50a1cc..881d0254e2cb 100644 --- a/internal/services/applicationinsights/application_insights_workbook_template_resource.go +++ b/internal/services/applicationinsights/application_insights_workbook_template_resource.go @@ -9,7 +9,7 @@ import ( "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" - "github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2020-11-20/applicationinsights" + workbooktemplates "github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2020-11-20/workbooktemplatesapis" "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" @@ -49,7 +49,7 @@ func (r ApplicationInsightsWorkbookTemplateResource) ModelObject() interface{} { } func (r ApplicationInsightsWorkbookTemplateResource) IDValidationFunc() pluginsdk.SchemaValidateFunc { - return applicationinsights.ValidateWorkbookTemplateID + return workbooktemplates.ValidateWorkbookTemplateID } func (r ApplicationInsightsWorkbookTemplateResource) Arguments() map[string]*pluginsdk.Schema { @@ -150,7 +150,7 @@ func (r ApplicationInsightsWorkbookTemplateResource) Create() sdk.ResourceFunc { client := metadata.Client.AppInsights.WorkbookTemplateClient subscriptionId := metadata.Client.Account.SubscriptionId - id := applicationinsights.NewWorkbookTemplateID(subscriptionId, model.ResourceGroupName, model.Name) + id := workbooktemplates.NewWorkbookTemplateID(subscriptionId, model.ResourceGroupName, model.Name) existing, err := client.WorkbookTemplatesGet(ctx, id) if err != nil && !response.WasNotFound(existing.HttpResponse) { return fmt.Errorf("checking for existing %s: %+v", id, err) @@ -166,9 +166,9 @@ func (r ApplicationInsightsWorkbookTemplateResource) Create() sdk.ResourceFunc { return err } - properties := &applicationinsights.WorkbookTemplate{ + properties := &workbooktemplates.WorkbookTemplate{ Location: location.Normalize(model.Location), - Properties: &applicationinsights.WorkbookTemplateProperties{ + Properties: &workbooktemplates.WorkbookTemplateProperties{ Priority: &model.Priority, TemplateData: templateDataValue, }, @@ -181,7 +181,7 @@ func (r ApplicationInsightsWorkbookTemplateResource) Create() sdk.ResourceFunc { } if model.Localized != "" { - var localizedValue map[string][]applicationinsights.WorkbookTemplateLocalizedGallery + var localizedValue map[string][]workbooktemplates.WorkbookTemplateLocalizedGallery if err := json.Unmarshal([]byte(model.Localized), &localizedValue); err != nil { return err } @@ -214,7 +214,7 @@ func (r ApplicationInsightsWorkbookTemplateResource) Update() sdk.ResourceFunc { Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { client := metadata.Client.AppInsights.WorkbookTemplateClient - id, err := applicationinsights.ParseWorkbookTemplateID(metadata.ResourceData.Id()) + id, err := workbooktemplates.ParseWorkbookTemplateID(metadata.ResourceData.Id()) if err != nil { return err } @@ -264,7 +264,7 @@ func (r ApplicationInsightsWorkbookTemplateResource) Update() sdk.ResourceFunc { } if metadata.ResourceData.HasChange("localized") { - var localizedValue map[string][]applicationinsights.WorkbookTemplateLocalizedGallery + var localizedValue map[string][]workbooktemplates.WorkbookTemplateLocalizedGallery if err := json.Unmarshal([]byte(model.Localized), &localizedValue); err != nil { return err } @@ -291,7 +291,7 @@ func (r ApplicationInsightsWorkbookTemplateResource) Read() sdk.ResourceFunc { Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { client := metadata.Client.AppInsights.WorkbookTemplateClient - id, err := applicationinsights.ParseWorkbookTemplateID(metadata.ResourceData.Id()) + id, err := workbooktemplates.ParseWorkbookTemplateID(metadata.ResourceData.Id()) if err != nil { return err } @@ -366,7 +366,7 @@ func (r ApplicationInsightsWorkbookTemplateResource) Delete() sdk.ResourceFunc { Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { client := metadata.Client.AppInsights.WorkbookTemplateClient - id, err := applicationinsights.ParseWorkbookTemplateID(metadata.ResourceData.Id()) + id, err := workbooktemplates.ParseWorkbookTemplateID(metadata.ResourceData.Id()) if err != nil { return err } @@ -380,10 +380,10 @@ func (r ApplicationInsightsWorkbookTemplateResource) Delete() sdk.ResourceFunc { } } -func expandWorkbookTemplateGalleryModel(inputList []WorkbookTemplateGalleryModel) (*[]applicationinsights.WorkbookTemplateGallery, error) { - var outputList []applicationinsights.WorkbookTemplateGallery +func expandWorkbookTemplateGalleryModel(inputList []WorkbookTemplateGalleryModel) (*[]workbooktemplates.WorkbookTemplateGallery, error) { + var outputList []workbooktemplates.WorkbookTemplateGallery for _, input := range inputList { - output := applicationinsights.WorkbookTemplateGallery{ + output := workbooktemplates.WorkbookTemplateGallery{ Category: utils.String(input.Category), Name: utils.String(input.Name), Order: utils.Int64(input.Order), @@ -397,7 +397,7 @@ func expandWorkbookTemplateGalleryModel(inputList []WorkbookTemplateGalleryModel return &outputList, nil } -func flattenWorkbookTemplateGalleryModel(inputList *[]applicationinsights.WorkbookTemplateGallery) ([]WorkbookTemplateGalleryModel, error) { +func flattenWorkbookTemplateGalleryModel(inputList *[]workbooktemplates.WorkbookTemplateGallery) ([]WorkbookTemplateGalleryModel, error) { var outputList []WorkbookTemplateGalleryModel if inputList == nil { return outputList, nil diff --git a/internal/services/applicationinsights/application_insights_workbook_template_resource_test.go b/internal/services/applicationinsights/application_insights_workbook_template_resource_test.go index 64fef725c218..610f9aec96c4 100644 --- a/internal/services/applicationinsights/application_insights_workbook_template_resource_test.go +++ b/internal/services/applicationinsights/application_insights_workbook_template_resource_test.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/hashicorp/go-azure-helpers/lang/response" - "github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2020-11-20/applicationinsights" + workbooktemplates "github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2020-11-20/workbooktemplatesapis" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" @@ -80,7 +80,7 @@ func TestAccApplicationInsightsWorkbookTemplate_update(t *testing.T) { } func (r ApplicationInsightsWorkbookTemplateResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := applicationinsights.ParseWorkbookTemplateID(state.ID) + id, err := workbooktemplates.ParseWorkbookTemplateID(state.ID) if err != nil { return nil, err } diff --git a/internal/services/applicationinsights/client/client.go b/internal/services/applicationinsights/client/client.go index 8f69466b6aaa..0746f0d7e629 100644 --- a/internal/services/applicationinsights/client/client.go +++ b/internal/services/applicationinsights/client/client.go @@ -2,7 +2,8 @@ package client import ( "github.com/Azure/azure-sdk-for-go/services/appinsights/mgmt/2020-02-02/insights" - workbookTemplate "github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2020-11-20/applicationinsights" + workbooktemplates "github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2020-11-20/workbooktemplatesapis" + workbooks "github.com/hashicorp/go-azure-sdk/resource-manager/applicationinsights/2022-04-01/workbooksapis" "github.com/hashicorp/terraform-provider-azurerm/internal/common" "github.com/hashicorp/terraform-provider-azurerm/internal/services/applicationinsights/azuresdkhacks" ) @@ -14,7 +15,8 @@ type Client struct { WebTestsClient *azuresdkhacks.WebTestsClient BillingClient *insights.ComponentCurrentBillingFeaturesClient SmartDetectionRuleClient *insights.ProactiveDetectionConfigurationsClient - WorkbookTemplateClient *workbookTemplate.ApplicationInsightsClient + WorkbookClient *workbooks.WorkbooksAPIsClient + WorkbookTemplateClient *workbooktemplates.WorkbookTemplatesAPIsClient } func NewClient(o *common.ClientOptions) *Client { @@ -37,7 +39,10 @@ func NewClient(o *common.ClientOptions) *Client { smartDetectionRuleClient := insights.NewProactiveDetectionConfigurationsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&smartDetectionRuleClient.Client, o.ResourceManagerAuthorizer) - workbookTemplateClient := workbookTemplate.NewApplicationInsightsClientWithBaseURI(o.ResourceManagerEndpoint) + workbookClient := workbooks.NewWorkbooksAPIsClientWithBaseURI(o.ResourceManagerEndpoint) + o.ConfigureClient(&workbookClient.Client, o.ResourceManagerAuthorizer) + + workbookTemplateClient := workbooktemplates.NewWorkbookTemplatesAPIsClientWithBaseURI(o.ResourceManagerEndpoint) o.ConfigureClient(&workbookTemplateClient.Client, o.ResourceManagerAuthorizer) return &Client{ @@ -47,6 +52,7 @@ func NewClient(o *common.ClientOptions) *Client { WebTestsClient: &webTestsWorkaroundClient, BillingClient: &billingClient, SmartDetectionRuleClient: &smartDetectionRuleClient, + WorkbookClient: &workbookClient, WorkbookTemplateClient: &workbookTemplateClient, } } diff --git a/internal/services/applicationinsights/registration.go b/internal/services/applicationinsights/registration.go index cc0f01206e8c..ff545e173a34 100644 --- a/internal/services/applicationinsights/registration.go +++ b/internal/services/applicationinsights/registration.go @@ -54,6 +54,7 @@ func (r Registration) DataSources() []sdk.DataSource { // Resources returns a list of Resources supported by this Service func (r Registration) Resources() []sdk.Resource { return []sdk.Resource{ + ApplicationInsightsWorkbookResource{}, ApplicationInsightsWorkbookTemplateResource{}, } } diff --git a/internal/services/applicationinsights/validate/workbook_name.go b/internal/services/applicationinsights/validate/workbook_name.go new file mode 100644 index 000000000000..68f1d61b4ffd --- /dev/null +++ b/internal/services/applicationinsights/validate/workbook_name.go @@ -0,0 +1,21 @@ +package validate + +import ( + "fmt" + "strings" +) + +func StringDoesNotContainUpperCaseLetter(input interface{}, k string) (warnings []string, errors []error) { + v, ok := input.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected type of %q to be string", k)) + return + } + + if strings.ToLower(v) != v { + errors = append(errors, fmt.Errorf("expected value of %s to not contain any uppercase letter", k)) + return + } + + return +} diff --git a/internal/services/applicationinsights/validate/workbook_tags.go b/internal/services/applicationinsights/validate/workbook_tags.go new file mode 100644 index 000000000000..3eccb45d3bc9 --- /dev/null +++ b/internal/services/applicationinsights/validate/workbook_tags.go @@ -0,0 +1,21 @@ +package validate + +import ( + "fmt" + + "github.com/hashicorp/terraform-provider-azurerm/internal/tags" +) + +func WorkbookTags(i interface{}, k string) (warnings []string, errors []error) { + warnings, errors = tags.Validate(i, k) + if len(errors) > 0 { + return + } + + tagsMap := i.(map[string]interface{}) + if _, ok := tagsMap["hidden-title"]; ok { + errors = append(errors, fmt.Errorf("a tag with the key `hidden-title` should not be used to set the display name. Please Use `display_name` instead")) + } + + return +} diff --git a/internal/services/appservice/helpers/function_app_schema.go b/internal/services/appservice/helpers/function_app_schema.go index 333fe1d20814..848b1458b27f 100644 --- a/internal/services/appservice/helpers/function_app_schema.go +++ b/internal/services/appservice/helpers/function_app_schema.go @@ -1551,7 +1551,7 @@ func ExpandSiteConfigLinuxFunctionApp(siteConfig []SiteConfigLinuxFunctionApp, e if linuxAppStack.NodeVersion != "" { appSettings = updateOrAppendAppSettings(appSettings, "FUNCTIONS_WORKER_RUNTIME", "node", false) appSettings = updateOrAppendAppSettings(appSettings, "WEBSITE_NODE_DEFAULT_VERSION", linuxAppStack.NodeVersion, false) - expanded.LinuxFxVersion = utils.String(fmt.Sprintf("Node|%s", linuxAppStack.NodeVersion)) + expanded.LinuxFxVersion = utils.String(fmt.Sprintf("NODE|%s", linuxAppStack.NodeVersion)) } if linuxAppStack.PythonVersion != "" { @@ -1687,6 +1687,10 @@ func ExpandSiteConfigLinuxFunctionApp(siteConfig []SiteConfigLinuxFunctionApp, e expanded.MinimumElasticInstanceCount = utils.Int32(int32(linuxSiteConfig.ElasticInstanceMinimum)) } + if metadata.ResourceData.HasChange("site_config.0.runtime_scale_monitoring_enabled") { + expanded.FunctionsRuntimeScaleMonitoringEnabled = utils.Bool(linuxSiteConfig.RuntimeScaleMonitoring) + } + expanded.AppSettings = &appSettings return expanded, nil @@ -1798,36 +1802,36 @@ func ExpandSiteConfigWindowsFunctionApp(siteConfig []SiteConfigWindowsFunctionAp if windowsAppStack.DotNetVersion != "" { if windowsAppStack.DotNetIsolated { appSettings = updateOrAppendAppSettings(appSettings, "FUNCTIONS_WORKER_RUNTIME", "dotnet-isolated", false) - windowsSiteConfig.WindowsFxVersion = fmt.Sprintf("DOTNET-ISOLATED|%s", windowsAppStack.DotNetVersion) + expanded.WindowsFxVersion = utils.String(fmt.Sprintf("DOTNET-ISOLATED|%s", windowsAppStack.DotNetVersion)) } else { appSettings = updateOrAppendAppSettings(appSettings, "FUNCTIONS_WORKER_RUNTIME", "dotnet", false) - windowsSiteConfig.WindowsFxVersion = fmt.Sprintf("DOTNET|%s", windowsAppStack.DotNetVersion) + expanded.WindowsFxVersion = utils.String(fmt.Sprintf("DOTNET|%s", windowsAppStack.DotNetVersion)) } } if windowsAppStack.NodeVersion != "" { appSettings = updateOrAppendAppSettings(appSettings, "FUNCTIONS_WORKER_RUNTIME", "node", false) appSettings = updateOrAppendAppSettings(appSettings, "WEBSITE_NODE_DEFAULT_VERSION", windowsAppStack.NodeVersion, false) - windowsSiteConfig.WindowsFxVersion = fmt.Sprintf("Node|%s", windowsAppStack.NodeVersion) + expanded.WindowsFxVersion = utils.String(fmt.Sprintf("Node|%s", windowsAppStack.NodeVersion)) } if windowsAppStack.JavaVersion != "" { appSettings = updateOrAppendAppSettings(appSettings, "FUNCTIONS_WORKER_RUNTIME", "java", false) - windowsSiteConfig.WindowsFxVersion = fmt.Sprintf("Java|%s", windowsAppStack.JavaVersion) + expanded.WindowsFxVersion = utils.String(fmt.Sprintf("Java|%s", windowsAppStack.JavaVersion)) } if windowsAppStack.PowerShellCoreVersion != "" { appSettings = updateOrAppendAppSettings(appSettings, "FUNCTIONS_WORKER_RUNTIME", "powershell", false) - windowsSiteConfig.WindowsFxVersion = fmt.Sprintf("PowerShell|%s", windowsAppStack.PowerShellCoreVersion) + expanded.WindowsFxVersion = utils.String(fmt.Sprintf("PowerShell|%s", windowsAppStack.PowerShellCoreVersion)) } if windowsAppStack.CustomHandler { appSettings = updateOrAppendAppSettings(appSettings, "FUNCTIONS_WORKER_RUNTIME", "custom", false) - windowsSiteConfig.WindowsFxVersion = "" // Custom needs an explicit empty string here + expanded.WindowsFxVersion = utils.String("") // Custom needs an explicit empty string here } } else { appSettings = updateOrAppendAppSettings(appSettings, "FUNCTIONS_WORKER_RUNTIME", "", true) - windowsSiteConfig.WindowsFxVersion = "" + expanded.WindowsFxVersion = utils.String("") } if metadata.ResourceData.HasChange("site_config.0.vnet_route_all_enabled") { @@ -1923,6 +1927,10 @@ func ExpandSiteConfigWindowsFunctionApp(siteConfig []SiteConfigWindowsFunctionAp expanded.MinimumElasticInstanceCount = utils.Int32(int32(windowsSiteConfig.ElasticInstanceMinimum)) } + if metadata.ResourceData.HasChange("site_config.0.runtime_scale_monitoring_enabled") { + expanded.FunctionsRuntimeScaleMonitoringEnabled = utils.Bool(windowsSiteConfig.RuntimeScaleMonitoring) + } + expanded.AppSettings = &appSettings return expanded, nil diff --git a/internal/services/appservice/helpers/function_app_slot_schema.go b/internal/services/appservice/helpers/function_app_slot_schema.go index dd213469737a..7c714e60ddd8 100644 --- a/internal/services/appservice/helpers/function_app_slot_schema.go +++ b/internal/services/appservice/helpers/function_app_slot_schema.go @@ -734,14 +734,14 @@ func ExpandSiteConfigWindowsFunctionAppSlot(siteConfig []SiteConfigWindowsFuncti Name: utils.String("FUNCTIONS_WORKER_RUNTIME"), Value: utils.String("dotnet-isolated"), }) - windowsSlotSiteConfig.WindowsFxVersion = fmt.Sprintf("DOTNET-ISOLATED|%s", windowsAppStack.DotNetVersion) + expanded.WindowsFxVersion = utils.String(fmt.Sprintf("DOTNET-ISOLATED|%s", windowsAppStack.DotNetVersion)) } else { appSettings = append(appSettings, web.NameValuePair{ Name: utils.String("FUNCTIONS_WORKER_RUNTIME"), Value: utils.String("dotnet"), }) - windowsSlotSiteConfig.WindowsFxVersion = fmt.Sprintf("DOTNET|%s", windowsAppStack.DotNetVersion) + expanded.WindowsFxVersion = utils.String(fmt.Sprintf("DOTNET|%s", windowsAppStack.DotNetVersion)) } } @@ -754,7 +754,7 @@ func ExpandSiteConfigWindowsFunctionAppSlot(siteConfig []SiteConfigWindowsFuncti Name: utils.String("WEBSITE_NODE_DEFAULT_VERSION"), Value: utils.String(windowsAppStack.NodeVersion), }) - windowsSlotSiteConfig.WindowsFxVersion = fmt.Sprintf("Node|%s", windowsAppStack.NodeVersion) + expanded.WindowsFxVersion = utils.String(fmt.Sprintf("Node|%s", windowsAppStack.NodeVersion)) } if windowsAppStack.JavaVersion != "" { @@ -762,7 +762,7 @@ func ExpandSiteConfigWindowsFunctionAppSlot(siteConfig []SiteConfigWindowsFuncti Name: utils.String("FUNCTIONS_WORKER_RUNTIME"), Value: utils.String("java"), }) - windowsSlotSiteConfig.WindowsFxVersion = fmt.Sprintf("Java|%s", windowsAppStack.JavaVersion) + expanded.WindowsFxVersion = utils.String(fmt.Sprintf("Java|%s", windowsAppStack.JavaVersion)) } if windowsAppStack.PowerShellCoreVersion != "" { @@ -770,7 +770,7 @@ func ExpandSiteConfigWindowsFunctionAppSlot(siteConfig []SiteConfigWindowsFuncti Name: utils.String("FUNCTIONS_WORKER_RUNTIME"), Value: utils.String("powershell"), }) - windowsSlotSiteConfig.WindowsFxVersion = fmt.Sprintf("PowerShell|%s", windowsAppStack.PowerShellCoreVersion) + expanded.WindowsFxVersion = utils.String(fmt.Sprintf("PowerShell|%s", windowsAppStack.PowerShellCoreVersion)) } if windowsAppStack.CustomHandler { @@ -778,14 +778,14 @@ func ExpandSiteConfigWindowsFunctionAppSlot(siteConfig []SiteConfigWindowsFuncti Name: utils.String("FUNCTIONS_WORKER_RUNTIME"), Value: utils.String("custom"), }) - windowsSlotSiteConfig.WindowsFxVersion = "" // Custom needs an explicit empty string here + expanded.WindowsFxVersion = utils.String("") // Custom needs an explicit empty string here } } else { appSettings = append(appSettings, web.NameValuePair{ Name: utils.String("FUNCTIONS_WORKER_RUNTIME"), Value: utils.String(""), }) - windowsSlotSiteConfig.WindowsFxVersion = "" + expanded.WindowsFxVersion = utils.String("") } } @@ -951,6 +951,7 @@ func ExpandSiteConfigLinuxFunctionAppSlot(siteConfig []SiteConfigLinuxFunctionAp if len(siteConfig) == 0 { return nil, nil } + expanded := &web.SiteConfig{} if existing != nil { expanded = existing @@ -1029,92 +1030,91 @@ func ExpandSiteConfigLinuxFunctionAppSlot(siteConfig []SiteConfigLinuxFunctionAp expanded.AppCommandLine = utils.String(linuxSlotSiteConfig.AppCommandLine) } - if metadata.ResourceData.HasChange("site_config.0.application_stack") && len(linuxSlotSiteConfig.ApplicationStack) > 0 { - if len(linuxSlotSiteConfig.ApplicationStack) > 0 { - linuxAppStack := linuxSlotSiteConfig.ApplicationStack[0] - if linuxAppStack.DotNetVersion != "" { - if linuxAppStack.DotNetIsolated { - appSettings = append(appSettings, web.NameValuePair{ - Name: utils.String("FUNCTIONS_WORKER_RUNTIME"), - Value: utils.String("dotnet-isolated"), - }) - linuxSlotSiteConfig.LinuxFxVersion = fmt.Sprintf("DOTNET-ISOLATED|%s", linuxAppStack.DotNetVersion) - } else { - appSettings = append(appSettings, web.NameValuePair{ - Name: utils.String("FUNCTIONS_WORKER_RUNTIME"), - Value: utils.String("dotnet"), - }) - linuxSlotSiteConfig.LinuxFxVersion = fmt.Sprintf("DOTNET|%s", linuxAppStack.DotNetVersion) - } - } - - if linuxAppStack.NodeVersion != "" { + if len(linuxSlotSiteConfig.ApplicationStack) > 0 { + linuxAppStack := linuxSlotSiteConfig.ApplicationStack[0] + if linuxAppStack.DotNetVersion != "" { + if linuxAppStack.DotNetIsolated { appSettings = append(appSettings, web.NameValuePair{ Name: utils.String("FUNCTIONS_WORKER_RUNTIME"), - Value: utils.String("node"), + Value: utils.String("dotnet-isolated"), }) - appSettings = append(appSettings, web.NameValuePair{ - Name: utils.String("WEBSITE_NODE_DEFAULT_VERSION"), - Value: utils.String(linuxAppStack.NodeVersion), - }) - linuxSlotSiteConfig.LinuxFxVersion = fmt.Sprintf("Node|%s", linuxAppStack.NodeVersion) - } - - if linuxAppStack.PythonVersion != "" { + expanded.LinuxFxVersion = utils.String(fmt.Sprintf("DOTNET-ISOLATED|%s", linuxAppStack.DotNetVersion)) + } else { appSettings = append(appSettings, web.NameValuePair{ Name: utils.String("FUNCTIONS_WORKER_RUNTIME"), - Value: utils.String("python"), + Value: utils.String("dotnet"), }) - linuxSlotSiteConfig.LinuxFxVersion = fmt.Sprintf("Python|%s", linuxAppStack.PythonVersion) + expanded.LinuxFxVersion = utils.String(fmt.Sprintf("DOTNET|%s", linuxAppStack.DotNetVersion)) } + } - if linuxAppStack.JavaVersion != "" { - appSettings = append(appSettings, web.NameValuePair{ - Name: utils.String("FUNCTIONS_WORKER_RUNTIME"), - Value: utils.String("java"), - }) - linuxSlotSiteConfig.LinuxFxVersion = fmt.Sprintf("Java|%s", linuxAppStack.JavaVersion) - } + if linuxAppStack.NodeVersion != "" { + appSettings = append(appSettings, web.NameValuePair{ + Name: utils.String("FUNCTIONS_WORKER_RUNTIME"), + Value: utils.String("node"), + }) + appSettings = append(appSettings, web.NameValuePair{ + Name: utils.String("WEBSITE_NODE_DEFAULT_VERSION"), + Value: utils.String(linuxAppStack.NodeVersion), + }) + expanded.LinuxFxVersion = utils.String(fmt.Sprintf("NODE|%s", linuxAppStack.NodeVersion)) + } - if linuxAppStack.PowerShellCoreVersion != "" { - appSettings = append(appSettings, web.NameValuePair{ - Name: utils.String("FUNCTIONS_WORKER_RUNTIME"), - Value: utils.String("powershell"), - }) - linuxSlotSiteConfig.LinuxFxVersion = fmt.Sprintf("PowerShell|%s", linuxAppStack.PowerShellCoreVersion) - } + if linuxAppStack.PythonVersion != "" { + appSettings = append(appSettings, web.NameValuePair{ + Name: utils.String("FUNCTIONS_WORKER_RUNTIME"), + Value: utils.String("python"), + }) + expanded.LinuxFxVersion = utils.String(fmt.Sprintf("Python|%s", linuxAppStack.PythonVersion)) + } - if linuxAppStack.CustomHandler { - appSettings = append(appSettings, web.NameValuePair{ - Name: utils.String("FUNCTIONS_WORKER_RUNTIME"), - Value: utils.String("custom"), - }) - linuxSlotSiteConfig.LinuxFxVersion = "" // Custom needs an explicit empty string here - } + if linuxAppStack.JavaVersion != "" { + appSettings = append(appSettings, web.NameValuePair{ + Name: utils.String("FUNCTIONS_WORKER_RUNTIME"), + Value: utils.String("java"), + }) + expanded.LinuxFxVersion = utils.String(fmt.Sprintf("Java|%s", linuxAppStack.JavaVersion)) + } - if linuxAppStack.Docker != nil && len(linuxAppStack.Docker) == 1 { - dockerConfig := linuxAppStack.Docker[0] - appSettings = append(appSettings, web.NameValuePair{ - Name: utils.String("DOCKER_REGISTRY_SERVER_URL"), - Value: utils.String(dockerConfig.RegistryURL), - }) - appSettings = append(appSettings, web.NameValuePair{ - Name: utils.String("DOCKER_REGISTRY_SERVER_USERNAME"), - Value: utils.String(dockerConfig.RegistryUsername), - }) - appSettings = append(appSettings, web.NameValuePair{ - Name: utils.String("DOCKER_REGISTRY_SERVER_PASSWORD"), - Value: utils.String(dockerConfig.RegistryPassword), - }) - linuxSlotSiteConfig.LinuxFxVersion = fmt.Sprintf("DOCKER|%s/%s:%s", dockerConfig.RegistryURL, dockerConfig.ImageName, dockerConfig.ImageTag) - } - } else { + if linuxAppStack.PowerShellCoreVersion != "" { appSettings = append(appSettings, web.NameValuePair{ Name: utils.String("FUNCTIONS_WORKER_RUNTIME"), - Value: utils.String(""), + Value: utils.String("powershell"), + }) + expanded.LinuxFxVersion = utils.String(fmt.Sprintf("PowerShell|%s", linuxAppStack.PowerShellCoreVersion)) + } + + if linuxAppStack.CustomHandler { + appSettings = append(appSettings, web.NameValuePair{ + Name: utils.String("FUNCTIONS_WORKER_RUNTIME"), + Value: utils.String("custom"), }) - linuxSlotSiteConfig.LinuxFxVersion = "" + expanded.LinuxFxVersion = utils.String("") // Custom needs an explicit empty string here } + + if linuxAppStack.Docker != nil && len(linuxAppStack.Docker) == 1 { + dockerConfig := linuxAppStack.Docker[0] + appSettings = append(appSettings, web.NameValuePair{ + Name: utils.String("DOCKER_REGISTRY_SERVER_URL"), + Value: utils.String(dockerConfig.RegistryURL), + }) + appSettings = append(appSettings, web.NameValuePair{ + Name: utils.String("DOCKER_REGISTRY_SERVER_USERNAME"), + Value: utils.String(dockerConfig.RegistryUsername), + }) + appSettings = append(appSettings, web.NameValuePair{ + Name: utils.String("DOCKER_REGISTRY_SERVER_PASSWORD"), + Value: utils.String(dockerConfig.RegistryPassword), + }) + expanded.LinuxFxVersion = utils.String(fmt.Sprintf("DOCKER|%s/%s:%s", dockerConfig.RegistryURL, dockerConfig.ImageName, dockerConfig.ImageTag)) + } + + } else { + appSettings = append(appSettings, web.NameValuePair{ + Name: utils.String("FUNCTIONS_WORKER_RUNTIME"), + Value: utils.String(""), + }) + expanded.LinuxFxVersion = utils.String("") } expanded.AcrUseManagedIdentityCreds = utils.Bool(linuxSlotSiteConfig.UseManagedIdentityACR) diff --git a/internal/services/appservice/helpers/service_plan.go b/internal/services/appservice/helpers/service_plan.go index 1a8efd3ab991..2477ec4c4aa8 100644 --- a/internal/services/appservice/helpers/service_plan.go +++ b/internal/services/appservice/helpers/service_plan.go @@ -26,7 +26,6 @@ var appServicePlanSkus = []string{ var freeSkus = []string{ "F1", - "FREE", } var sharedSkus = []string{ diff --git a/internal/services/appservice/helpers/web_app_schema.go b/internal/services/appservice/helpers/web_app_schema.go index e26bf287988e..a4e51d19dc80 100644 --- a/internal/services/appservice/helpers/web_app_schema.go +++ b/internal/services/appservice/helpers/web_app_schema.go @@ -8,6 +8,7 @@ import ( "github.com/Azure/azure-sdk-for-go/services/web/mgmt/2021-02-01/web" "github.com/Azure/go-autorest/autorest/date" + "github.com/hashicorp/terraform-provider-azurerm/internal/features" "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" apimValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/apimanagement/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" @@ -867,6 +868,7 @@ type ApplicationStackWindows struct { } // Version information for the below validations was taken in part from - https://github.com/Azure/app-service-linux-docs/tree/master/Runtime_Support +// There is no 3.0 version of .netFramework, setting the property to this value causing app to be broke. func windowsApplicationStackSchema() *pluginsdk.Schema { return &pluginsdk.Schema{ Type: pluginsdk.TypeList, @@ -878,12 +880,24 @@ func windowsApplicationStackSchema() *pluginsdk.Schema { "dotnet_version": { Type: pluginsdk.TypeString, Optional: true, - ValidateFunc: validation.StringInSlice([]string{ - "v3.0", - "v4.0", - "v5.0", - "v6.0", - }, false), + ValidateFunc: func() pluginsdk.SchemaValidateFunc { + if !features.FourPointOh() { + return validation.StringInSlice([]string{ + "v2.0", + "v3.0", + "core3.1", + "v4.0", + "v5.0", + "v6.0"}, false) + } + return validation.StringInSlice([]string{ + "v2.0", + "core3.1", + "v4.0", + "v5.0", + "v6.0", + }, false) + }(), AtLeastOneOf: []string{ "site_config.0.application_stack.0.docker_container_name", "site_config.0.application_stack.0.dotnet_version", @@ -2902,6 +2916,9 @@ func ExpandSiteConfigWindows(siteConfig []SiteConfigWindows, existing *web.SiteC if len(winSiteConfig.ApplicationStack) == 1 { winAppStack := winSiteConfig.ApplicationStack[0] expanded.NetFrameworkVersion = utils.String(winAppStack.NetFrameworkVersion) + if winAppStack.CurrentStack == "dotnetcore" { + expanded.NetFrameworkVersion = nil + } expanded.PhpVersion = utils.String(winAppStack.PhpVersion) expanded.NodeVersion = utils.String(winAppStack.NodeVersion) expanded.PythonVersion = utils.String(winAppStack.PythonVersion) diff --git a/internal/services/appservice/linux_function_app_data_source.go b/internal/services/appservice/linux_function_app_data_source.go index 89bcfbb5b33c..5bc87d017455 100644 --- a/internal/services/appservice/linux_function_app_data_source.go +++ b/internal/services/appservice/linux_function_app_data_source.go @@ -47,6 +47,7 @@ type LinuxFunctionAppDataSourceModel struct { SiteConfig []helpers.SiteConfigLinuxFunctionApp `tfschema:"site_config"` StickySettings []helpers.StickySettings `tfschema:"sticky_settings"` Tags map[string]string `tfschema:"tags"` + VirtualNetworkSubnetID string `tfschema:"virtual_network_subnet_id"` CustomDomainVerificationId string `tfschema:"custom_domain_verification_id"` DefaultHostname string `tfschema:"default_hostname"` @@ -219,6 +220,11 @@ func (d LinuxFunctionAppDataSource) Attributes() map[string]*pluginsdk.Schema { "site_credential": helpers.SiteCredentialSchema(), "sticky_settings": helpers.StickySettingsComputedSchema(), + + "virtual_network_subnet_id": { + Type: pluginsdk.TypeString, + Computed: true, + }, } } @@ -309,6 +315,16 @@ func (d LinuxFunctionAppDataSource) Read() sdk.ResourceFunc { DefaultHostname: utils.NormalizeNilableString(functionApp.DefaultHostName), } + if v := props.OutboundIPAddresses; v != nil { + state.OutboundIPAddresses = *v + state.OutboundIPAddressList = strings.Split(*v, ",") + } + + if v := props.PossibleOutboundIPAddresses; v != nil { + state.PossibleOutboundIPAddresses = *v + state.PossibleOutboundIPAddressList = strings.Split(*v, ",") + } + configResp, err := client.GetConfiguration(ctx, id.ResourceGroup, id.SiteName) if err != nil { return fmt.Errorf("making Read request on AzureRM Function App Configuration %q: %+v", id.SiteName, err) @@ -334,6 +350,7 @@ func (d LinuxFunctionAppDataSource) Read() sdk.ResourceFunc { state.HttpsOnly = utils.NormaliseNilableBool(functionApp.HTTPSOnly) state.ClientCertEnabled = utils.NormaliseNilableBool(functionApp.ClientCertEnabled) + state.VirtualNetworkSubnetID = utils.NormalizeNilableString(functionApp.VirtualNetworkSubnetID) metadata.SetID(id) diff --git a/internal/services/appservice/linux_function_app_data_source_test.go b/internal/services/appservice/linux_function_app_data_source_test.go index aa29c992a841..6a751da77063 100644 --- a/internal/services/appservice/linux_function_app_data_source_test.go +++ b/internal/services/appservice/linux_function_app_data_source_test.go @@ -2,6 +2,7 @@ package appservice_test import ( "fmt" + "regexp" "testing" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" @@ -14,11 +15,17 @@ func TestAccLinuxFunctionAppDataSource_standardComplete(t *testing.T) { data := acceptance.BuildTestData(t, "data.azurerm_linux_function_app", "test") d := LinuxFunctionAppDataSource{} + ipListRegex := regexp.MustCompile(`(([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})(,){0,1})+`) + data.DataSourceTest(t, []acceptance.TestStep{ { Config: d.standardComplete(data), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).Key("location").HasValue(data.Locations.Primary), + check.That(data.ResourceName).Key("outbound_ip_addresses").MatchesRegex(ipListRegex), + check.That(data.ResourceName).Key("outbound_ip_address_list.#").Exists(), + check.That(data.ResourceName).Key("possible_outbound_ip_addresses").MatchesRegex(ipListRegex), + check.That(data.ResourceName).Key("possible_outbound_ip_address_list.#").Exists(), check.That(data.ResourceName).Key("default_hostname").HasValue(fmt.Sprintf("acctest-lfa-%d.azurewebsites.net", data.RandomInteger)), ), }, diff --git a/internal/services/appservice/linux_function_app_resource.go b/internal/services/appservice/linux_function_app_resource.go index 7296966de840..3ea480a09c61 100644 --- a/internal/services/appservice/linux_function_app_resource.go +++ b/internal/services/appservice/linux_function_app_resource.go @@ -18,6 +18,7 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/internal/services/appservice/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/appservice/validate" kvValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/keyvault/validate" + networkValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/validate" storageValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/storage/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" @@ -54,6 +55,7 @@ type LinuxFunctionAppModel struct { KeyVaultReferenceIdentityID string `tfschema:"key_vault_reference_identity_id"` SiteConfig []helpers.SiteConfigLinuxFunctionApp `tfschema:"site_config"` Tags map[string]string `tfschema:"tags"` + VirtualNetworkSubnetID string `tfschema:"virtual_network_subnet_id"` // Computed CustomDomainVerificationId string `tfschema:"custom_domain_verification_id"` @@ -243,6 +245,12 @@ func (r LinuxFunctionAppResource) Arguments() map[string]*pluginsdk.Schema { "sticky_settings": helpers.StickySettingsSchema(), "tags": tags.Schema(), + + "virtual_network_subnet_id": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: networkValidate.SubnetID, + }, } } @@ -321,22 +329,12 @@ func (r LinuxFunctionAppResource) Create() sdk.ResourceFunc { return fmt.Errorf("reading %s: %+v", servicePlanId, err) } - sendContentSettings := !functionApp.ForceDisableContentShare - if planSku := servicePlan.Sku; planSku != nil && planSku.Tier != nil { - switch tier := *planSku.Tier; strings.ToLower(tier) { - case "dynamic": // Consumption Plan modifications to request - sendContentSettings = false - case "elastic": // ElasticPremium Plan modifications to request? - case "basic": // App Service Plan modifications to request? - sendContentSettings = false - case "standard": - sendContentSettings = false - case "premiumv2", "premiumv3": - sendContentSettings = false - } - } else { - return fmt.Errorf("determining plan type for Linux %s: %v", id, err) + var planSKU *string + if sku := servicePlan.Sku; sku != nil && sku.Name != nil { + planSKU = sku.Name } + // Only send for ElasticPremium + sendContentSettings := helpers.PlanIsElastic(planSKU) && !functionApp.ForceDisableContentShare existing, err := client.Get(ctx, id.ResourceGroup, id.SiteName) if err != nil && !utils.ResponseWasNotFound(existing.Response) { @@ -413,12 +411,18 @@ func (r LinuxFunctionAppResource) Create() sdk.ResourceFunc { if functionApp.AppSettings == nil { functionApp.AppSettings = make(map[string]string) } - suffix := uuid.New().String()[0:4] - if _, present := functionApp.AppSettings["WEBSITE_CONTENTSHARE"]; !present { - functionApp.AppSettings["WEBSITE_CONTENTSHARE"] = fmt.Sprintf("%s-%s", strings.ToLower(functionApp.Name), suffix) - } - if _, present := functionApp.AppSettings["WEBSITE_CONTENTAZUREFILECONNECTIONSTRING"]; !present { - functionApp.AppSettings["WEBSITE_CONTENTAZUREFILECONNECTIONSTRING"] = storageString + if !functionApp.StorageUsesMSI { + suffix := uuid.New().String()[0:4] + if _, present := functionApp.AppSettings["WEBSITE_CONTENTSHARE"]; !present { + functionApp.AppSettings["WEBSITE_CONTENTSHARE"] = fmt.Sprintf("%s-%s", strings.ToLower(functionApp.Name), suffix) + } + if _, present := functionApp.AppSettings["WEBSITE_CONTENTAZUREFILECONNECTIONSTRING"]; !present { + functionApp.AppSettings["WEBSITE_CONTENTAZUREFILECONNECTIONSTRING"] = storageString + } + } else { + if _, present := functionApp.AppSettings["AzureWebJobsStorage__accountName"]; !present { + functionApp.AppSettings["AzureWebJobsStorage__accountName"] = storageString + } } } @@ -450,6 +454,10 @@ func (r LinuxFunctionAppResource) Create() sdk.ResourceFunc { siteEnvelope.SiteProperties.KeyVaultReferenceIdentity = utils.String(functionApp.KeyVaultReferenceIdentityID) } + if functionApp.VirtualNetworkSubnetID != "" { + siteEnvelope.SiteProperties.VirtualNetworkSubnetID = utils.String(functionApp.VirtualNetworkSubnetID) + } + future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.SiteName, siteEnvelope) if err != nil { return fmt.Errorf("creating Linux %s: %+v", id, err) @@ -595,6 +603,16 @@ func (r LinuxFunctionAppResource) Read() sdk.ResourceFunc { DefaultHostname: utils.NormalizeNilableString(props.DefaultHostName), } + if v := props.OutboundIPAddresses; v != nil { + state.OutboundIPAddresses = *v + state.OutboundIPAddressList = strings.Split(*v, ",") + } + + if v := props.PossibleOutboundIPAddresses; v != nil { + state.PossibleOutboundIPAddresses = *v + state.PossibleOutboundIPAddressList = strings.Split(*v, ",") + } + configResp, err := client.GetConfiguration(ctx, id.ResourceGroup, id.SiteName) if err != nil { return fmt.Errorf("making Read request on AzureRM Function App Configuration %q: %+v", id.SiteName, err) @@ -621,6 +639,10 @@ func (r LinuxFunctionAppResource) Read() sdk.ResourceFunc { state.HttpsOnly = utils.NormaliseNilableBool(functionApp.HTTPSOnly) state.ClientCertEnabled = utils.NormaliseNilableBool(functionApp.ClientCertEnabled) + if subnetId := utils.NormalizeNilableString(props.VirtualNetworkSubnetID); subnetId != "" { + state.VirtualNetworkSubnetID = subnetId + } + if err := metadata.Encode(&state); err != nil { return fmt.Errorf("encoding: %+v", err) } @@ -687,7 +709,7 @@ func (r LinuxFunctionAppResource) Update() sdk.ResourceFunc { } // Only send for ElasticPremium - sendContentSettings := helpers.PlanIsElastic(planSKU) + sendContentSettings := helpers.PlanIsElastic(planSKU) && !state.ForceDisableContentShare // Some service plan updates are allowed - see customiseDiff for exceptions if metadata.ResourceData.HasChange("service_plan_id") { @@ -702,6 +724,19 @@ func (r LinuxFunctionAppResource) Update() sdk.ResourceFunc { existing.SiteProperties.HTTPSOnly = utils.Bool(state.HttpsOnly) } + if metadata.ResourceData.HasChange("virtual_network_subnet_id") { + subnetId := metadata.ResourceData.Get("virtual_network_subnet_id").(string) + if subnetId == "" { + if _, err := client.DeleteSwiftVirtualNetwork(ctx, id.ResourceGroup, id.SiteName); err != nil { + return fmt.Errorf("removing `virtual_network_subnet_id` association for %s: %+v", *id, err) + } + var empty *string + existing.SiteProperties.VirtualNetworkSubnetID = empty + } else { + existing.SiteProperties.VirtualNetworkSubnetID = utils.String(subnetId) + } + } + if metadata.ResourceData.HasChange("client_certificate_enabled") { existing.SiteProperties.ClientCertEnabled = utils.Bool(state.ClientCertEnabled) } diff --git a/internal/services/appservice/linux_function_app_resource_test.go b/internal/services/appservice/linux_function_app_resource_test.go index c99013c45f94..312948a4ad52 100644 --- a/internal/services/appservice/linux_function_app_resource_test.go +++ b/internal/services/appservice/linux_function_app_resource_test.go @@ -42,6 +42,23 @@ func TestAccLinuxFunctionApp_basicBasicPlan(t *testing.T) { }) } +func TestAccLinuxFunctionApp_basicRuntimeCheck(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_linux_function_app", "test") + r := LinuxFunctionAppResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.runtimeScaleCheck(data, SkuElasticPremiumPlan), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("kind").HasValue("functionapp,linux"), + check.That(data.ResourceName).Key("site_config.0.runtime_scale_monitoring_enabled").HasValue("true"), + ), + }, + data.ImportStep(), + }) +} + func TestAccLinuxFunctionApp_basicConsumptionPlan(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_linux_function_app", "test") r := LinuxFunctionAppResource{} @@ -885,6 +902,7 @@ func TestAccLinuxFunctionApp_appStackNodeUpdate(t *testing.T) { Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), check.That(data.ResourceName).Key("kind").HasValue("functionapp,linux"), + check.That(data.ResourceName).Key("site_config.0.linux_fx_version").HasValue("NODE|12"), ), }, data.ImportStep(), @@ -893,6 +911,7 @@ func TestAccLinuxFunctionApp_appStackNodeUpdate(t *testing.T) { Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), check.That(data.ResourceName).Key("kind").HasValue("functionapp,linux"), + check.That(data.ResourceName).Key("site_config.0.linux_fx_version").HasValue("NODE|16"), ), }, data.ImportStep(), @@ -901,6 +920,16 @@ func TestAccLinuxFunctionApp_appStackNodeUpdate(t *testing.T) { Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), check.That(data.ResourceName).Key("kind").HasValue("functionapp,linux"), + check.That(data.ResourceName).Key("site_config.0.linux_fx_version").HasValue("NODE|14"), + ), + }, + data.ImportStep(), + { + Config: r.appStackNodeUpdateTags(data, SkuBasicPlan, "14"), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("kind").HasValue("functionapp,linux"), + check.That(data.ResourceName).Key("site_config.0.linux_fx_version").HasValue("NODE|14"), ), }, data.ImportStep(), @@ -1096,7 +1125,22 @@ func TestAccLinuxFunctionApp_updateStorageAccount(t *testing.T) { }) } -func TestAccLinuxFunctionApp_msiStorageAccount(t *testing.T) { +func TestAccLinuxFunctionApp_msiStorageAccountElastic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_linux_function_app", "test") + r := LinuxFunctionAppResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.msiStorageAccount(data, SkuElasticPremiumPlan), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("kind").HasValue("functionapp,linux"), + ), + }, + data.ImportStep(), + }) +} +func TestAccLinuxFunctionApp_msiStorageAccountStandard(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_linux_function_app", "test") r := LinuxFunctionAppResource{} @@ -1168,6 +1212,21 @@ func TestAccLinuxFunctionApp_storageAccountKeyVaultSecretVersionless(t *testing. }) } +func TestAccLinuxFunctionAppASEv3_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_linux_function_app", "test") + r := LinuxFunctionAppResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.withASEV3(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + // CustomDiff tests func TestAccLinuxFunctionApp_consumptionPlanBackupShouldError(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_linux_function_app", "test") @@ -1193,6 +1252,90 @@ func TestAccLinuxFunctionApp_basicPlanBackupShouldError(t *testing.T) { }) } +func TestAccLinuxFunctionApp_vNetIntegration(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_linux_function_app", "test") + r := LinuxFunctionAppResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.vNetIntegration_subnet1(data, SkuStandardPlan), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("virtual_network_subnet_id").MatchesOtherKey( + check.That("azurerm_subnet.test1").Key("id"), + ), + ), + }, + data.ImportStep(), + }) +} + +func TestAccLinuxFunctionApp_vNetIntegrationUpdate(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_linux_function_app", "test") + r := LinuxFunctionAppResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.vNetIntegration_basic(data, SkuStandardPlan), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.vNetIntegration_subnet1(data, SkuStandardPlan), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("virtual_network_subnet_id").MatchesOtherKey( + check.That("azurerm_subnet.test1").Key("id"), + ), + ), + }, + data.ImportStep(), + { + Config: r.vNetIntegration_subnet2(data, SkuStandardPlan), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("virtual_network_subnet_id").MatchesOtherKey( + check.That("azurerm_subnet.test2").Key("id"), + ), + ), + }, + data.ImportStep(), + { + Config: r.vNetIntegration_basic(data, SkuStandardPlan), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +// Outputs + +func TestAccLinuxFunctionApp_basicOutputs(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_linux_function_app", "test") + r := LinuxFunctionAppResource{} + + ipListRegex := regexp.MustCompile(`(([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})(,){0,1})+`) + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data, SkuStandardPlan), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("outbound_ip_addresses").MatchesRegex(ipListRegex), + check.That(data.ResourceName).Key("outbound_ip_address_list.#").Exists(), + check.That(data.ResourceName).Key("possible_outbound_ip_addresses").MatchesRegex(ipListRegex), + check.That(data.ResourceName).Key("possible_outbound_ip_address_list.#").Exists(), + check.That(data.ResourceName).Key("default_hostname").MatchesRegex(regexp.MustCompile(`(.)+`)), + ), + }, + data.ImportStep(), + }) +} + // Configs func (r LinuxFunctionAppResource) Exists(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { @@ -1236,6 +1379,31 @@ resource "azurerm_linux_function_app" "test" { `, r.template(data, planSku), data.RandomInteger) } +func (r LinuxFunctionAppResource) runtimeScaleCheck(data acceptance.TestData, planSku string) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +%s + +resource "azurerm_linux_function_app" "test" { + name = "acctest-LFA-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + service_plan_id = azurerm_service_plan.test.id + + storage_account_name = azurerm_storage_account.test.name + storage_account_access_key = azurerm_storage_account.test.primary_access_key + + site_config { + runtime_scale_monitoring_enabled = true + pre_warmed_instance_count = 1 + } +} +`, r.template(data, planSku), data.RandomInteger) +} + func (r LinuxFunctionAppResource) healthCheckPath(data acceptance.TestData, planSku string) string { return fmt.Sprintf(` provider "azurerm" { @@ -1941,6 +2109,36 @@ resource "azurerm_linux_function_app" "test" { `, r.template(data, planSku), data.RandomInteger, nodeVersion) } +func (r LinuxFunctionAppResource) appStackNodeUpdateTags(data acceptance.TestData, planSku string, nodeVersion string) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +%s + +resource "azurerm_linux_function_app" "test" { + name = "acctest-LFA-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + service_plan_id = azurerm_service_plan.test.id + + storage_account_name = azurerm_storage_account.test.name + storage_account_access_key = azurerm_storage_account.test.primary_access_key + + site_config { + application_stack { + node_version = "%s" + } + } + + tags = { + foo = "bar" + } +} +`, r.template(data, planSku), data.RandomInteger, nodeVersion) +} + func (r LinuxFunctionAppResource) appStackDocker(data acceptance.TestData, planSku string) string { return fmt.Sprintf(` provider "azurerm" { @@ -2800,7 +2998,11 @@ resource "azurerm_linux_function_app" "test" { type = "SystemAssigned" } - site_config {} + site_config { + application_stack { + python_version = "3.9" + } + } } `, r.template(data, planSku), data.RandomInteger) } @@ -3136,3 +3338,222 @@ resource "azurerm_user_assigned_identity" "test" { } `, r.template(data, planSku), data.RandomInteger) } + +func (r LinuxFunctionAppResource) vNetIntegration_basic(data acceptance.TestData, planSku string) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +%s + +resource "azurerm_virtual_network" "test" { + name = "vnet-%d" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_subnet" "test1" { + name = "subnet1" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.1.0/24"] + + delegation { + name = "delegation" + + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_subnet" "test2" { + name = "subnet2" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.2.0/24"] + + delegation { + name = "delegation" + + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_linux_function_app" "test" { + name = "acctest-LFA-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + service_plan_id = azurerm_service_plan.test.id + + storage_account_name = azurerm_storage_account.test.name + storage_account_access_key = azurerm_storage_account.test.primary_access_key + + site_config {} + +} + + +`, r.template(data, planSku), data.RandomInteger, data.RandomInteger) +} + +func (r LinuxFunctionAppResource) vNetIntegration_subnet1(data acceptance.TestData, planSku string) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +%s + +resource "azurerm_virtual_network" "test" { + name = "vnet-%d" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_subnet" "test1" { + name = "subnet1" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.1.0/24"] + + delegation { + name = "delegation" + + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_subnet" "test2" { + name = "subnet2" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.2.0/24"] + + delegation { + name = "delegation" + + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_linux_function_app" "test" { + name = "acctest-LFA-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + service_plan_id = azurerm_service_plan.test.id + virtual_network_subnet_id = azurerm_subnet.test1.id + + storage_account_name = azurerm_storage_account.test.name + storage_account_access_key = azurerm_storage_account.test.primary_access_key + + site_config {} + +} +`, r.template(data, planSku), data.RandomInteger, data.RandomInteger) +} + +func (r LinuxFunctionAppResource) vNetIntegration_subnet2(data acceptance.TestData, planSku string) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +%s + +resource "azurerm_virtual_network" "test" { + name = "vnet-%d" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_subnet" "test1" { + name = "subnet1" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.1.0/24"] + + delegation { + name = "delegation" + + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_subnet" "test2" { + name = "subnet2" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.2.0/24"] + + delegation { + name = "delegation" + + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_linux_function_app" "test" { + name = "acctest-LFA-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + service_plan_id = azurerm_service_plan.test.id + virtual_network_subnet_id = azurerm_subnet.test2.id + + storage_account_name = azurerm_storage_account.test.name + storage_account_access_key = azurerm_storage_account.test.primary_access_key + + site_config {} + +} +`, r.template(data, planSku), data.RandomInteger, data.RandomInteger) +} + +func (r LinuxFunctionAppResource) withASEV3(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_storage_account" "test" { + name = "acctestsa%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + account_tier = "Standard" + account_replication_type = "LRS" +} + +resource "azurerm_linux_function_app" "test" { + name = "acctest-LFA-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + service_plan_id = azurerm_service_plan.test.id + + storage_account_name = azurerm_storage_account.test.name + storage_account_access_key = azurerm_storage_account.test.primary_access_key + + site_config { + vnet_route_all_enabled = true + } +} + +`, ServicePlanResource{}.aseV3Linux(data), data.RandomString, data.RandomInteger) +} diff --git a/internal/services/appservice/linux_function_app_slot_resource.go b/internal/services/appservice/linux_function_app_slot_resource.go index 6924a4338781..4920f56de734 100644 --- a/internal/services/appservice/linux_function_app_slot_resource.go +++ b/internal/services/appservice/linux_function_app_slot_resource.go @@ -16,6 +16,7 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/internal/services/appservice/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/appservice/validate" kvValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/keyvault/validate" + networkValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/validate" storageValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/storage/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" @@ -47,6 +48,7 @@ type LinuxFunctionAppSlotModel struct { KeyVaultReferenceIdentityID string `tfschema:"key_vault_reference_identity_id"` SiteConfig []helpers.SiteConfigLinuxFunctionAppSlot `tfschema:"site_config"` Tags map[string]string `tfschema:"tags"` + VirtualNetworkSubnetID string `tfschema:"virtual_network_subnet_id"` CustomDomainVerificationId string `tfschema:"custom_domain_verification_id"` DefaultHostname string `tfschema:"default_hostname"` Kind string `tfschema:"kind"` @@ -224,6 +226,12 @@ func (r LinuxFunctionAppSlotResource) Arguments() map[string]*pluginsdk.Schema { "site_config": helpers.SiteConfigSchemaLinuxFunctionAppSlot(), "tags": tags.Schema(), + + "virtual_network_subnet_id": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: networkValidate.SubnetID, + }, } } @@ -317,22 +325,12 @@ func (r LinuxFunctionAppSlotResource) Create() sdk.ResourceFunc { return fmt.Errorf("reading %s: %+v", servicePlanId, err) } - sendContentSettings := !functionAppSlot.ForceDisableContentShare - if planSku := servicePlan.Sku; planSku != nil && planSku.Tier != nil { - switch tier := *planSku.Tier; strings.ToLower(tier) { - case "dynamic": // Consumption Plan modifications to request - sendContentSettings = false - case "elastic": // ElasticPremium Plan modifications to request? - case "basic": // App Service Plan modifications to request? - sendContentSettings = false - case "standard": - sendContentSettings = false - case "premiumv2", "premiumv3": - sendContentSettings = false - } - } else { - return fmt.Errorf("determining plan type for Linux %s: %v", id, err) + var planSKU *string + if sku := servicePlan.Sku; sku != nil && sku.Name != nil { + planSKU = sku.Name } + // Only send for ElasticPremium + sendContentSettings := helpers.PlanIsElastic(planSKU) && !functionAppSlot.ForceDisableContentShare existing, err := client.GetSlot(ctx, id.ResourceGroup, id.SiteName, id.SlotName) if err != nil && !utils.ResponseWasNotFound(existing.Response) { @@ -408,12 +406,18 @@ func (r LinuxFunctionAppSlotResource) Create() sdk.ResourceFunc { if functionAppSlot.AppSettings == nil { functionAppSlot.AppSettings = make(map[string]string) } - suffix := uuid.New().String()[0:4] - if _, present := functionAppSlot.AppSettings["WEBSITE_CONTENTSHARE"]; !present { - functionAppSlot.AppSettings["WEBSITE_CONTENTSHARE"] = fmt.Sprintf("%s-%s", strings.ToLower(functionAppSlot.Name), suffix) - } - if _, present := functionAppSlot.AppSettings["WEBSITE_CONTENTAZUREFILECONNECTIONSTRING"]; !present { - functionAppSlot.AppSettings["WEBSITE_CONTENTAZUREFILECONNECTIONSTRING"] = storageString + if !functionAppSlot.StorageUsesMSI { + suffix := uuid.New().String()[0:4] + if _, present := functionAppSlot.AppSettings["WEBSITE_CONTENTSHARE"]; !present { + functionAppSlot.AppSettings["WEBSITE_CONTENTSHARE"] = fmt.Sprintf("%s-%s", strings.ToLower(functionAppSlot.Name), suffix) + } + if _, present := functionAppSlot.AppSettings["WEBSITE_CONTENTAZUREFILECONNECTIONSTRING"]; !present { + functionAppSlot.AppSettings["WEBSITE_CONTENTAZUREFILECONNECTIONSTRING"] = storageString + } + } else { + if _, present := functionAppSlot.AppSettings["AzureWebJobsStorage__accountName"]; !present { + functionAppSlot.AppSettings["AzureWebJobsStorage__accountName"] = storageString + } } } @@ -445,6 +449,10 @@ func (r LinuxFunctionAppSlotResource) Create() sdk.ResourceFunc { siteEnvelope.SiteProperties.KeyVaultReferenceIdentity = utils.String(functionAppSlot.KeyVaultReferenceIdentityID) } + if functionAppSlot.VirtualNetworkSubnetID != "" { + siteEnvelope.SiteProperties.VirtualNetworkSubnetID = utils.String(functionAppSlot.VirtualNetworkSubnetID) + } + future, err := client.CreateOrUpdateSlot(ctx, id.ResourceGroup, id.SiteName, siteEnvelope, id.SlotName) if err != nil { return fmt.Errorf("creating Linux %s: %+v", id, err) @@ -597,6 +605,10 @@ func (r LinuxFunctionAppSlotResource) Read() sdk.ResourceFunc { state.HttpsOnly = utils.NormaliseNilableBool(functionApp.HTTPSOnly) state.ClientCertEnabled = utils.NormaliseNilableBool(functionApp.ClientCertEnabled) + if subnetId := utils.NormalizeNilableString(props.VirtualNetworkSubnetID); subnetId != "" { + state.VirtualNetworkSubnetID = subnetId + } + if err := metadata.Encode(&state); err != nil { return fmt.Errorf("encoding: %+v", err) } @@ -662,7 +674,7 @@ func (r LinuxFunctionAppSlotResource) Update() sdk.ResourceFunc { return err } - sendContentSettings := !helpers.PlanIsElastic(planSKU) + sendContentSettings := helpers.PlanIsElastic(planSKU) && !state.ForceDisableContentShare if metadata.ResourceData.HasChange("enabled") { existing.SiteProperties.Enabled = utils.Bool(state.Enabled) @@ -696,6 +708,19 @@ func (r LinuxFunctionAppSlotResource) Update() sdk.ResourceFunc { existing.Tags = tags.FromTypedObject(state.Tags) } + if metadata.ResourceData.HasChange("virtual_network_subnet_id") { + subnetId := metadata.ResourceData.Get("virtual_network_subnet_id").(string) + if subnetId == "" { + if _, err := client.DeleteSwiftVirtualNetworkSlot(ctx, id.ResourceGroup, id.SiteName, id.SlotName); err != nil { + return fmt.Errorf("removing `virtual_network_subnet_id` association for %s: %+v", *id, err) + } + var empty *string + existing.SiteProperties.VirtualNetworkSubnetID = empty + } else { + existing.SiteProperties.VirtualNetworkSubnetID = utils.String(subnetId) + } + } + storageString := state.StorageAccountName if !state.StorageUsesMSI { if state.StorageKeyVaultSecretID != "" { diff --git a/internal/services/appservice/linux_function_app_slot_resource_test.go b/internal/services/appservice/linux_function_app_slot_resource_test.go index 3c0d36d44b8f..4b2e56b6b118 100644 --- a/internal/services/appservice/linux_function_app_slot_resource_test.go +++ b/internal/services/appservice/linux_function_app_slot_resource_test.go @@ -715,6 +715,7 @@ func TestAccLinuxFunctionAppSlot_appStackNodeUpdate(t *testing.T) { Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), check.That(data.ResourceName).Key("kind").HasValue("functionapp,linux"), + check.That(data.ResourceName).Key("site_config.0.linux_fx_version").HasValue("NODE|12"), ), }, data.ImportStep(), @@ -723,6 +724,25 @@ func TestAccLinuxFunctionAppSlot_appStackNodeUpdate(t *testing.T) { Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), check.That(data.ResourceName).Key("kind").HasValue("functionapp,linux"), + check.That(data.ResourceName).Key("site_config.0.linux_fx_version").HasValue("NODE|14"), + ), + }, + data.ImportStep(), + { + Config: r.appStackNode(data, SkuStandardPlan, "16"), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("kind").HasValue("functionapp,linux"), + check.That(data.ResourceName).Key("site_config.0.linux_fx_version").HasValue("NODE|16"), + ), + }, + data.ImportStep(), + { + Config: r.appStackNodeUpdateTags(data, SkuStandardPlan, "16"), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("kind").HasValue("functionapp,linux"), + check.That(data.ResourceName).Key("site_config.0.linux_fx_version").HasValue("NODE|16"), ), }, data.ImportStep(), @@ -893,7 +913,23 @@ func TestAccLinuxFunctionAppSlot_identityKeyVaultIdentity(t *testing.T) { }) } -func TestAccLinuxFunctionAppSlot_msiStorageAccount(t *testing.T) { +func TestAccLinuxFunctionAppSlot_msiStorageAccountElastic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_linux_function_app_slot", "test") + r := LinuxFunctionAppSlotResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.msiStorageAccount(data, SkuElasticPremiumPlan), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("kind").HasValue("functionapp,linux"), + ), + }, + data.ImportStep(), + }) +} + +func TestAccLinuxFunctionAppSlot_msiStorageAccountStandard(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_linux_function_app_slot", "test") r := LinuxFunctionAppSlotResource{} @@ -941,6 +977,81 @@ func TestAccLinuxFunctionAppSlot_storageAccountKeyVaultSecretVersionless(t *test }) } +func TestAccLinuxFunctionAppSlot_vNetIntegration(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_linux_function_app_slot", "test") + r := LinuxFunctionAppSlotResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.vNetIntegration_subnet1(data, SkuStandardPlan), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("virtual_network_subnet_id").MatchesOtherKey( + check.That("azurerm_subnet.test1").Key("id"), + ), + ), + }, + data.ImportStep(), + }) +} + +func TestAccLinuxFunctionAppSlot_vNetIntegrationUpdate(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_linux_function_app_slot", "test") + r := LinuxFunctionAppSlotResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.vNetIntegration_basic(data, SkuStandardPlan), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.vNetIntegration_subnet1(data, SkuStandardPlan), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("virtual_network_subnet_id").MatchesOtherKey( + check.That("azurerm_subnet.test1").Key("id"), + ), + ), + }, + data.ImportStep(), + { + Config: r.vNetIntegration_subnet2(data, SkuStandardPlan), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("virtual_network_subnet_id").MatchesOtherKey( + check.That("azurerm_subnet.test2").Key("id"), + ), + ), + }, + data.ImportStep(), + { + Config: r.vNetIntegration_basic(data, SkuStandardPlan), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccLinuxFunctionAppSlotASEv3_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_linux_function_app_slot", "test") + r := LinuxFunctionAppSlotResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.withASEV3(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + // Configs func (r LinuxFunctionAppSlotResource) Exists(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { @@ -1423,6 +1534,33 @@ resource "azurerm_linux_function_app_slot" "test" { `, r.template(data, planSku), data.RandomInteger, nodeVersion) } +func (r LinuxFunctionAppSlotResource) appStackNodeUpdateTags(data acceptance.TestData, planSku string, nodeVersion string) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +%s + +resource "azurerm_linux_function_app_slot" "test" { + name = "acctest-LFAS-%d" + function_app_id = azurerm_linux_function_app.test.id + storage_account_name = azurerm_storage_account.test.name + storage_account_access_key = azurerm_storage_account.test.primary_access_key + + site_config { + application_stack { + node_version = "%s" + } + } + + tags = { + foo = "bar" + } +} +`, r.template(data, planSku), data.RandomInteger, nodeVersion) +} + func (r LinuxFunctionAppSlotResource) appStackDocker(data acceptance.TestData, planSku string) string { return fmt.Sprintf(` provider "azurerm" { @@ -2214,7 +2352,11 @@ resource "azurerm_linux_function_app_slot" "test" { type = "SystemAssigned" } - site_config {} + site_config { + application_stack { + python_version = "3.9" + } + } } `, r.template(data, planSku), data.RandomInteger) } @@ -2521,3 +2663,220 @@ resource "azurerm_user_assigned_identity" "test" { } `, r.template(data, planSku), data.RandomInteger) } + +func (r LinuxFunctionAppSlotResource) vNetIntegration_basic(data acceptance.TestData, planSku string) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +%s + +resource "azurerm_virtual_network" "test" { + name = "vnet-%d" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_subnet" "test1" { + name = "subnet1" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.1.0/24"] + + delegation { + name = "delegation" + + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_subnet" "test2" { + name = "subnet2" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.2.0/24"] + + delegation { + name = "delegation" + + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_linux_function_app_slot" "test" { + name = "acctest-LFAS-%d" + function_app_id = azurerm_linux_function_app.test.id + storage_account_name = azurerm_storage_account.test.name + storage_account_access_key = azurerm_storage_account.test.primary_access_key + + site_config {} +} + +`, r.template(data, planSku), data.RandomInteger, data.RandomInteger) +} + +func (r LinuxFunctionAppSlotResource) vNetIntegration_subnet1(data acceptance.TestData, planSku string) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +%s + +resource "azurerm_virtual_network" "test" { + name = "vnet-%d" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_subnet" "test1" { + name = "subnet1" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.1.0/24"] + + delegation { + name = "delegation" + + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_subnet" "test2" { + name = "subnet2" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.2.0/24"] + + delegation { + name = "delegation" + + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_linux_function_app_slot" "test" { + name = "acctest-LFAS-%d" + function_app_id = azurerm_linux_function_app.test.id + storage_account_name = azurerm_storage_account.test.name + storage_account_access_key = azurerm_storage_account.test.primary_access_key + virtual_network_subnet_id = azurerm_subnet.test1.id + + site_config {} +} +`, r.template(data, planSku), data.RandomInteger, data.RandomInteger) +} + +func (r LinuxFunctionAppSlotResource) vNetIntegration_subnet2(data acceptance.TestData, planSku string) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +%s + +resource "azurerm_virtual_network" "test" { + name = "vnet-%d" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_subnet" "test1" { + name = "subnet1" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.1.0/24"] + + delegation { + name = "delegation" + + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_subnet" "test2" { + name = "subnet2" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.2.0/24"] + + delegation { + name = "delegation" + + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_linux_function_app_slot" "test" { + name = "acctest-LFAS-%d" + function_app_id = azurerm_linux_function_app.test.id + storage_account_name = azurerm_storage_account.test.name + storage_account_access_key = azurerm_storage_account.test.primary_access_key + virtual_network_subnet_id = azurerm_subnet.test2.id + + site_config {} +} +`, r.template(data, planSku), data.RandomInteger, data.RandomInteger) +} + +func (r LinuxFunctionAppSlotResource) withASEV3(data acceptance.TestData) string { + return fmt.Sprintf(` +%[1]s + +resource "azurerm_storage_account" "test" { + name = "acctestsa%[2]s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + account_tier = "Standard" + account_replication_type = "LRS" +} + +resource "azurerm_linux_function_app" "test" { + name = "acctest-LFA-%[3]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + service_plan_id = azurerm_service_plan.test.id + + storage_account_name = azurerm_storage_account.test.name + storage_account_access_key = azurerm_storage_account.test.primary_access_key + + site_config { + vnet_route_all_enabled = true + } +} + +resource "azurerm_linux_function_app_slot" "test" { + name = "acctest-LFAS-%[3]d" + function_app_id = azurerm_linux_function_app.test.id + storage_account_name = azurerm_storage_account.test.name + storage_account_access_key = azurerm_storage_account.test.primary_access_key + + site_config { + vnet_route_all_enabled = true + } +} + +`, ServicePlanResource{}.aseV3Linux(data), data.RandomString, data.RandomInteger) +} diff --git a/internal/services/appservice/linux_web_app_resource.go b/internal/services/appservice/linux_web_app_resource.go index f6f1917396d8..99a4c7d911b8 100644 --- a/internal/services/appservice/linux_web_app_resource.go +++ b/internal/services/appservice/linux_web_app_resource.go @@ -16,6 +16,7 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/internal/services/appservice/helpers" "github.com/hashicorp/terraform-provider-azurerm/internal/services/appservice/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/appservice/validate" + networkValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" @@ -130,9 +131,9 @@ func (r LinuxWebAppResource) Arguments() map[string]*pluginsdk.Schema { }, "virtual_network_subnet_id": { - Type: pluginsdk.TypeString, - Optional: true, - ForceNew: true, + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: networkValidate.SubnetID, }, "identity": commonschema.SystemAssignedUserAssignedIdentityOptional(), @@ -501,11 +502,14 @@ func (r LinuxWebAppResource) Read() sdk.ResourceFunc { KeyVaultReferenceIdentityID: utils.NormalizeNilableString(props.KeyVaultReferenceIdentity), Enabled: utils.NormaliseNilableBool(props.Enabled), HttpsOnly: utils.NormaliseNilableBool(props.HTTPSOnly), - VirtualNetworkSubnetID: utils.NormalizeNilableString(webApp.VirtualNetworkSubnetID), StickySettings: helpers.FlattenStickySettings(stickySettings.SlotConfigNames), Tags: tags.ToTypedObject(webApp.Tags), } + if subnetId := utils.NormalizeNilableString(props.VirtualNetworkSubnetID); subnetId != "" { + state.VirtualNetworkSubnetID = subnetId + } + var healthCheckCount *int state.AppSettings, healthCheckCount = helpers.FlattenAppSettings(appSettings) @@ -665,6 +669,19 @@ func (r LinuxWebAppResource) Update() sdk.ResourceFunc { existing.SiteConfig = siteConfig } + if metadata.ResourceData.HasChange("virtual_network_subnet_id") { + subnetId := metadata.ResourceData.Get("virtual_network_subnet_id").(string) + if subnetId == "" { + if _, err := client.DeleteSwiftVirtualNetwork(ctx, id.ResourceGroup, id.SiteName); err != nil { + return fmt.Errorf("removing `virtual_network_subnet_id` association for %s: %+v", *id, err) + } + var empty *string + existing.SiteProperties.VirtualNetworkSubnetID = empty + } else { + existing.SiteProperties.VirtualNetworkSubnetID = utils.String(subnetId) + } + } + updateFuture, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.SiteName, existing) if err != nil { return fmt.Errorf("updating Linux %s: %+v", id, err) diff --git a/internal/services/appservice/linux_web_app_resource_test.go b/internal/services/appservice/linux_web_app_resource_test.go index a276dfd801a2..64e7d94c5e79 100644 --- a/internal/services/appservice/linux_web_app_resource_test.go +++ b/internal/services/appservice/linux_web_app_resource_test.go @@ -1122,9 +1122,12 @@ func TestAccLinuxWebApp_vNetIntegration(t *testing.T) { data.ResourceTest(t, r, []acceptance.TestStep{ { - Config: r.vNetIntegrationWebApp_withSubnetId(data), + Config: r.vNetIntegrationWebApp_subnet1(data), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("virtual_network_subnet_id").MatchesOtherKey( + check.That("azurerm_subnet.test1").Key("id"), + ), ), }, data.ImportStep(), @@ -1144,9 +1147,22 @@ func TestAccLinuxWebApp_vNetIntegrationUpdate(t *testing.T) { }, data.ImportStep(), { - Config: r.vNetIntegrationWebApp_withSubnetId(data), + Config: r.vNetIntegrationWebApp_subnet1(data), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("virtual_network_subnet_id").MatchesOtherKey( + check.That("azurerm_subnet.test1").Key("id"), + ), + ), + }, + data.ImportStep(), + { + Config: r.vNetIntegrationWebApp_subnet2(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("virtual_network_subnet_id").MatchesOtherKey( + check.That("azurerm_subnet.test2").Key("id"), + ), ), }, data.ImportStep(), @@ -2913,8 +2929,8 @@ resource "azurerm_virtual_network" "test" { resource_group_name = azurerm_resource_group.test.name } -resource "azurerm_subnet" "test" { - name = "subnet" +resource "azurerm_subnet" "test1" { + name = "subnet1" resource_group_name = azurerm_resource_group.test.name virtual_network_name = azurerm_virtual_network.test.name address_prefixes = ["10.0.1.0/24"] @@ -2929,6 +2945,22 @@ resource "azurerm_subnet" "test" { } } +resource "azurerm_subnet" "test2" { + name = "subnet2" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.2.0/24"] + + delegation { + name = "delegation" + + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + resource "azurerm_linux_web_app" "test" { name = "acctestWA-%d" location = azurerm_resource_group.test.location @@ -2940,7 +2972,66 @@ resource "azurerm_linux_web_app" "test" { `, r.baseTemplate(data), data.RandomInteger, data.RandomInteger) } -func (r LinuxWebAppResource) vNetIntegrationWebApp_withSubnetId(data acceptance.TestData) string { +func (r LinuxWebAppResource) vNetIntegrationWebApp_subnet1(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +%s + +resource "azurerm_virtual_network" "test" { + name = "vnet-%d" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_subnet" "test1" { + name = "subnet1" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.1.0/24"] + + delegation { + name = "delegation" + + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_subnet" "test2" { + name = "subnet2" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.2.0/24"] + + delegation { + name = "delegation" + + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_linux_web_app" "test" { + name = "acctestWA-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + service_plan_id = azurerm_service_plan.test.id + virtual_network_subnet_id = azurerm_subnet.test1.id + + site_config {} +} +`, r.baseTemplate(data), data.RandomInteger, data.RandomInteger) +} + +func (r LinuxWebAppResource) vNetIntegrationWebApp_subnet2(data acceptance.TestData) string { return fmt.Sprintf(` provider "azurerm" { features {} @@ -2955,8 +3046,8 @@ resource "azurerm_virtual_network" "test" { resource_group_name = azurerm_resource_group.test.name } -resource "azurerm_subnet" "test" { - name = "subnet" +resource "azurerm_subnet" "test1" { + name = "subnet1" resource_group_name = azurerm_resource_group.test.name virtual_network_name = azurerm_virtual_network.test.name address_prefixes = ["10.0.1.0/24"] @@ -2971,12 +3062,28 @@ resource "azurerm_subnet" "test" { } } +resource "azurerm_subnet" "test2" { + name = "subnet2" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.2.0/24"] + + delegation { + name = "delegation" + + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + resource "azurerm_linux_web_app" "test" { name = "acctestWA-%d" location = azurerm_resource_group.test.location resource_group_name = azurerm_resource_group.test.name service_plan_id = azurerm_service_plan.test.id - virtual_network_subnet_id = azurerm_subnet.test.id + virtual_network_subnet_id = azurerm_subnet.test2.id site_config {} } diff --git a/internal/services/appservice/linux_web_app_slot_resource.go b/internal/services/appservice/linux_web_app_slot_resource.go index ef686bce20a2..f0d164243ef4 100644 --- a/internal/services/appservice/linux_web_app_slot_resource.go +++ b/internal/services/appservice/linux_web_app_slot_resource.go @@ -14,6 +14,7 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/internal/services/appservice/helpers" "github.com/hashicorp/terraform-provider-azurerm/internal/services/appservice/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/appservice/validate" + networkValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" @@ -132,9 +133,9 @@ func (r LinuxWebAppSlotResource) Arguments() map[string]*pluginsdk.Schema { }, "virtual_network_subnet_id": { - Type: pluginsdk.TypeString, - Optional: true, - ForceNew: true, + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: networkValidate.SubnetID, }, "identity": commonschema.SystemAssignedUserAssignedIdentityOptional(), @@ -451,7 +452,10 @@ func (r LinuxWebAppSlotResource) Read() sdk.ResourceFunc { Enabled: utils.NormaliseNilableBool(props.Enabled), HttpsOnly: utils.NormaliseNilableBool(props.HTTPSOnly), Tags: tags.ToTypedObject(webApp.Tags), - VirtualNetworkSubnetID: utils.NormalizeNilableString(webApp.VirtualNetworkSubnetID), + } + + if subnetId := utils.NormalizeNilableString(props.VirtualNetworkSubnetID); subnetId != "" { + state.VirtualNetworkSubnetID = subnetId } var healthCheckCount *int @@ -588,6 +592,19 @@ func (r LinuxWebAppSlotResource) Update() sdk.ResourceFunc { existing.SiteConfig = siteConfig } + if metadata.ResourceData.HasChange("virtual_network_subnet_id") { + subnetId := metadata.ResourceData.Get("virtual_network_subnet_id").(string) + if subnetId == "" { + if _, err := client.DeleteSwiftVirtualNetworkSlot(ctx, id.ResourceGroup, id.SiteName, id.SlotName); err != nil { + return fmt.Errorf("removing `virtual_network_subnet_id` association for %s: %+v", *id, err) + } + var empty *string + existing.SiteProperties.VirtualNetworkSubnetID = empty + } else { + existing.SiteProperties.VirtualNetworkSubnetID = utils.String(subnetId) + } + } + updateFuture, err := client.CreateOrUpdateSlot(ctx, id.ResourceGroup, id.SiteName, existing, id.SlotName) if err != nil { return fmt.Errorf("updating Linux %s: %+v", id, err) diff --git a/internal/services/appservice/linux_web_app_slot_resource_test.go b/internal/services/appservice/linux_web_app_slot_resource_test.go index 6d46b77a3da0..ae43c913cc13 100644 --- a/internal/services/appservice/linux_web_app_slot_resource_test.go +++ b/internal/services/appservice/linux_web_app_slot_resource_test.go @@ -898,10 +898,12 @@ func TestAccLinuxWebAppSlot_vNetIntegration(t *testing.T) { data.ResourceTest(t, r, []acceptance.TestStep{ { - Config: r.vNetIntegrationWebApp_withSubnetId(data), + Config: r.vNetIntegrationWebApp_subnet1(data), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), - check.That(data.ResourceName).Key("virtual_network_subnet_id").Exists(), + check.That(data.ResourceName).Key("virtual_network_subnet_id").MatchesOtherKey( + check.That("azurerm_subnet.test1").Key("id"), + ), ), }, data.ImportStep(), @@ -921,9 +923,22 @@ func TestAccLinuxWebAppSlot_vNetIntegrationUpdate(t *testing.T) { }, data.ImportStep(), { - Config: r.vNetIntegrationWebApp_withSubnetId(data), + Config: r.vNetIntegrationWebApp_subnet1(data), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("virtual_network_subnet_id").MatchesOtherKey( + check.That("azurerm_subnet.test1").Key("id"), + ), + ), + }, + data.ImportStep(), + { + Config: r.vNetIntegrationWebApp_subnet2(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("virtual_network_subnet_id").MatchesOtherKey( + check.That("azurerm_subnet.test2").Key("id"), + ), ), }, data.ImportStep(), @@ -2186,14 +2201,87 @@ resource "azurerm_virtual_network" "test" { resource_group_name = azurerm_resource_group.test.name } -resource "azurerm_subnet" "test" { - name = "subnet" +resource "azurerm_subnet" "test1" { + name = "subnet1" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.1.0/24"] + + delegation { + name = "delegation" + + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_subnet" "test2" { + name = "subnet2" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.2.0/24"] + + delegation { + name = "delegation" + + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_linux_web_app_slot" "test" { + name = "acctestWAS-%[2]d" + app_service_id = azurerm_linux_web_app.test.id + + site_config {} +} +`, r.baseTemplate(data), data.RandomInteger, data.RandomInteger) +} + +func (r LinuxWebAppSlotResource) vNetIntegrationWebApp_subnet1(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +%s + +resource "azurerm_virtual_network" "test" { + name = "vnet-%d" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_subnet" "test1" { + name = "subnet1" resource_group_name = azurerm_resource_group.test.name virtual_network_name = azurerm_virtual_network.test.name address_prefixes = ["10.0.1.0/24"] delegation { name = "delegation" + + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_subnet" "test2" { + name = "subnet2" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.2.0/24"] + + delegation { + name = "delegation" + service_delegation { name = "Microsoft.Web/serverFarms" actions = ["Microsoft.Network/virtualNetworks/subnets/action"] @@ -2204,14 +2292,14 @@ resource "azurerm_subnet" "test" { resource "azurerm_linux_web_app_slot" "test" { name = "acctestWAS-%[2]d" app_service_id = azurerm_linux_web_app.test.id - virtual_network_subnet_id = azurerm_subnet.test.id + virtual_network_subnet_id = azurerm_subnet.test1.id site_config {} } `, r.baseTemplate(data), data.RandomInteger, data.RandomInteger) } -func (r LinuxWebAppSlotResource) vNetIntegrationWebApp_withSubnetId(data acceptance.TestData) string { +func (r LinuxWebAppSlotResource) vNetIntegrationWebApp_subnet2(data acceptance.TestData) string { return fmt.Sprintf(` provider "azurerm" { features {} @@ -2226,8 +2314,8 @@ resource "azurerm_virtual_network" "test" { resource_group_name = azurerm_resource_group.test.name } -resource "azurerm_subnet" "test" { - name = "subnet" +resource "azurerm_subnet" "test1" { + name = "subnet1" resource_group_name = azurerm_resource_group.test.name virtual_network_name = azurerm_virtual_network.test.name address_prefixes = ["10.0.1.0/24"] @@ -2242,10 +2330,26 @@ resource "azurerm_subnet" "test" { } } +resource "azurerm_subnet" "test2" { + name = "subnet2" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.2.0/24"] + + delegation { + name = "delegation" + + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + resource "azurerm_linux_web_app_slot" "test" { name = "acctestWAS-%[2]d" app_service_id = azurerm_linux_web_app.test.id - virtual_network_subnet_id = azurerm_subnet.test.id + virtual_network_subnet_id = azurerm_subnet.test2.id site_config {} } diff --git a/internal/services/appservice/service_plan_resource_test.go b/internal/services/appservice/service_plan_resource_test.go index 76b5bff434b0..f8e828986a77 100644 --- a/internal/services/appservice/service_plan_resource_test.go +++ b/internal/services/appservice/service_plan_resource_test.go @@ -441,3 +441,64 @@ resource "azurerm_service_plan" "test" { } `, data.RandomInteger, data.Locations.Primary) } + +func (r ServicePlanResource) aseV3Linux(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-appserviceplan-%[1]d" + location = "%[2]s" +} + +resource "azurerm_resource_group" "test2" { + name = "acctestRG2-ase-%[1]d" + location = "%[2]s" +} + + +resource "azurerm_virtual_network" "test" { + name = "acctest-vnet-%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + address_space = ["10.0.0.0/16"] +} + +resource "azurerm_subnet" "test" { + name = "acctest-subnet-%[1]d" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.2.0/24"] + delegation { + name = "asedelegation" + service_delegation { + name = "Microsoft.Web/hostingEnvironments" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_app_service_environment_v3" "test" { + name = "acctest-ase-%[1]d" + resource_group_name = azurerm_resource_group.test.name + subnet_id = azurerm_subnet.test.id +} + +resource "azurerm_service_plan" "test" { + name = "acctest-SP-%[1]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + os_type = "Linux" + sku_name = "I1v2" + + app_service_environment_id = azurerm_app_service_environment_v3.test.id + + tags = { + environment = "AccTest" + Foo = "bar" + } +} +`, data.RandomInteger, data.Locations.Primary) +} diff --git a/internal/services/appservice/validate/web_app_name_test.go b/internal/services/appservice/validate/web_app_name_test.go new file mode 100644 index 000000000000..1273d241c86b --- /dev/null +++ b/internal/services/appservice/validate/web_app_name_test.go @@ -0,0 +1,50 @@ +package validate_test + +import ( + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/services/appservice/validate" +) + +func TestWebAppName(t *testing.T) { + cases := []struct { + Input string + Valid bool + }{ + { + Input: "", + Valid: false, + }, + { + Input: "a", + Valid: true, + }, + { + Input: "-valid", + Valid: true, + }, + { + // len is 35 + Input: "ThisIsALongAndValidNameThatWillWork", + Valid: true, + }, + { + Input: "ThisNameIsTooLongThisNameIsTooLongThisNameIsTooLongThisNameIsTooLongThisNameIsTooLongThisNameIsTooLongThisNameIsTooLongThisNameIsTooLong", + Valid: false, + }, + { + // len is 60 and should show the warning message + Input: "012345678901234567890123456789012345678901234567890123456789", + Valid: true, + }, + } + + for _, tc := range cases { + _, errs := validate.WebAppName(tc.Input, "test") + valid := len(errs) == 0 + + if valid != tc.Valid { + t.Fatalf("expected %s to be %t, got %t", tc.Input, tc.Valid, valid) + } + } +} diff --git a/internal/services/appservice/windows_function_app_data_source.go b/internal/services/appservice/windows_function_app_data_source.go index b82be7e16eef..88eaf7125e64 100644 --- a/internal/services/appservice/windows_function_app_data_source.go +++ b/internal/services/appservice/windows_function_app_data_source.go @@ -47,6 +47,7 @@ type WindowsFunctionAppDataSourceModel struct { SiteConfig []helpers.SiteConfigWindowsFunctionApp `tfschema:"site_config"` StickySettings []helpers.StickySettings `tfschema:"sticky_settings"` Tags map[string]string `tfschema:"tags"` + VirtualNetworkSubnetId string `tfschema:"virtual_network_subnet_id"` CustomDomainVerificationId string `tfschema:"custom_domain_verification_id"` DefaultHostname string `tfschema:"default_hostname"` @@ -216,6 +217,11 @@ func (d WindowsFunctionAppDataSource) Attributes() map[string]*pluginsdk.Schema "identity": commonschema.SystemAssignedUserAssignedIdentityComputed(), "tags": tags.SchemaDataSource(), + + "virtual_network_subnet_id": { + Type: pluginsdk.TypeString, + Computed: true, + }, } } @@ -257,6 +263,17 @@ func (d WindowsFunctionAppDataSource) Read() sdk.ResourceFunc { functionApp.Kind = utils.NormalizeNilableString(existing.Kind) functionApp.CustomDomainVerificationId = utils.NormalizeNilableString(props.CustomDomainVerificationID) functionApp.DefaultHostname = utils.NormalizeNilableString(props.DefaultHostName) + functionApp.VirtualNetworkSubnetId = utils.NormalizeNilableString(props.VirtualNetworkSubnetID) + + if v := props.OutboundIPAddresses; v != nil { + functionApp.OutboundIPAddresses = *v + functionApp.OutboundIPAddressList = strings.Split(*v, ",") + } + + if v := props.PossibleOutboundIPAddresses; v != nil { + functionApp.PossibleOutboundIPAddresses = *v + functionApp.PossibleOutboundIPAddressList = strings.Split(*v, ",") + } appSettingsResp, err := client.ListApplicationSettings(ctx, id.ResourceGroup, id.SiteName) if err != nil { diff --git a/internal/services/appservice/windows_function_app_data_source_test.go b/internal/services/appservice/windows_function_app_data_source_test.go index b8ab54af0115..c14b492143a8 100644 --- a/internal/services/appservice/windows_function_app_data_source_test.go +++ b/internal/services/appservice/windows_function_app_data_source_test.go @@ -2,6 +2,7 @@ package appservice_test import ( "fmt" + "regexp" "testing" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" @@ -14,11 +15,17 @@ func TestAccWindowsFunctionAppDataSource_complete(t *testing.T) { data := acceptance.BuildTestData(t, "data.azurerm_windows_function_app", "test") d := WindowsFunctionAppDataSource{} + ipListRegex := regexp.MustCompile(`(([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})(,){0,1})+`) + data.DataSourceTest(t, []acceptance.TestStep{ { Config: d.complete(data), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).Key("location").HasValue(data.Locations.Primary), + check.That(data.ResourceName).Key("outbound_ip_addresses").MatchesRegex(ipListRegex), + check.That(data.ResourceName).Key("outbound_ip_address_list.#").Exists(), + check.That(data.ResourceName).Key("possible_outbound_ip_addresses").MatchesRegex(ipListRegex), + check.That(data.ResourceName).Key("possible_outbound_ip_address_list.#").Exists(), check.That(data.ResourceName).Key("default_hostname").HasValue(fmt.Sprintf("acctest-wfa-%d.azurewebsites.net", data.RandomInteger)), ), }, diff --git a/internal/services/appservice/windows_function_app_resource.go b/internal/services/appservice/windows_function_app_resource.go index cfd3422eca33..246ce171bde1 100644 --- a/internal/services/appservice/windows_function_app_resource.go +++ b/internal/services/appservice/windows_function_app_resource.go @@ -18,6 +18,7 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/internal/services/appservice/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/appservice/validate" kvValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/keyvault/validate" + networkValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/validate" storageValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/storage/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" @@ -54,6 +55,7 @@ type WindowsFunctionAppModel struct { KeyVaultReferenceIdentityID string `tfschema:"key_vault_reference_identity_id"` SiteConfig []helpers.SiteConfigWindowsFunctionApp `tfschema:"site_config"` Tags map[string]string `tfschema:"tags"` + VirtualNetworkSubnetID string `tfschema:"virtual_network_subnet_id"` // Computed CustomDomainVerificationId string `tfschema:"custom_domain_verification_id"` @@ -243,6 +245,12 @@ func (r WindowsFunctionAppResource) Arguments() map[string]*pluginsdk.Schema { "sticky_settings": helpers.StickySettingsSchema(), "tags": tags.Schema(), + + "virtual_network_subnet_id": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: networkValidate.SubnetID, + }, } } @@ -321,21 +329,12 @@ func (r WindowsFunctionAppResource) Create() sdk.ResourceFunc { return fmt.Errorf("reading %s: %+v", servicePlanId, err) } - sendContentSettings := !functionApp.ForceDisableContentShare - if planSku := servicePlan.Sku; planSku != nil && planSku.Tier != nil { - switch tier := *planSku.Tier; strings.ToLower(tier) { - case "dynamic": - case "elastic": - case "basic": - sendContentSettings = false - case "standard": - sendContentSettings = false - case "premiumv2", "premiumv3": - sendContentSettings = false - } - } else { - return fmt.Errorf("determining plan type for Windows %s: %v", id, err) + var planSKU *string + if sku := servicePlan.Sku; sku != nil && sku.Name != nil { + planSKU = sku.Name } + // Only send for Dynamic and ElasticPremium + sendContentSettings := (helpers.PlanIsConsumption(planSKU) || helpers.PlanIsElastic(planSKU)) && !functionApp.ForceDisableContentShare existing, err := client.Get(ctx, id.ResourceGroup, id.SiteName) if err != nil && !utils.ResponseWasNotFound(existing.Response) { @@ -411,12 +410,18 @@ func (r WindowsFunctionAppResource) Create() sdk.ResourceFunc { if functionApp.AppSettings == nil { functionApp.AppSettings = make(map[string]string) } - suffix := uuid.New().String()[0:4] - if _, present := functionApp.AppSettings["WEBSITE_CONTENTSHARE"]; !present { - functionApp.AppSettings["WEBSITE_CONTENTSHARE"] = fmt.Sprintf("%s-%s", strings.ToLower(functionApp.Name), suffix) - } - if _, present := functionApp.AppSettings["WEBSITE_CONTENTAZUREFILECONNECTIONSTRING"]; !present { - functionApp.AppSettings["WEBSITE_CONTENTAZUREFILECONNECTIONSTRING"] = storageString + if !functionApp.StorageUsesMSI { + suffix := uuid.New().String()[0:4] + if _, present := functionApp.AppSettings["WEBSITE_CONTENTSHARE"]; !present { + functionApp.AppSettings["WEBSITE_CONTENTSHARE"] = fmt.Sprintf("%s-%s", strings.ToLower(functionApp.Name), suffix) + } + if _, present := functionApp.AppSettings["WEBSITE_CONTENTAZUREFILECONNECTIONSTRING"]; !present { + functionApp.AppSettings["WEBSITE_CONTENTAZUREFILECONNECTIONSTRING"] = storageString + } + } else { + if _, present := functionApp.AppSettings["AzureWebJobsStorage__accountName"]; !present { + functionApp.AppSettings["AzureWebJobsStorage__accountName"] = storageString + } } } @@ -444,6 +449,10 @@ func (r WindowsFunctionAppResource) Create() sdk.ResourceFunc { }, } + if functionApp.VirtualNetworkSubnetID != "" { + siteEnvelope.SiteProperties.VirtualNetworkSubnetID = utils.String(functionApp.VirtualNetworkSubnetID) + } + if functionApp.KeyVaultReferenceIdentityID != "" { siteEnvelope.SiteProperties.KeyVaultReferenceIdentity = utils.String(functionApp.KeyVaultReferenceIdentityID) } @@ -593,6 +602,16 @@ func (r WindowsFunctionAppResource) Read() sdk.ResourceFunc { DefaultHostname: utils.NormalizeNilableString(props.DefaultHostName), } + if v := props.OutboundIPAddresses; v != nil { + state.OutboundIPAddresses = *v + state.OutboundIPAddressList = strings.Split(*v, ",") + } + + if v := props.PossibleOutboundIPAddresses; v != nil { + state.PossibleOutboundIPAddresses = *v + state.PossibleOutboundIPAddressList = strings.Split(*v, ",") + } + configResp, err := client.GetConfiguration(ctx, id.ResourceGroup, id.SiteName) if err != nil { return fmt.Errorf("making Read request on AzureRM Function App Configuration %q: %+v", id.SiteName, err) @@ -619,6 +638,10 @@ func (r WindowsFunctionAppResource) Read() sdk.ResourceFunc { state.HttpsOnly = utils.NormaliseNilableBool(functionApp.HTTPSOnly) state.ClientCertEnabled = utils.NormaliseNilableBool(functionApp.ClientCertEnabled) + if subnetId := utils.NormalizeNilableString(functionApp.VirtualNetworkSubnetID); subnetId != "" { + state.VirtualNetworkSubnetID = subnetId + } + if err := metadata.Encode(&state); err != nil { return fmt.Errorf("encoding: %+v", err) } @@ -683,7 +706,9 @@ func (r WindowsFunctionAppResource) Update() sdk.ResourceFunc { if err != nil { return err } - sendContentSettings := !helpers.PlanIsAppPlan(planSKU) + + // Only send for Dynamic and ElasticPremium + sendContentSettings := (helpers.PlanIsConsumption(planSKU) || helpers.PlanIsElastic(planSKU)) && !state.ForceDisableContentShare // Some service plan updates are allowed - see customiseDiff for exceptions if metadata.ResourceData.HasChange("service_plan_id") { @@ -722,6 +747,19 @@ func (r WindowsFunctionAppResource) Update() sdk.ResourceFunc { existing.Tags = tags.FromTypedObject(state.Tags) } + if metadata.ResourceData.HasChange("virtual_network_subnet_id") { + subnetId := metadata.ResourceData.Get("virtual_network_subnet_id").(string) + if subnetId == "" { + if _, err := client.DeleteSwiftVirtualNetwork(ctx, id.ResourceGroup, id.SiteName); err != nil { + return fmt.Errorf("removing `virtual_network_subnet_id` association for %s: %+v", *id, err) + } + var empty *string + existing.SiteProperties.VirtualNetworkSubnetID = empty + } else { + existing.SiteProperties.VirtualNetworkSubnetID = utils.String(subnetId) + } + } + storageString := state.StorageAccountName if !state.StorageUsesMSI { if state.StorageKeyVaultSecretID != "" { diff --git a/internal/services/appservice/windows_function_app_resource_test.go b/internal/services/appservice/windows_function_app_resource_test.go index 1bc62718b313..25729c5ea3ff 100644 --- a/internal/services/appservice/windows_function_app_resource_test.go +++ b/internal/services/appservice/windows_function_app_resource_test.go @@ -3,6 +3,7 @@ package appservice_test import ( "context" "fmt" + "regexp" "strings" "testing" @@ -33,6 +34,23 @@ func TestAccWindowsFunctionApp_basicBasicPlan(t *testing.T) { }) } +func TestAccWindowsFunctionApp_basicRuntimeCheck(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_windows_function_app", "test") + r := WindowsFunctionAppResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.runtimeScaleCheck(data, SkuElasticPremiumPlan), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("kind").HasValue("functionapp"), + check.That(data.ResourceName).Key("site_config.0.runtime_scale_monitoring_enabled").HasValue("true"), + ), + }, + data.ImportStep(), + }) +} + func TestAccWindowsFunctionApp_basicConsumptionPlan(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_windows_function_app", "test") r := WindowsFunctionAppResource{} @@ -878,6 +896,32 @@ func TestAccWindowsFunctionApp_appStackNodeUpdate(t *testing.T) { }) } +func TestAccWindowsFunctionApp_appStackUpdateTags(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_windows_function_app", "test") + r := WindowsFunctionAppResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.appStackNode(data, SkuConsumptionPlan, "~14"), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("kind").HasValue("functionapp"), + check.That(data.ResourceName).Key("site_config.0.windows_fx_version").HasValue("Node|~14"), + ), + }, + data.ImportStep(), + { + Config: r.appStackNodeWithTags(data, SkuConsumptionPlan, "~14"), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("kind").HasValue("functionapp"), + check.That(data.ResourceName).Key("site_config.0.windows_fx_version").HasValue("Node|~14"), + ), + }, + data.ImportStep(), + }) +} + func TestAccWindowsFunctionApp_appStackJava(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_windows_function_app", "test") r := WindowsFunctionAppResource{} @@ -984,7 +1028,39 @@ func TestAccWindowsFunctionApp_updateStorageAccount(t *testing.T) { }) } -func TestAccWindowsFunctionApp_msiStorageAccount(t *testing.T) { +func TestAccWindowsFunctionApp_msiStorageAccountConsumption(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_windows_function_app", "test") + r := WindowsFunctionAppResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.msiStorageAccount(data, SkuConsumptionPlan), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("kind").HasValue("functionapp"), + ), + }, + data.ImportStep(), + }) +} + +func TestAccWindowsFunctionApp_msiStorageAccountElastic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_windows_function_app", "test") + r := WindowsFunctionAppResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.msiStorageAccount(data, SkuElasticPremiumPlan), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("kind").HasValue("functionapp"), + ), + }, + data.ImportStep(), + }) +} + +func TestAccWindowsFunctionApp_msiStorageAccountStandard(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_windows_function_app", "test") r := WindowsFunctionAppResource{} @@ -1056,6 +1132,105 @@ func TestAccWindowsFunctionApp_storageAccountKeyVaultSecretVersionless(t *testin }) } +func TestAccWindowsFunctionApp_vNetIntegration(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_windows_function_app", "test") + r := WindowsFunctionAppResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.vNetIntegration_subnet1(data, SkuStandardPlan), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("virtual_network_subnet_id").MatchesOtherKey( + check.That("azurerm_subnet.test1").Key("id"), + ), + ), + }, + data.ImportStep(), + }) +} + +func TestAccWindowsFunctionApp_vNetIntegrationUpdate(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_windows_function_app", "test") + r := WindowsFunctionAppResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.vNetIntegration_basic(data, SkuStandardPlan), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.vNetIntegration_subnet1(data, SkuStandardPlan), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("virtual_network_subnet_id").MatchesOtherKey( + check.That("azurerm_subnet.test1").Key("id"), + ), + ), + }, + data.ImportStep(), + { + Config: r.vNetIntegration_subnet2(data, SkuStandardPlan), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("virtual_network_subnet_id").MatchesOtherKey( + check.That("azurerm_subnet.test2").Key("id"), + ), + ), + }, + data.ImportStep(), + { + Config: r.vNetIntegration_basic(data, SkuStandardPlan), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccWindowsFunctionAppASEv3_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_windows_function_app", "test") + r := WindowsFunctionAppResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.withASEV3(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +// Outputs + +func TestAccWindowsFunctionApp_basicOutputs(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_windows_function_app", "test") + r := WindowsFunctionAppResource{} + + ipListRegex := regexp.MustCompile(`(([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})(,){0,1})+`) + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data, SkuStandardPlan), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("outbound_ip_addresses").MatchesRegex(ipListRegex), + check.That(data.ResourceName).Key("outbound_ip_address_list.#").Exists(), + check.That(data.ResourceName).Key("possible_outbound_ip_addresses").MatchesRegex(ipListRegex), + check.That(data.ResourceName).Key("possible_outbound_ip_address_list.#").Exists(), + check.That(data.ResourceName).Key("default_hostname").MatchesRegex(regexp.MustCompile(`(.)+`)), + ), + }, + data.ImportStep(), + }) +} + // Exists func (r WindowsFunctionAppResource) Exists(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { @@ -1101,6 +1276,31 @@ resource "azurerm_windows_function_app" "test" { `, r.template(data, planSku), data.RandomInteger) } +func (r WindowsFunctionAppResource) runtimeScaleCheck(data acceptance.TestData, planSku string) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +%s + +resource "azurerm_windows_function_app" "test" { + name = "acctest-WFA-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + service_plan_id = azurerm_service_plan.test.id + + storage_account_name = azurerm_storage_account.test.name + storage_account_access_key = azurerm_storage_account.test.primary_access_key + + site_config { + runtime_scale_monitoring_enabled = true + pre_warmed_instance_count = 1 + } +} +`, r.template(data, planSku), data.RandomInteger) +} + func (r WindowsFunctionAppResource) appSettings(data acceptance.TestData, planSku string) string { return fmt.Sprintf(` provider "azurerm" { @@ -2265,6 +2465,36 @@ resource "azurerm_windows_function_app" "test" { `, r.template(data, planSku), data.RandomInteger, nodeVersion) } +func (r WindowsFunctionAppResource) appStackNodeWithTags(data acceptance.TestData, planSku string, nodeVersion string) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +%s + +resource "azurerm_windows_function_app" "test" { + name = "acctest-WFA-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + service_plan_id = azurerm_service_plan.test.id + + storage_account_name = azurerm_storage_account.test.name + storage_account_access_key = azurerm_storage_account.test.primary_access_key + + site_config { + application_stack { + node_version = "%s" + } + } + + tags = { + env = "TestAcc" + } +} +`, r.template(data, planSku), data.RandomInteger, nodeVersion) +} + func (r WindowsFunctionAppResource) appStackJava(data acceptance.TestData, planSku string, javaVersion string) string { return fmt.Sprintf(` provider "azurerm" { @@ -2350,7 +2580,7 @@ provider "azurerm" { %s resource "azurerm_windows_function_app" "test" { - name = "acctest-LFA-%d" + name = "acctest-WFA-%d" location = azurerm_resource_group.test.location resource_group_name = azurerm_resource_group.test.name service_plan_id = azurerm_service_plan.test.id @@ -2506,7 +2736,11 @@ resource "azurerm_windows_function_app" "test" { type = "SystemAssigned" } - site_config {} + site_config { + application_stack { + dotnet_version = "6" + } + } } `, r.template(data, planSku), data.RandomInteger) } @@ -2717,7 +2951,7 @@ func (WindowsFunctionAppResource) template(data acceptance.TestData, planSku str } return fmt.Sprintf(` resource "azurerm_resource_group" "test" { - name = "acctestRG-LFA-%d" + name = "acctestRG-WFA-%d" location = "%s" } @@ -2846,3 +3080,197 @@ resource "azurerm_service_plan" "test" { } `, data.RandomInteger, data.Locations.Primary, data.RandomString, planSku) } + +func (r WindowsFunctionAppResource) vNetIntegration_basic(data acceptance.TestData, planSku string) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} +%s + +resource "azurerm_virtual_network" "test" { + name = "vnet-%d" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_subnet" "test1" { + name = "subnet1" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.1.0/24"] + delegation { + name = "delegation" + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_subnet" "test2" { + name = "subnet2" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.2.0/24"] + delegation { + name = "delegation" + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_windows_function_app" "test" { + name = "acctest-WFA-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + service_plan_id = azurerm_service_plan.test.id + storage_account_name = azurerm_storage_account.test.name + storage_account_access_key = azurerm_storage_account.test.primary_access_key + site_config {} +} + +`, r.template(data, planSku), data.RandomInteger, data.RandomInteger) +} + +func (r WindowsFunctionAppResource) vNetIntegration_subnet1(data acceptance.TestData, planSku string) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} +%s +resource "azurerm_virtual_network" "test" { + name = "vnet-%d" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_subnet" "test1" { + name = "subnet1" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.1.0/24"] + delegation { + name = "delegation" + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_subnet" "test2" { + name = "subnet2" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.2.0/24"] + delegation { + name = "delegation" + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_windows_function_app" "test" { + name = "acctest-WFA-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + service_plan_id = azurerm_service_plan.test.id + virtual_network_subnet_id = azurerm_subnet.test1.id + storage_account_name = azurerm_storage_account.test.name + storage_account_access_key = azurerm_storage_account.test.primary_access_key + site_config {} +} + +`, r.template(data, planSku), data.RandomInteger, data.RandomInteger) +} + +func (r WindowsFunctionAppResource) vNetIntegration_subnet2(data acceptance.TestData, planSku string) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} +%s +resource "azurerm_virtual_network" "test" { + name = "vnet-%d" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_subnet" "test1" { + name = "subnet1" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.1.0/24"] + delegation { + name = "delegation" + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_subnet" "test2" { + name = "subnet2" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.2.0/24"] + delegation { + name = "delegation" + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_windows_function_app" "test" { + name = "acctest-WFA-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + service_plan_id = azurerm_service_plan.test.id + virtual_network_subnet_id = azurerm_subnet.test2.id + storage_account_name = azurerm_storage_account.test.name + storage_account_access_key = azurerm_storage_account.test.primary_access_key + site_config {} +} + +`, r.template(data, planSku), data.RandomInteger, data.RandomInteger) +} + +func (r WindowsFunctionAppResource) withASEV3(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_storage_account" "test" { + name = "acctestsa%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + account_tier = "Standard" + account_replication_type = "LRS" +} + +resource "azurerm_windows_function_app" "test" { + name = "acctest-WFA-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + service_plan_id = azurerm_service_plan.test.id + + storage_account_name = azurerm_storage_account.test.name + storage_account_access_key = azurerm_storage_account.test.primary_access_key + + site_config { + vnet_route_all_enabled = true + } +} + +`, ServicePlanResource{}.aseV3(data), data.RandomString, data.RandomInteger) +} diff --git a/internal/services/appservice/windows_function_app_slot_resource.go b/internal/services/appservice/windows_function_app_slot_resource.go index 675eb013e537..3a47b06699e0 100644 --- a/internal/services/appservice/windows_function_app_slot_resource.go +++ b/internal/services/appservice/windows_function_app_slot_resource.go @@ -16,6 +16,7 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/internal/services/appservice/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/appservice/validate" kvValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/keyvault/validate" + networkValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/validate" storageValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/storage/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" @@ -55,6 +56,7 @@ type WindowsFunctionAppSlotModel struct { PossibleOutboundIPAddresses string `tfschema:"possible_outbound_ip_addresses"` PossibleOutboundIPAddressList []string `tfschema:"possible_outbound_ip_address_list"` SiteCredentials []helpers.SiteCredential `tfschema:"site_credential"` + VirtualNetworkSubnetID string `tfschema:"virtual_network_subnet_id"` } var _ sdk.ResourceWithUpdate = WindowsFunctionAppSlotResource{} @@ -224,6 +226,12 @@ func (r WindowsFunctionAppSlotResource) Arguments() map[string]*pluginsdk.Schema "site_config": helpers.SiteConfigSchemaWindowsFunctionAppSlot(), "tags": tags.Schema(), + + "virtual_network_subnet_id": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: networkValidate.SubnetID, + }, } } @@ -324,21 +332,14 @@ func (r WindowsFunctionAppSlotResource) Create() sdk.ResourceFunc { return fmt.Errorf("reading %s: %+v", servicePlanId, err) } - sendContentSettings := !functionAppSlot.ForceDisableContentShare - if planSku := servicePlan.Sku; planSku != nil && planSku.Tier != nil { - switch tier := *planSku.Tier; strings.ToLower(tier) { - case "dynamic": - case "elastic": - case "basic": - sendContentSettings = false - case "standard": - sendContentSettings = false - case "premiumv2", "premiumv3": - sendContentSettings = false - } + var planSKU *string + if sku := servicePlan.Sku; sku != nil && sku.Name != nil { + planSKU = sku.Name } else { - return fmt.Errorf("determining plan type for Windows %s: %v", id, err) + return fmt.Errorf("could not determine Service Plan SKU type") } + // Only send for Dynamic and ElasticPremium + sendContentSettings := (helpers.PlanIsConsumption(planSKU) || helpers.PlanIsElastic(planSKU)) && !functionAppSlot.ForceDisableContentShare existing, err := client.GetSlot(ctx, id.ResourceGroup, id.SiteName, id.SlotName) if err != nil && !utils.ResponseWasNotFound(existing.Response) { @@ -414,12 +415,18 @@ func (r WindowsFunctionAppSlotResource) Create() sdk.ResourceFunc { if functionAppSlot.AppSettings == nil { functionAppSlot.AppSettings = make(map[string]string) } - suffix := uuid.New().String()[0:4] - if _, present := functionAppSlot.AppSettings["WEBSITE_CONTENTSHARE"]; !present { - functionAppSlot.AppSettings["WEBSITE_CONTENTSHARE"] = fmt.Sprintf("%s-%s", strings.ToLower(functionAppSlot.Name), suffix) - } - if _, present := functionAppSlot.AppSettings["WEBSITE_CONTENTAZUREFILECONNECTIONSTRING"]; !present { - functionAppSlot.AppSettings["WEBSITE_CONTENTAZUREFILECONNECTIONSTRING"] = storageString + if !functionAppSlot.StorageUsesMSI { + suffix := uuid.New().String()[0:4] + if _, present := functionAppSlot.AppSettings["WEBSITE_CONTENTSHARE"]; !present { + functionAppSlot.AppSettings["WEBSITE_CONTENTSHARE"] = fmt.Sprintf("%s-%s", strings.ToLower(functionAppSlot.Name), suffix) + } + if _, present := functionAppSlot.AppSettings["WEBSITE_CONTENTAZUREFILECONNECTIONSTRING"]; !present { + functionAppSlot.AppSettings["WEBSITE_CONTENTAZUREFILECONNECTIONSTRING"] = storageString + } + } else { + if _, present := functionAppSlot.AppSettings["AzureWebJobsStorage__accountName"]; !present { + functionAppSlot.AppSettings["AzureWebJobsStorage__accountName"] = storageString + } } } @@ -447,6 +454,10 @@ func (r WindowsFunctionAppSlotResource) Create() sdk.ResourceFunc { }, } + if functionAppSlot.VirtualNetworkSubnetID != "" { + siteEnvelope.SiteProperties.VirtualNetworkSubnetID = utils.String(functionAppSlot.VirtualNetworkSubnetID) + } + if functionAppSlot.KeyVaultReferenceIdentityID != "" { siteEnvelope.SiteProperties.KeyVaultReferenceIdentity = utils.String(functionAppSlot.KeyVaultReferenceIdentityID) } @@ -511,18 +522,18 @@ func (r WindowsFunctionAppSlotResource) Read() sdk.ResourceFunc { if err != nil { return err } - functionAppSlot, err := client.GetSlot(ctx, id.ResourceGroup, id.SiteName, id.SlotName) + functionApp, err := client.GetSlot(ctx, id.ResourceGroup, id.SiteName, id.SlotName) if err != nil { - if utils.ResponseWasNotFound(functionAppSlot.Response) { + if utils.ResponseWasNotFound(functionApp.Response) { return metadata.MarkAsGone(id) } return fmt.Errorf("reading Windows %s: %+v", id, err) } - if functionAppSlot.SiteProperties == nil { + if functionApp.SiteProperties == nil { return fmt.Errorf("reading properties of Windows %s", id) } - props := *functionAppSlot.SiteProperties + props := *functionApp.SiteProperties appSettingsResp, err := client.ListApplicationSettingsSlot(ctx, id.ResourceGroup, id.SiteName, id.SlotName) if err != nil { @@ -567,11 +578,11 @@ func (r WindowsFunctionAppSlotResource) Read() sdk.ResourceFunc { state := WindowsFunctionAppSlotModel{ Name: id.SlotName, FunctionAppID: parse.NewFunctionAppID(id.SubscriptionId, id.ResourceGroup, id.SiteName).ID(), - Enabled: utils.NormaliseNilableBool(functionAppSlot.Enabled), - ClientCertMode: string(functionAppSlot.ClientCertMode), + Enabled: utils.NormaliseNilableBool(functionApp.Enabled), + ClientCertMode: string(functionApp.ClientCertMode), DailyMemoryTimeQuota: int(utils.NormaliseNilableInt32(props.DailyMemoryTimeQuota)), - Tags: tags.ToTypedObject(functionAppSlot.Tags), - Kind: utils.NormalizeNilableString(functionAppSlot.Kind), + Tags: tags.ToTypedObject(functionApp.Tags), + Kind: utils.NormalizeNilableString(functionApp.Kind), KeyVaultReferenceIdentityID: utils.NormalizeNilableString(props.KeyVaultReferenceIdentity), CustomDomainVerificationId: utils.NormalizeNilableString(props.CustomDomainVerificationID), DefaultHostname: utils.NormalizeNilableString(props.DefaultHostName), @@ -600,14 +611,18 @@ func (r WindowsFunctionAppSlotResource) Read() sdk.ResourceFunc { state.SiteConfig[0].AppServiceLogs = helpers.FlattenFunctionAppAppServiceLogs(logs) - state.HttpsOnly = utils.NormaliseNilableBool(functionAppSlot.HTTPSOnly) - state.ClientCertEnabled = utils.NormaliseNilableBool(functionAppSlot.ClientCertEnabled) + state.HttpsOnly = utils.NormaliseNilableBool(functionApp.HTTPSOnly) + state.ClientCertEnabled = utils.NormaliseNilableBool(functionApp.ClientCertEnabled) + + if subnetId := utils.NormalizeNilableString(props.VirtualNetworkSubnetID); subnetId != "" { + state.VirtualNetworkSubnetID = subnetId + } if err := metadata.Encode(&state); err != nil { return fmt.Errorf("encoding: %+v", err) } - flattenedIdentity, err := flattenIdentity(functionAppSlot.Identity) + flattenedIdentity, err := flattenIdentity(functionApp.Identity) if err != nil { return fmt.Errorf("flattening `identity`: %+v", err) } @@ -667,7 +682,9 @@ func (r WindowsFunctionAppSlotResource) Update() sdk.ResourceFunc { if err != nil { return err } - sendContentSettings := !helpers.PlanIsAppPlan(planSKU) + + // Only send for Dynamic and ElasticPremium + sendContentSettings := (helpers.PlanIsConsumption(planSKU) || helpers.PlanIsElastic(planSKU)) && !state.ForceDisableContentShare // Some service plan updates are allowed - see customiseDiff for exceptions if metadata.ResourceData.HasChange("enabled") { @@ -702,6 +719,19 @@ func (r WindowsFunctionAppSlotResource) Update() sdk.ResourceFunc { existing.Tags = tags.FromTypedObject(state.Tags) } + if metadata.ResourceData.HasChange("virtual_network_subnet_id") { + subnetId := metadata.ResourceData.Get("virtual_network_subnet_id").(string) + if subnetId == "" { + if _, err := client.DeleteSwiftVirtualNetworkSlot(ctx, id.ResourceGroup, id.SiteName, id.SlotName); err != nil { + return fmt.Errorf("removing `virtual_network_subnet_id` association for %s: %+v", *id, err) + } + var empty *string + existing.SiteProperties.VirtualNetworkSubnetID = empty + } else { + existing.SiteProperties.VirtualNetworkSubnetID = utils.String(subnetId) + } + } + storageString := state.StorageAccountName if !state.StorageUsesMSI { if state.StorageKeyVaultSecretID != "" { diff --git a/internal/services/appservice/windows_function_app_slot_resource_test.go b/internal/services/appservice/windows_function_app_slot_resource_test.go index c3cf61dba2dc..a8ba79aa2470 100644 --- a/internal/services/appservice/windows_function_app_slot_resource_test.go +++ b/internal/services/appservice/windows_function_app_slot_resource_test.go @@ -815,7 +815,39 @@ func TestAccWindowsFunctionAppSlot_updateStorageAccount(t *testing.T) { }) } -func TestAccWindowsFunctionAppSlot_msiStorageAccount(t *testing.T) { +func TestAccWindowsFunctionAppSlot_msiStorageAccountConsumption(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_windows_function_app_slot", "test") + r := WindowsFunctionAppSlotResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.msiStorageAccount(data, SkuConsumptionPlan), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("kind").HasValue("functionapp"), + ), + }, + data.ImportStep(), + }) +} + +func TestAccWindowsFunctionAppSlot_msiStorageAccountElastic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_windows_function_app_slot", "test") + r := WindowsFunctionAppSlotResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.msiStorageAccount(data, SkuElasticPremiumPlan), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("kind").HasValue("functionapp"), + ), + }, + data.ImportStep(), + }) +} + +func TestAccWindowsFunctionAppSlot_msiStorageAccountStandard(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_windows_function_app_slot", "test") r := WindowsFunctionAppSlotResource{} @@ -863,6 +895,81 @@ func TestAccWindowsFunctionAppSlot_storageAccountKeyVaultSecretVersionless(t *te }) } +func TestAccWindowsFunctionAppSlot_vNetIntegration(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_windows_function_app_slot", "test") + r := WindowsFunctionAppSlotResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.vNetIntegration_subnet1(data, SkuStandardPlan), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("virtual_network_subnet_id").MatchesOtherKey( + check.That("azurerm_subnet.test1").Key("id"), + ), + ), + }, + data.ImportStep(), + }) +} + +func TestAccWindowsFunctionAppSlot_vNetIntegrationUpdate(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_windows_function_app_slot", "test") + r := WindowsFunctionAppSlotResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.vNetIntegration_basic(data, SkuStandardPlan), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.vNetIntegration_subnet1(data, SkuStandardPlan), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("virtual_network_subnet_id").MatchesOtherKey( + check.That("azurerm_subnet.test1").Key("id"), + ), + ), + }, + data.ImportStep(), + { + Config: r.vNetIntegration_subnet2(data, SkuStandardPlan), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("virtual_network_subnet_id").MatchesOtherKey( + check.That("azurerm_subnet.test2").Key("id"), + ), + ), + }, + data.ImportStep(), + { + Config: r.vNetIntegration_basic(data, SkuStandardPlan), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccWindowsFunctionAppSlotASEv3_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_windows_function_app_slot", "test") + r := WindowsFunctionAppSlotResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.withASEV3(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + // Exists func (r WindowsFunctionAppSlotResource) Exists(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { @@ -2001,7 +2108,11 @@ resource "azurerm_windows_function_app_slot" "test" { type = "SystemAssigned" } - site_config {} + site_config { + application_stack { + dotnet_version = "6" + } + } } `, r.template(data, planSku), data.RandomInteger) } @@ -2163,7 +2274,7 @@ func (WindowsFunctionAppSlotResource) template(data acceptance.TestData, planSku } return fmt.Sprintf(` resource "azurerm_resource_group" "test" { - name = "acctestRG-LFA-%[1]d" + name = "acctestRG-WFA-%[1]d" location = "%[2]s" } @@ -2316,3 +2427,189 @@ resource "azurerm_windows_function_app" "test" { } `, data.RandomInteger, data.Locations.Primary, data.RandomString, planSku) } + +func (r WindowsFunctionAppSlotResource) vNetIntegration_basic(data acceptance.TestData, planSku string) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} +%s +resource "azurerm_virtual_network" "test" { + name = "vnet-%d" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} +resource "azurerm_subnet" "test1" { + name = "subnet1" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.1.0/24"] + delegation { + name = "delegation" + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} +resource "azurerm_subnet" "test2" { + name = "subnet2" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.2.0/24"] + delegation { + name = "delegation" + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} +resource "azurerm_windows_function_app_slot" "test" { + name = "acctest-WFAS-%d" + function_app_id = azurerm_windows_function_app.test.id + storage_account_name = azurerm_storage_account.test.name + storage_account_access_key = azurerm_storage_account.test.primary_access_key + site_config {} +} +`, r.template(data, planSku), data.RandomInteger, data.RandomInteger) +} + +func (r WindowsFunctionAppSlotResource) vNetIntegration_subnet1(data acceptance.TestData, planSku string) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} +%s +resource "azurerm_virtual_network" "test" { + name = "vnet-%d" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} +resource "azurerm_subnet" "test1" { + name = "subnet1" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.1.0/24"] + delegation { + name = "delegation" + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} +resource "azurerm_subnet" "test2" { + name = "subnet2" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.2.0/24"] + delegation { + name = "delegation" + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} +resource "azurerm_windows_function_app_slot" "test" { + name = "acctest-WFAS-%d" + function_app_id = azurerm_windows_function_app.test.id + storage_account_name = azurerm_storage_account.test.name + storage_account_access_key = azurerm_storage_account.test.primary_access_key + virtual_network_subnet_id = azurerm_subnet.test1.id + site_config {} +} +`, r.template(data, planSku), data.RandomInteger, data.RandomInteger) +} + +func (r WindowsFunctionAppSlotResource) vNetIntegration_subnet2(data acceptance.TestData, planSku string) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} +%s +resource "azurerm_virtual_network" "test" { + name = "vnet-%d" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} +resource "azurerm_subnet" "test1" { + name = "subnet1" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.1.0/24"] + delegation { + name = "delegation" + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} +resource "azurerm_subnet" "test2" { + name = "subnet2" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.2.0/24"] + delegation { + name = "delegation" + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} +resource "azurerm_windows_function_app_slot" "test" { + name = "acctest-WFAS-%d" + function_app_id = azurerm_windows_function_app.test.id + storage_account_name = azurerm_storage_account.test.name + storage_account_access_key = azurerm_storage_account.test.primary_access_key + virtual_network_subnet_id = azurerm_subnet.test2.id + site_config {} +} +`, r.template(data, planSku), data.RandomInteger, data.RandomInteger) +} + +func (r WindowsFunctionAppSlotResource) withASEV3(data acceptance.TestData) string { + return fmt.Sprintf(` +%[1]s + +resource "azurerm_storage_account" "test" { + name = "acctestsa%[2]s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + account_tier = "Standard" + account_replication_type = "LRS" +} + +resource "azurerm_windows_function_app" "test" { + name = "acctest-WFA-%[3]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + service_plan_id = azurerm_service_plan.test.id + + storage_account_name = azurerm_storage_account.test.name + storage_account_access_key = azurerm_storage_account.test.primary_access_key + + site_config { + vnet_route_all_enabled = true + } +} + +resource "azurerm_windows_function_app_slot" "test" { + name = "acctest-WFAS-%[3]d" + function_app_id = azurerm_windows_function_app.test.id + storage_account_name = azurerm_storage_account.test.name + storage_account_access_key = azurerm_storage_account.test.primary_access_key + + site_config { + vnet_route_all_enabled = true + } +} + +`, ServicePlanResource{}.aseV3(data), data.RandomString, data.RandomInteger) +} diff --git a/internal/services/appservice/windows_web_app_data_source.go b/internal/services/appservice/windows_web_app_data_source.go index 48a9d59ef9f2..f4641f72659f 100644 --- a/internal/services/appservice/windows_web_app_data_source.go +++ b/internal/services/appservice/windows_web_app_data_source.go @@ -46,6 +46,7 @@ type WindowsWebAppDataSourceModel struct { PossibleOutboundIPAddressList []string `tfschema:"possible_outbound_ip_address_list"` SiteCredentials []helpers.SiteCredential `tfschema:"site_credential"` Tags map[string]string `tfschema:"tags"` + VirtualNetworkSubnetID string `tfschema:"virtual_network_subnet_id"` } var _ sdk.DataSource = WindowsWebAppDataSource{} @@ -172,6 +173,11 @@ func (d WindowsWebAppDataSource) Attributes() map[string]*pluginsdk.Schema { "storage_account": helpers.StorageAccountSchemaComputed(), + "virtual_network_subnet_id": { + Type: pluginsdk.TypeString, + Computed: true, + }, + "tags": tags.SchemaDataSource(), } } diff --git a/internal/services/appservice/windows_web_app_resource.go b/internal/services/appservice/windows_web_app_resource.go index a730feb630a9..fbfa9bd52ce6 100644 --- a/internal/services/appservice/windows_web_app_resource.go +++ b/internal/services/appservice/windows_web_app_resource.go @@ -15,6 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/internal/services/appservice/helpers" "github.com/hashicorp/terraform-provider-azurerm/internal/services/appservice/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/appservice/validate" + networkValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" @@ -52,6 +53,7 @@ type WindowsWebAppModel struct { SiteCredentials []helpers.SiteCredential `tfschema:"site_credential"` ZipDeployFile string `tfschema:"zip_deploy_file"` Tags map[string]string `tfschema:"tags"` + VirtualNetworkSubnetID string `tfschema:"virtual_network_subnet_id"` } var _ sdk.ResourceWithCustomImporter = WindowsWebAppResource{} @@ -151,6 +153,12 @@ func (r WindowsWebAppResource) Arguments() map[string]*pluginsdk.Schema { }, "tags": tags.Schema(), + + "virtual_network_subnet_id": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: networkValidate.SubnetID, + }, } } @@ -313,6 +321,10 @@ func (r WindowsWebAppResource) Create() sdk.ResourceFunc { siteEnvelope.SiteProperties.KeyVaultReferenceIdentity = utils.String(webApp.KeyVaultReferenceIdentityID) } + if webApp.VirtualNetworkSubnetID != "" { + siteEnvelope.SiteProperties.VirtualNetworkSubnetID = utils.String(webApp.VirtualNetworkSubnetID) + } + future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.SiteName, siteEnvelope) if err != nil { return fmt.Errorf("creating Windows %s: %+v", id, err) @@ -510,6 +522,10 @@ func (r WindowsWebAppResource) Read() sdk.ResourceFunc { Tags: tags.ToTypedObject(webApp.Tags), } + if subnetId := utils.NormalizeNilableString(props.VirtualNetworkSubnetID); subnetId != "" { + state.VirtualNetworkSubnetID = subnetId + } + var healthCheckCount *int state.AppSettings, healthCheckCount = helpers.FlattenAppSettings(appSettings) @@ -655,6 +671,19 @@ func (r WindowsWebAppResource) Update() sdk.ResourceFunc { existing.Tags = tags.FromTypedObject(state.Tags) } + if metadata.ResourceData.HasChange("virtual_network_subnet_id") { + subnetId := metadata.ResourceData.Get("virtual_network_subnet_id").(string) + if subnetId == "" { + if _, err := client.DeleteSwiftVirtualNetwork(ctx, id.ResourceGroup, id.SiteName); err != nil { + return fmt.Errorf("removing `virtual_network_subnet_id` association for %s: %+v", *id, err) + } + var empty *string + existing.SiteProperties.VirtualNetworkSubnetID = empty + } else { + existing.SiteProperties.VirtualNetworkSubnetID = utils.String(subnetId) + } + } + currentStack := "" stateConfig := state.SiteConfig[0] if len(stateConfig.ApplicationStack) == 1 { diff --git a/internal/services/appservice/windows_web_app_resource_test.go b/internal/services/appservice/windows_web_app_resource_test.go index 4b0f031cc828..ee2fba96de3d 100644 --- a/internal/services/appservice/windows_web_app_resource_test.go +++ b/internal/services/appservice/windows_web_app_resource_test.go @@ -556,13 +556,13 @@ func TestAccWindowsWebApp_virtualDirectoriesUpdate(t *testing.T) { } // App Stacks -func TestAccWindowsWebApp_withDotNet3(t *testing.T) { +func TestAccWindowsWebApp_withDotNetCore(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_windows_web_app", "test") r := WindowsWebAppResource{} data.ResourceTest(t, r, []acceptance.TestStep{ { - Config: r.dotNetCore(data, "v3.0"), + Config: r.dotNetCore(data, "core3.1"), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), ), @@ -1055,6 +1055,66 @@ func TestAccWindowsWebAppASEV3_basic(t *testing.T) { }) } +func TestAccWindowsWebApp_vNetIntegration(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_windows_web_app", "test") + r := WindowsWebAppResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.vNetIntegrationWebApp_subnet1(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("virtual_network_subnet_id").MatchesOtherKey( + check.That("azurerm_subnet.test1").Key("id"), + ), + ), + }, + data.ImportStep(), + }) +} + +func TestAccWindowsWebApp_vNetIntegrationUpdate(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_windows_web_app", "test") + r := WindowsWebAppResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.vNetIntegrationWebApp_basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.vNetIntegrationWebApp_subnet1(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("virtual_network_subnet_id").MatchesOtherKey( + check.That("azurerm_subnet.test1").Key("id"), + ), + ), + }, + data.ImportStep(), + { + Config: r.vNetIntegrationWebApp_subnet2(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("virtual_network_subnet_id").MatchesOtherKey( + check.That("azurerm_subnet.test2").Key("id"), + ), + ), + }, + data.ImportStep(), + { + Config: r.vNetIntegrationWebApp_basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func (r WindowsWebAppResource) Exists(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { id, err := parse.WebAppID(state.ID) if err != nil { @@ -2828,3 +2888,158 @@ data "azurerm_storage_account_sas" "test" { } `, r.baseTemplate(data), data.RandomInteger, data.RandomString) } + +func (r WindowsWebAppResource) vNetIntegrationWebApp_basic(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} +%s +resource "azurerm_virtual_network" "test" { + name = "vnet-%d" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_subnet" "test1" { + name = "subnet1" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.1.0/24"] + delegation { + name = "delegation" + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_subnet" "test2" { + name = "subnet2" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.2.0/24"] + delegation { + name = "delegation" + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_windows_web_app" "test" { + name = "acctestWA-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + service_plan_id = azurerm_service_plan.test.id + site_config {} +} +`, r.baseTemplate(data), data.RandomInteger, data.RandomInteger) +} + +func (r WindowsWebAppResource) vNetIntegrationWebApp_subnet1(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} +%s +resource "azurerm_virtual_network" "test" { + name = "vnet-%d" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_subnet" "test1" { + name = "subnet1" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.1.0/24"] + delegation { + name = "delegation" + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_subnet" "test2" { + name = "subnet2" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.2.0/24"] + delegation { + name = "delegation" + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_windows_web_app" "test" { + name = "acctestWA-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + service_plan_id = azurerm_service_plan.test.id + virtual_network_subnet_id = azurerm_subnet.test1.id + site_config {} +} +`, r.baseTemplate(data), data.RandomInteger, data.RandomInteger) +} + +func (r WindowsWebAppResource) vNetIntegrationWebApp_subnet2(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} +%s +resource "azurerm_virtual_network" "test" { + name = "vnet-%d" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_subnet" "test1" { + name = "subnet1" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.1.0/24"] + delegation { + name = "delegation" + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_subnet" "test2" { + name = "subnet2" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.2.0/24"] + delegation { + name = "delegation" + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_windows_web_app" "test" { + name = "acctestWA-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + service_plan_id = azurerm_service_plan.test.id + virtual_network_subnet_id = azurerm_subnet.test2.id + site_config {} +} +`, r.baseTemplate(data), data.RandomInteger, data.RandomInteger) +} diff --git a/internal/services/appservice/windows_web_app_slot_resource.go b/internal/services/appservice/windows_web_app_slot_resource.go index 011c4e5a851c..de51b5def48d 100644 --- a/internal/services/appservice/windows_web_app_slot_resource.go +++ b/internal/services/appservice/windows_web_app_slot_resource.go @@ -13,6 +13,7 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/internal/services/appservice/helpers" "github.com/hashicorp/terraform-provider-azurerm/internal/services/appservice/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/appservice/validate" + networkValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" @@ -47,6 +48,7 @@ type WindowsWebAppSlotModel struct { SiteCredentials []helpers.SiteCredential `tfschema:"site_credential"` ZipDeployFile string `tfschema:"zip_deploy_file"` Tags map[string]string `tfschema:"tags"` + VirtualNetworkSubnetID string `tfschema:"virtual_network_subnet_id"` } var _ sdk.ResourceWithUpdate = WindowsWebAppSlotResource{} @@ -153,6 +155,12 @@ func (r WindowsWebAppSlotResource) Arguments() map[string]*pluginsdk.Schema { }, "tags": tags.Schema(), + + "virtual_network_subnet_id": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: networkValidate.SubnetID, + }, } } @@ -272,6 +280,10 @@ func (r WindowsWebAppSlotResource) Create() sdk.ResourceFunc { siteEnvelope.SiteProperties.KeyVaultReferenceIdentity = utils.String(webAppSlot.KeyVaultReferenceIdentityID) } + if webAppSlot.VirtualNetworkSubnetID != "" { + siteEnvelope.SiteProperties.VirtualNetworkSubnetID = utils.String(webAppSlot.VirtualNetworkSubnetID) + } + future, err := client.CreateOrUpdateSlot(ctx, id.ResourceGroup, id.SiteName, siteEnvelope, id.SlotName) if err != nil { return fmt.Errorf("creating Windows %s: %+v", id, err) @@ -450,6 +462,10 @@ func (r WindowsWebAppSlotResource) Read() sdk.ResourceFunc { Tags: tags.ToTypedObject(webApp.Tags), } + if subnetId := utils.NormalizeNilableString(props.VirtualNetworkSubnetID); subnetId != "" { + state.VirtualNetworkSubnetID = subnetId + } + var healthCheckCount *int state.AppSettings, healthCheckCount = helpers.FlattenAppSettings(appSettings) @@ -585,6 +601,19 @@ func (r WindowsWebAppSlotResource) Update() sdk.ResourceFunc { existing.SiteConfig = siteConfig } + if metadata.ResourceData.HasChange("virtual_network_subnet_id") { + subnetId := metadata.ResourceData.Get("virtual_network_subnet_id").(string) + if subnetId == "" { + if _, err := client.DeleteSwiftVirtualNetworkSlot(ctx, id.ResourceGroup, id.SiteName, id.SlotName); err != nil { + return fmt.Errorf("removing `virtual_network_subnet_id` association for %s: %+v", *id, err) + } + var empty *string + existing.SiteProperties.VirtualNetworkSubnetID = empty + } else { + existing.SiteProperties.VirtualNetworkSubnetID = utils.String(subnetId) + } + } + updateFuture, err := client.CreateOrUpdateSlot(ctx, id.ResourceGroup, id.SiteName, existing, id.SlotName) if err != nil { return fmt.Errorf("updating Windows %s: %+v", id, err) diff --git a/internal/services/appservice/windows_web_app_slot_resource_test.go b/internal/services/appservice/windows_web_app_slot_resource_test.go index 9d58283baeae..813b82c2a20b 100644 --- a/internal/services/appservice/windows_web_app_slot_resource_test.go +++ b/internal/services/appservice/windows_web_app_slot_resource_test.go @@ -710,6 +710,66 @@ func TestAccWindowsWebAppSlot_zipDeploy(t *testing.T) { }) } +func TestAccWindowsWebAppSlot_vNetIntegration(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_windows_web_app_slot", "test") + r := WindowsWebAppSlotResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.vNetIntegrationWebApp_subnet1(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("virtual_network_subnet_id").MatchesOtherKey( + check.That("azurerm_subnet.test1").Key("id"), + ), + ), + }, + data.ImportStep(), + }) +} + +func TestAccWindowsWebAppSlot_vNetIntegrationUpdate(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_windows_web_app_slot", "test") + r := WindowsWebAppSlotResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.vNetIntegrationWebApp_basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.vNetIntegrationWebApp_subnet1(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("virtual_network_subnet_id").MatchesOtherKey( + check.That("azurerm_subnet.test1").Key("id"), + ), + ), + }, + data.ImportStep(), + { + Config: r.vNetIntegrationWebApp_subnet2(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("virtual_network_subnet_id").MatchesOtherKey( + check.That("azurerm_subnet.test2").Key("id"), + ), + ), + }, + data.ImportStep(), + { + Config: r.vNetIntegrationWebApp_basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + // Exists func (r WindowsWebAppSlotResource) Exists(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { @@ -1853,3 +1913,155 @@ resource "azurerm_windows_web_app" "test" { } `, data.RandomInteger, data.Locations.Primary) } + +func (r WindowsWebAppSlotResource) vNetIntegrationWebApp_basic(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} +%s +resource "azurerm_virtual_network" "test" { + name = "vnet-%d" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_subnet" "test1" { + name = "subnet1" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.1.0/24"] + delegation { + name = "delegation" + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_subnet" "test2" { + name = "subnet2" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.2.0/24"] + delegation { + name = "delegation" + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_windows_web_app_slot" "test" { + name = "acctestWAS-%[2]d" + app_service_id = azurerm_windows_web_app.test.id + + site_config {} +} +`, r.baseTemplate(data), data.RandomInteger, data.RandomInteger) +} + +func (r WindowsWebAppSlotResource) vNetIntegrationWebApp_subnet1(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} +%s +resource "azurerm_virtual_network" "test" { + name = "vnet-%d" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_subnet" "test1" { + name = "subnet1" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.1.0/24"] + delegation { + name = "delegation" + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_subnet" "test2" { + name = "subnet2" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.2.0/24"] + delegation { + name = "delegation" + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_windows_web_app_slot" "test" { + name = "acctestWAS-%[2]d" + app_service_id = azurerm_windows_web_app.test.id + virtual_network_subnet_id = azurerm_subnet.test1.id + + site_config {} +} +`, r.baseTemplate(data), data.RandomInteger, data.RandomInteger) +} + +func (r WindowsWebAppSlotResource) vNetIntegrationWebApp_subnet2(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} +%s +resource "azurerm_virtual_network" "test" { + name = "vnet-%d" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_subnet" "test1" { + name = "subnet1" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.1.0/24"] + delegation { + name = "delegation" + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_subnet" "test2" { + name = "subnet2" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.2.0/24"] + delegation { + name = "delegation" + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_windows_web_app_slot" "test" { + name = "acctestWAS-%[2]d" + app_service_id = azurerm_windows_web_app.test.id + virtual_network_subnet_id = azurerm_subnet.test2.id + + site_config {} +} +`, r.baseTemplate(data), data.RandomInteger, data.RandomInteger) +} diff --git a/internal/services/automation/automation_account_data_source.go b/internal/services/automation/automation_account_data_source.go index e5646692b0dc..6e5ef6c19e2f 100644 --- a/internal/services/automation/automation_account_data_source.go +++ b/internal/services/automation/automation_account_data_source.go @@ -4,9 +4,10 @@ import ( "fmt" "time" + "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/automationaccount" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/automation/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" "github.com/hashicorp/terraform-provider-azurerm/utils" @@ -40,6 +41,22 @@ func dataSourceAutomationAccount() *pluginsdk.Resource { Type: pluginsdk.TypeString, Computed: true, }, + "private_endpoint_connection": { + Type: pluginsdk.TypeList, + Computed: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Computed: true, + }, + "id": { + Type: pluginsdk.TypeString, + Computed: true, + }, + }, + }, + }, }, } } @@ -47,21 +64,23 @@ func dataSourceAutomationAccount() *pluginsdk.Resource { func dataSourceAutomationAccountRead(d *pluginsdk.ResourceData, meta interface{}) error { iclient := meta.(*clients.Client).Automation.AgentRegistrationInfoClient client := meta.(*clients.Client).Automation.AccountClient + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id := parse.NewAutomationAccountID(client.SubscriptionID, d.Get("resource_group_name").(string), d.Get("name").(string)) + id := automationaccount.NewAutomationAccountID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) - resp, err := client.Get(ctx, id.ResourceGroup, id.Name) + resp, err := client.Get(ctx, id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { return fmt.Errorf("%s was not found", id) } return fmt.Errorf("retreiving %s: %+v", id, err) } d.SetId(id.ID()) - iresp, err := iclient.Get(ctx, id.ResourceGroup, id.Name) + iresp, err := iclient.Get(ctx, id.ResourceGroupName, id.AutomationAccountName) if err != nil { if utils.ResponseWasNotFound(iresp.Response) { return fmt.Errorf("%q Account Registration Information was not found", id) @@ -73,5 +92,21 @@ func dataSourceAutomationAccountRead(d *pluginsdk.ResourceData, meta interface{} d.Set("secondary_key", iresp.Keys.Secondary) } d.Set("endpoint", iresp.Endpoint) + if resp.Model != nil && resp.Model.Properties != nil { + d.Set("private_endpoint_connection", flattenPrivateEndpointConnections(resp.Model.Properties.PrivateEndpointConnections)) + } return nil } + +func flattenPrivateEndpointConnections(conns *[]automationaccount.PrivateEndpointConnection) (res []interface{}) { + if conns == nil || len(*conns) == 0 { + return + } + for _, con := range *conns { + res = append(res, map[string]interface{}{ + "id": con.Id, + "name": con.Name, + }) + } + return res +} diff --git a/internal/services/automation/automation_account_resource.go b/internal/services/automation/automation_account_resource.go index 18e665f53bc3..21483628e355 100644 --- a/internal/services/automation/automation_account_resource.go +++ b/internal/services/automation/automation_account_resource.go @@ -5,14 +5,18 @@ import ( "log" "time" - "github.com/Azure/azure-sdk-for-go/services/preview/automation/mgmt/2020-01-13-preview/automation" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/identity" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/automationaccount" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/automation/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/automation/validate" + keyVaultParse "github.com/hashicorp/terraform-provider-azurerm/internal/services/keyvault/parse" + keyVaultValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/keyvault/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" @@ -27,7 +31,7 @@ func resourceAutomationAccount() *pluginsdk.Resource { Update: resourceAutomationAccountUpdate, Delete: resourceAutomationAccountDelete, Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - _, err := parse.AutomationAccountID(id) + _, err := automationaccount.ParseAutomationAccountID(id) return err }), @@ -51,16 +55,50 @@ func resourceAutomationAccount() *pluginsdk.Resource { "resource_group_name": commonschema.ResourceGroupName(), "sku_name": { - Type: pluginsdk.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - string(automation.SkuNameEnumBasic), - string(automation.SkuNameEnumFree), - }, false), + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(automationaccount.PossibleValuesForSkuNameEnum(), false), }, "identity": commonschema.SystemAssignedUserAssignedIdentityOptional(), + "encryption": { + Type: pluginsdk.TypeList, + Optional: true, + Computed: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*schema.Schema{ + "user_assigned_identity_id": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: commonids.ValidateUserAssignedIdentityID, + }, + + "key_source": { + Type: pluginsdk.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice( + automationaccount.PossibleValuesForEncryptionKeySourceType(), + false, + ), + }, + + "key_vault_key_id": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: keyVaultValidate.NestedItemIdWithOptionalVersion, + }, + }, + }, + }, + + "local_authentication_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: true, + }, + "tags": tags.Schema(), "dsc_server_endpoint": { @@ -82,6 +120,22 @@ func resourceAutomationAccount() *pluginsdk.Resource { Optional: true, Default: true, }, + "private_endpoint_connection": { + Type: pluginsdk.TypeList, + Computed: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Computed: true, + }, + "id": { + Type: pluginsdk.TypeString, + Computed: true, + }, + }, + }, + }, }, } } @@ -92,35 +146,51 @@ func resourceAutomationAccountCreate(d *pluginsdk.ResourceData, meta interface{} ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) defer cancel() - id := parse.NewAutomationAccountID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) - existing, err := client.Get(ctx, id.ResourceGroup, id.Name) + id := automationaccount.NewAutomationAccountID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) + existing, err := client.Get(ctx, id) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return fmt.Errorf("checking for presence of existing %s: %+v", id, err) } } - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return tf.ImportAsExistsError("azurerm_automation_account", id.ID()) } - identity, err := expandAutomationAccountIdentity(d.Get("identity").([]interface{}), true) + identityVal, err := identity.ExpandSystemAndUserAssignedMap(d.Get("identity").([]interface{})) if err != nil { return fmt.Errorf("expanding `identity`: %+v", err) } - parameters := automation.AccountCreateOrUpdateParameters{ - AccountCreateOrUpdateProperties: &automation.AccountCreateOrUpdateProperties{ - Sku: &automation.Sku{ - Name: automation.SkuNameEnum(d.Get("sku_name").(string)), + parameters := automationaccount.AutomationAccountCreateOrUpdateParameters{ + Properties: &automationaccount.AutomationAccountCreateOrUpdateProperties{ + Sku: &automationaccount.Sku{ + Name: automationaccount.SkuNameEnum(d.Get("sku_name").(string)), }, PublicNetworkAccess: utils.Bool(d.Get("public_network_access_enabled").(bool)), }, Location: utils.String(location.Normalize(d.Get("location").(string))), - Identity: identity, - Tags: tags.Expand(d.Get("tags").(map[string]interface{})), } - if _, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.Name, parameters); err != nil { + if localAuth := d.Get("local_authentication_enabled").(bool); localAuth == false { + parameters.Properties.DisableLocalAuth = utils.Bool(true) + } + if encryption := d.Get("encryption").([]interface{}); len(encryption) > 0 { + enc, err := expandEncryption(encryption[0].(map[string]interface{})) + if err != nil { + return fmt.Errorf("expanding `encryption`: %v", err) + } + parameters.Properties.Encryption = enc + } + // for create account do not set identity property (even TypeNone is not allowed), or api will response error + if identityVal.Type != identity.TypeNone { + parameters.Identity = identityVal + } + if tagsVal := expandTags(d.Get("tags").(map[string]interface{})); tagsVal != nil { + parameters.Tags = &tagsVal + } + + if _, err := client.CreateOrUpdate(ctx, id, parameters); err != nil { return fmt.Errorf("creating %s: %+v", id, err) } @@ -133,27 +203,42 @@ func resourceAutomationAccountUpdate(d *pluginsdk.ResourceData, meta interface{} ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.AutomationAccountID(d.Id()) + id, err := automationaccount.ParseAutomationAccountID(d.Id()) if err != nil { return err } - identity, err := expandAutomationAccountIdentity(d.Get("identity").([]interface{}), false) + identity, err := identity.ExpandSystemAndUserAssignedMap(d.Get("identity").([]interface{})) if err != nil { return fmt.Errorf("expanding `identity`: %+v", err) } - parameters := automation.AccountUpdateParameters{ - AccountUpdateProperties: &automation.AccountUpdateProperties{ - Sku: &automation.Sku{ - Name: automation.SkuNameEnum(d.Get("sku_name").(string)), + parameters := automationaccount.AutomationAccountUpdateParameters{ + Properties: &automationaccount.AutomationAccountUpdateProperties{ + Sku: &automationaccount.Sku{ + Name: automationaccount.SkuNameEnum(d.Get("sku_name").(string)), }, PublicNetworkAccess: utils.Bool(d.Get("public_network_access_enabled").(bool)), }, Location: utils.String(location.Normalize(d.Get("location").(string))), Identity: identity, - Tags: tags.Expand(d.Get("tags").(map[string]interface{})), } - if _, err := client.Update(ctx, id.ResourceGroup, id.Name, parameters); err != nil { + if localAuth := d.Get("local_authentication_enabled").(bool); localAuth == false { + parameters.Properties.DisableLocalAuth = utils.Bool(true) + } + + if encryption := d.Get("encryption").([]interface{}); len(encryption) > 0 { + enc, err := expandEncryption(encryption[0].(map[string]interface{})) + if err != nil { + return fmt.Errorf("expanding `encryption`: %v", err) + } + parameters.Properties.Encryption = enc + } + + if tagsVal := expandTags(d.Get("tags").(map[string]interface{})); tagsVal != nil { + parameters.Tags = &tagsVal + } + + if _, err := client.Update(ctx, *id, parameters); err != nil { return fmt.Errorf("updating %s: %+v", *id, err) } @@ -166,14 +251,14 @@ func resourceAutomationAccountRead(d *pluginsdk.ResourceData, meta interface{}) ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.AutomationAccountID(d.Id()) + id, err := automationaccount.ParseAutomationAccountID(d.Id()) if err != nil { return err } - resp, err := client.Get(ctx, id.ResourceGroup, id.Name) + resp, err := client.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { log.Printf("[DEBUG] %s was not found - removing from state!", *id) d.SetId("") return nil @@ -182,9 +267,9 @@ func resourceAutomationAccountRead(d *pluginsdk.ResourceData, meta interface{}) return fmt.Errorf("retrieving %s: %+v", *id, err) } - keysResp, err := registrationClient.Get(ctx, id.ResourceGroup, id.Name) + keysResp, err := registrationClient.Get(ctx, id.ResourceGroupName, id.AutomationAccountName) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { log.Printf("[DEBUG] Agent Registration Info for %s was not found - removing from state!", *id) d.SetId("") return nil @@ -193,27 +278,42 @@ func resourceAutomationAccountRead(d *pluginsdk.ResourceData, meta interface{}) return fmt.Errorf("retrieving Registration Info for %s: %+v", *id, err) } - d.Set("name", id.Name) - d.Set("resource_group_name", id.ResourceGroup) - d.Set("location", location.NormalizeNilable(resp.Location)) + d.Set("name", id.AutomationAccountName) + d.Set("resource_group_name", id.ResourceGroupName) + + d.Set("location", location.NormalizeNilable(resp.Model.Location)) publicNetworkAccessEnabled := true - if resp.PublicNetworkAccess != nil { - publicNetworkAccessEnabled = *resp.PublicNetworkAccess + if resp.Model == nil || resp.Model.Properties == nil { + return fmt.Errorf("retrieving Automation Account got empty Model") + } + prop := resp.Model.Properties + if prop.PublicNetworkAccess != nil { + publicNetworkAccessEnabled = *prop.PublicNetworkAccess } d.Set("public_network_access_enabled", publicNetworkAccessEnabled) skuName := "" - if sku := resp.Sku; sku != nil { - skuName = string(resp.Sku.Name) + if sku := prop.Sku; sku != nil { + skuName = string(prop.Sku.Name) } d.Set("sku_name", skuName) + localAuthEnabled := true + if val := prop.DisableLocalAuth; val != nil && *val == true { + localAuthEnabled = false + } + d.Set("local_authentication_enabled", localAuthEnabled) + + if err := d.Set("encryption", flattenEncryption(prop.Encryption)); err != nil { + return fmt.Errorf("setting `encryption`: %+v", err) + } + d.Set("dsc_server_endpoint", keysResp.Endpoint) if keys := keysResp.Keys; keys != nil { d.Set("dsc_primary_access_key", keys.Primary) d.Set("dsc_secondary_access_key", keys.Secondary) } - identity, err := flattenAutomationAccountIdentity(resp.Identity) + identity, err := identity.FlattenSystemAndUserAssignedMap(resp.Model.Identity) if err != nil { return fmt.Errorf("flattening `identity`: %+v", err) } @@ -221,7 +321,14 @@ func resourceAutomationAccountRead(d *pluginsdk.ResourceData, meta interface{}) return fmt.Errorf("setting `identity`: %+v", err) } - return tags.FlattenAndSet(d, resp.Tags) + if resp.Model != nil && resp.Model.Properties != nil { + d.Set("private_endpoint_connection", flattenPrivateEndpointConnections(resp.Model.Properties.PrivateEndpointConnections)) + } + + if resp.Model.Tags != nil { + return flattenAndSetTags(d, *resp.Model.Tags) + } + return nil } func resourceAutomationAccountDelete(d *pluginsdk.ResourceData, meta interface{}) error { @@ -229,14 +336,14 @@ func resourceAutomationAccountDelete(d *pluginsdk.ResourceData, meta interface{} ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.AutomationAccountID(d.Id()) + id, err := automationaccount.ParseAutomationAccountID(d.Id()) if err != nil { return err } - resp, err := client.Delete(ctx, id.ResourceGroup, id.Name) + resp, err := client.Delete(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp) { + if response.WasNotFound(resp.HttpResponse) { return nil } @@ -246,57 +353,50 @@ func resourceAutomationAccountDelete(d *pluginsdk.ResourceData, meta interface{} return nil } -func expandAutomationAccountIdentity(input []interface{}, newResource bool) (*automation.Identity, error) { - expanded, err := identity.ExpandSystemAndUserAssignedMap(input) - if err != nil { - return nil, err +func expandEncryption(encMap map[string]interface{}) (*automationaccount.EncryptionProperties, error) { + var id interface{} + id, ok := encMap["user_assigned_identity_id"].(string) + if !ok { + return nil, fmt.Errorf("read encryption user identity id error") } - - if newResource && expanded.Type == identity.TypeNone { - return nil, nil + prop := &automationaccount.EncryptionProperties{ + Identity: &automationaccount.EncryptionPropertiesIdentity{ + UserAssignedIdentity: &id, + }, } - - out := automation.Identity{ - Type: automation.ResourceIdentityType(string(expanded.Type)), + if val, ok := encMap["key_source"].(string); ok && val != "" { + prop.KeySource = (*automationaccount.EncryptionKeySourceType)(&val) } - - if len(expanded.IdentityIds) > 0 { - ids := make(map[string]*automation.IdentityUserAssignedIdentitiesValue) - - for k := range expanded.IdentityIds { - ids[k] = &automation.IdentityUserAssignedIdentitiesValue{ - // intentionally empty - } + if keyIdStr := encMap["key_vault_key_id"].(string); keyIdStr != "" { + keyId, err := keyVaultParse.ParseOptionallyVersionedNestedItemID(keyIdStr) + if err != nil { + return nil, err + } + prop.KeyVaultProperties = &automationaccount.KeyVaultProperties{ + KeyName: utils.String(keyId.Name), + KeyVersion: utils.String(keyId.Version), + KeyvaultUri: utils.String(keyId.KeyVaultBaseUrl), } - - out.UserAssignedIdentities = ids } - - return &out, nil + return prop, nil } -func flattenAutomationAccountIdentity(input *automation.Identity) (*[]interface{}, error) { - var transformed *identity.SystemAndUserAssignedMap - if input != nil { - transformed = &identity.SystemAndUserAssignedMap{ - Type: identity.Type(string(input.Type)), - IdentityIds: make(map[string]identity.UserAssignedIdentityDetails), - } - if input.PrincipalID != nil { - transformed.PrincipalId = *input.PrincipalID - } - if input.TenantID != nil { - transformed.TenantId = *input.TenantID - } - if input.UserAssignedIdentities != nil { - for k, v := range input.UserAssignedIdentities { - transformed.IdentityIds[k] = identity.UserAssignedIdentityDetails{ - ClientId: v.ClientID, - PrincipalId: v.PrincipalID, - } - } +func flattenEncryption(encryption *automationaccount.EncryptionProperties) (res []interface{}) { + if encryption == nil { + return + } + item := map[string]interface{}{} + if encryption.KeySource != nil { + item["key_source"] = (string)(*encryption.KeySource) + } + if encryption.Identity != nil && encryption.Identity.UserAssignedIdentity != nil { + item["user_assigned_identity_id"] = (*encryption.Identity.UserAssignedIdentity).(string) + } + if keyProp := encryption.KeyVaultProperties; keyProp != nil { + keyVaultKeyId, err := keyVaultParse.NewNestedItemID(*keyProp.KeyvaultUri, "keys", *keyProp.KeyName, *keyProp.KeyVersion) + if err == nil { + item["key_vault_key_id"] = keyVaultKeyId.ID() } } - - return identity.FlattenSystemAndUserAssignedMap(transformed) + return []interface{}{item} } diff --git a/internal/services/automation/automation_account_resource_test.go b/internal/services/automation/automation_account_resource_test.go index baad6de2efb6..bbf395aefceb 100644 --- a/internal/services/automation/automation_account_resource_test.go +++ b/internal/services/automation/automation_account_resource_test.go @@ -5,10 +5,11 @@ import ( "fmt" "testing" + "github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/automationaccount" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/automation/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -69,6 +70,24 @@ func TestAccAutomationAccount_complete(t *testing.T) { }) } +func TestAccAutomationAccount_encryption(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_automation_account", "test") + r := AutomationAccountResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.encryption(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("sku_name").HasValue("Basic"), + check.That(data.ResourceName).Key("local_authentication_enabled").HasValue("false"), + check.That(data.ResourceName).Key("encryption.0.key_source").HasValue("Microsoft.Keyvault"), + ), + }, + data.ImportStep(), + }) +} + func TestAccAutomationAccount_identityUpdate(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_automation_account", "test") r := AutomationAccountResource{} @@ -160,17 +179,17 @@ func TestAccAutomationAccount_userAssignedIdentity(t *testing.T) { } func (t AutomationAccountResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.AutomationAccountID(state.ID) + id, err := automationaccount.ParseAutomationAccountID(state.ID) if err != nil { return nil, err } - resp, err := clients.Automation.AccountClient.Get(ctx, id.ResourceGroup, id.Name) + resp, err := clients.Automation.AccountClient.Get(ctx, *id) if err != nil { - return nil, fmt.Errorf("retrieving Automation Account %q (resource group: %q): %+v", id.Name, id.ResourceGroup, err) + return nil, fmt.Errorf("retrieving Automation Account %q (resource group: %q): %+v", id.AutomationAccountName, id.ResourceGroupName, err) } - return utils.Bool(resp.AccountProperties != nil), nil + return utils.Bool(resp.Model.Properties != nil), nil } func (AutomationAccountResource) basic(data acceptance.TestData) string { @@ -256,6 +275,123 @@ resource "azurerm_automation_account" "test" { `, data.RandomInteger, data.Locations.Primary) } +func (AutomationAccountResource) encryption(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features { + key_vault { + purge_soft_delete_on_destroy = false + purge_soft_deleted_keys_on_destroy = false + } + } +} + +data "azurerm_client_config" "current" { +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-auto-%[1]d" + location = "%[2]s" +} + +resource "azurerm_user_assigned_identity" "test" { + name = "acctestUAI-%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_key_vault" "test" { + name = "vault%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + tenant_id = data.azurerm_client_config.current.tenant_id + sku_name = "standard" + soft_delete_retention_days = 7 + purge_protection_enabled = true + + access_policy { + tenant_id = data.azurerm_client_config.current.tenant_id + object_id = data.azurerm_client_config.current.object_id + + certificate_permissions = [ + "ManageContacts", + ] + + key_permissions = [ + "Create", + "Get", + "List", + "Delete", + "Purge", + ] + + secret_permissions = [ + "Set", + ] + } + + access_policy { + tenant_id = azurerm_user_assigned_identity.test.tenant_id + object_id = azurerm_user_assigned_identity.test.principal_id + + certificate_permissions = [] + + key_permissions = [ + "Get", + "Recover", + "WrapKey", + "UnwrapKey", + ] + + secret_permissions = [] + } +} + +data "azurerm_key_vault" "test" { + name = azurerm_key_vault.test.name + resource_group_name = azurerm_key_vault.test.resource_group_name +} + +resource "azurerm_key_vault_key" "test" { + name = "acckvkey-%[1]d" + key_vault_id = azurerm_key_vault.test.id + key_type = "RSA" + key_size = 2048 + + key_opts = [ + "decrypt", + "encrypt", + "sign", + "unwrapKey", + "verify", + "wrapKey", + ] +} + +resource "azurerm_automation_account" "test" { + name = "acctest-%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku_name = "Basic" + + identity { + type = "UserAssigned" + identity_ids = [ + azurerm_user_assigned_identity.test.id + ] + } + + local_authentication_enabled = false + + encryption { + key_source = "Microsoft.Keyvault" + user_assigned_identity_id = azurerm_user_assigned_identity.test.id + key_vault_key_id = azurerm_key_vault_key.test.id + } +} +`, data.RandomInteger, data.Locations.Primary) +} + func (AutomationAccountResource) userAssignedIdentity(data acceptance.TestData) string { return fmt.Sprintf(` provider "azurerm" { diff --git a/internal/services/automation/automation_connection_type_resource.go b/internal/services/automation/automation_connection_type_resource.go new file mode 100644 index 000000000000..347b082d1b91 --- /dev/null +++ b/internal/services/automation/automation_connection_type_resource.go @@ -0,0 +1,211 @@ +package automation + +import ( + "context" + "fmt" + "time" + + "github.com/Azure/azure-sdk-for-go/services/preview/automation/mgmt/2020-01-13-preview/automation" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/automationaccount" + "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" + "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/automation/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/automation/validate" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type Field struct { + Name string `tfschema:"name"` + IsOptional bool `tfschema:"is_optional"` + IsEncrypted bool `tfschema:"is_encrypted"` + Type string `tfschema:"type"` +} + +type AutomationConnectionTypeModel struct { + ResourceGrup string `json:"resource_grup" tfschema:"resource_group_name"` + AutomationAccountName string `json:"automation_account_name" tfschema:"automation_account_name"` + Name string `json:"name" tfschema:"name"` + IsGlobal bool `json:"is_global" tfschema:"is_global"` + Field []Field `json:"field" tfschema:"field"` +} + +type AutomationConnectionTypeResource struct{} + +var _ sdk.Resource = (*AutomationConnectionTypeResource)(nil) + +func (m AutomationConnectionTypeResource) Arguments() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "resource_group_name": azure.SchemaResourceGroupName(), + + "automation_account_name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.AutomationAccount(), + }, + + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.ConnectionTypeName, + }, + + "is_global": { + Type: pluginsdk.TypeBool, + Optional: true, + ForceNew: true, + }, + + "field": { + Type: pluginsdk.TypeList, + Required: true, + ForceNew: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + }, + "is_encrypted": { + Type: pluginsdk.TypeBool, + Optional: true, + }, + "is_optional": { + Type: pluginsdk.TypeBool, + Optional: true, + }, + "type": { + Type: pluginsdk.TypeString, + Required: true, + }, + }, + }, + }, + } +} + +func (m AutomationConnectionTypeResource) Attributes() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{} +} + +func (m AutomationConnectionTypeResource) ModelObject() interface{} { + return &AutomationConnectionTypeModel{} +} + +func (m AutomationConnectionTypeResource) ResourceType() string { + return "azurerm_automation_connection_type" +} + +func (m AutomationConnectionTypeResource) Create() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, meta sdk.ResourceMetaData) error { + client := meta.Client.Automation.ConnectionTypeClient + connClient := meta.Client.Automation.AccountClient + + var model AutomationConnectionTypeModel + if err := meta.Decode(&model); err != nil { + return err + } + subscriptionID := meta.Client.Account.SubscriptionId + + accountID := automationaccount.NewAutomationAccountID(subscriptionID, model.ResourceGrup, model.AutomationAccountName) + account, err := connClient.Get(ctx, accountID) + if err != nil { + return fmt.Errorf("retrieving automation account %q: %+v", accountID, err) + } + if response.WasNotFound(account.HttpResponse) { + return fmt.Errorf("automation account %q was not found", accountID) + } + + id := parse.NewConnectionTypeID(accountID.SubscriptionId, model.ResourceGrup, model.AutomationAccountName, model.Name) + existing, err := client.Get(ctx, id.ResourceGroup, model.AutomationAccountName, model.Name) + if !utils.ResponseWasNotFound(existing.Response) { + if err != nil { + return fmt.Errorf("retreiving %s: %v", id, err) + } + return meta.ResourceRequiresImport(m.ResourceType(), id) + } + param := automation.ConnectionTypeCreateOrUpdateParameters{ + Name: utils.String(model.Name), + ConnectionTypeCreateOrUpdateProperties: &automation.ConnectionTypeCreateOrUpdateProperties{ + IsGlobal: utils.Bool(model.IsGlobal), + FieldDefinitions: map[string]*automation.FieldDefinition{}, + }, + } + for _, field := range model.Field { + param.ConnectionTypeCreateOrUpdateProperties.FieldDefinitions[field.Name] = &automation.FieldDefinition{ + IsEncrypted: utils.Bool(field.IsEncrypted), + IsOptional: utils.Bool(field.IsOptional), + Type: utils.String(field.Type), + } + } + _, err = client.CreateOrUpdate(ctx, id.ResourceGroup, id.AutomationAccountName, id.Name, param) + if err != nil { + return fmt.Errorf("creating %s: %v", id, err) + } + + meta.SetID(id) + return nil + }, + } +} + +func (m AutomationConnectionTypeResource) Read() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 5 * time.Minute, + Func: func(ctx context.Context, meta sdk.ResourceMetaData) error { + id, err := parse.ConnectionTypeID(meta.ResourceData.Id()) + if err != nil { + return err + } + + client := meta.Client.Automation.ConnectionTypeClient + result, err := client.Get(ctx, id.ResourceGroup, id.AutomationAccountName, id.Name) + if err != nil { + return err + } + + var output AutomationConnectionTypeModel + output.IsGlobal = utils.NormaliseNilableBool(result.IsGlobal) + output.Name = utils.NormalizeNilableString(result.Name) + output.AutomationAccountName = id.AutomationAccountName + output.ResourceGrup = id.ResourceGroup + for name, prop := range result.FieldDefinitions { + output.Field = append(output.Field, Field{ + Name: name, + Type: utils.NormalizeNilableString(prop.Type), + IsEncrypted: utils.NormaliseNilableBool(prop.IsEncrypted), + IsOptional: utils.NormaliseNilableBool(prop.IsOptional), + }) + } + + return meta.Encode(&output) + }, + } +} + +func (m AutomationConnectionTypeResource) Delete() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 10 * time.Minute, + Func: func(ctx context.Context, meta sdk.ResourceMetaData) error { + id, err := parse.ConnectionTypeID(meta.ResourceData.Id()) + if err != nil { + return err + } + + client := meta.Client.Automation.ConnectionTypeClient + if _, err = client.Delete(ctx, id.ResourceGroup, id.AutomationAccountName, id.Name); err != nil { + return fmt.Errorf("deleting %s: %v", id, err) + } + return nil + }, + } +} + +func (m AutomationConnectionTypeResource) IDValidationFunc() pluginsdk.SchemaValidateFunc { + return validate.ConnectionTypeID +} diff --git a/internal/services/automation/automation_connection_type_resource_test.go b/internal/services/automation/automation_connection_type_resource_test.go new file mode 100644 index 000000000000..cd9dc3b16b17 --- /dev/null +++ b/internal/services/automation/automation_connection_type_resource_test.go @@ -0,0 +1,83 @@ +package automation_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/automation" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/automation/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type AutomationConnectionTypeResource struct{} + +func (a AutomationConnectionTypeResource) Exists(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + id, err := parse.ConnectionTypeID(state.ID) + if err != nil { + return nil, err + } + resp, err := client.Automation.ConnectionTypeClient.Get(ctx, id.ResourceGroup, id.AutomationAccountName, id.Name) + if err != nil { + return nil, fmt.Errorf("retrieving Automation Connection Type %s: %+v", id, err) + } + return utils.Bool(resp.ConnectionTypeProperties != nil), nil +} + +func (a AutomationConnectionTypeResource) template(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-auto-%[1]d" + location = "%[2]s" +} + +resource "azurerm_automation_account" "test" { + name = "acctest-%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku_name = "Basic" +} +`, data.RandomInteger, data.Locations.Primary) +} + +func (a AutomationConnectionTypeResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` + + +%s + +resource "azurerm_automation_connection_type" "test" { + name = "acctest-%[2]d" + resource_group_name = azurerm_resource_group.test.name + automation_account_name = azurerm_automation_account.test.name + is_global = false + field { + name = "my_def" + type = "string" + } +} +`, a.template(data), data.RandomInteger) +} + +func TestAccAutomationConnectionType_basic(t *testing.T) { + data := acceptance.BuildTestData(t, automation.AutomationConnectionTypeResource{}.ResourceType(), "test") + r := AutomationConnectionTypeResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("is_global").HasValue("false"), + ), + }, + data.ImportStep(), + }) +} diff --git a/internal/services/automation/automation_hybrid_runbook_worker_group.go b/internal/services/automation/automation_hybrid_runbook_worker_group.go new file mode 100644 index 000000000000..3bc5c1ea142b --- /dev/null +++ b/internal/services/automation/automation_hybrid_runbook_worker_group.go @@ -0,0 +1,180 @@ +package automation + +import ( + "context" + "fmt" + "net/http" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/hybridrunbookworkergroup" + "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type HybridRunbookWorkerGroupModel struct { + ResourceGroupName string `tfschema:"resource_group_name"` + AutomationAccountName string `tfschema:"automation_account_name"` + Name string `tfschema:"name"` + CredentialName string `tfschema:"credential_name"` +} + +type HybridRunbookWorkerGroupResource struct{} + +var _ sdk.Resource = (*HybridRunbookWorkerGroupResource)(nil) + +func (m HybridRunbookWorkerGroupResource) Arguments() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "resource_group_name": commonschema.ResourceGroupName(), // end if common + "automation_account_name": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + "name": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + "credential_name": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + } +} + +func (m HybridRunbookWorkerGroupResource) Attributes() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{} +} + +func (m HybridRunbookWorkerGroupResource) ModelObject() interface{} { + return &HybridRunbookWorkerGroupModel{} +} + +func (m HybridRunbookWorkerGroupResource) ResourceType() string { + return "azurerm_automation_hybrid_runbook_worker_group" +} + +func (m HybridRunbookWorkerGroupResource) Create() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, meta sdk.ResourceMetaData) error { + client := meta.Client.Automation.RunBookWgClient + + var model HybridRunbookWorkerGroupModel + if err := meta.Decode(&model); err != nil { + return err + } + + subscriptionID := meta.Client.Account.SubscriptionId + id := hybridrunbookworkergroup.NewHybridRunbookWorkerGroupID(subscriptionID, model.ResourceGroupName, + model.AutomationAccountName, model.Name) + existing, err := client.Get(ctx, id) + if !response.WasNotFound(existing.HttpResponse) { + if err != nil { + return fmt.Errorf("retreiving %s: %v", id, err) + } + return meta.ResourceRequiresImport(m.ResourceType(), id) + } + req := hybridrunbookworkergroup.HybridRunbookWorkerGroupCreateOrUpdateParameters{} + if model.CredentialName != "" { + req.Credential = &hybridrunbookworkergroup.RunAsCredentialAssociationProperty{ + Name: utils.String(model.CredentialName), + } + } + // return 201 cause err in autorest sdk + future, err := client.Create(ctx, id, req) + if err != nil && !response.WasStatusCode(future.HttpResponse, http.StatusCreated) { + return fmt.Errorf("creating %s: %v", id, err) + } + + meta.SetID(id) + return nil + }, + } +} + +func (m HybridRunbookWorkerGroupResource) Read() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 5 * time.Minute, + Func: func(ctx context.Context, meta sdk.ResourceMetaData) error { + id, err := hybridrunbookworkergroup.ParseHybridRunbookWorkerGroupID(meta.ResourceData.Id()) + if err != nil { + return err + } + client := meta.Client.Automation.RunBookWgClient + result, err := client.Get(ctx, *id) + if err != nil { + return err + } + if result.Model == nil { + return fmt.Errorf("retrieving %s got nil model", id) + } + var output HybridRunbookWorkerGroupModel + + output.Name = utils.NormalizeNilableString(result.Model.Name) + output.AutomationAccountName = id.AutomationAccountName + if c := result.Model.Credential; c != nil { + output.CredentialName = utils.NormalizeNilableString(c.Name) + } + output.ResourceGroupName = id.ResourceGroupName + return meta.Encode(&output) + }, + } +} + +func (m HybridRunbookWorkerGroupResource) Update() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 10 * time.Minute, + Func: func(ctx context.Context, meta sdk.ResourceMetaData) (err error) { + client := meta.Client.Automation.RunBookWgClient + id, err := hybridrunbookworkergroup.ParseHybridRunbookWorkerGroupID(meta.ResourceData.Id()) + if err != nil { + return err + } + + var model HybridRunbookWorkerGroupModel + if err = meta.Decode(&model); err != nil { + return fmt.Errorf("decoding err: %+v", err) + } + + var upd hybridrunbookworkergroup.HybridRunbookWorkerGroupCreateOrUpdateParameters + if meta.ResourceData.HasChange("credential_name") { + upd.Credential = &hybridrunbookworkergroup.RunAsCredentialAssociationProperty{ + Name: utils.String(model.CredentialName), + } + } + if _, err = client.Update(ctx, *id, upd); err != nil { + return fmt.Errorf("updating %s: %v", id, err) + } + + return nil + }, + } +} + +func (m HybridRunbookWorkerGroupResource) Delete() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 10 * time.Minute, + Func: func(ctx context.Context, meta sdk.ResourceMetaData) error { + id, err := hybridrunbookworkergroup.ParseHybridRunbookWorkerGroupID(meta.ResourceData.Id()) + if err != nil { + return err + } + meta.Logger.Infof("deleting %s", id) + client := meta.Client.Automation.RunBookWgClient + if _, err = client.Delete(ctx, *id); err != nil { + return fmt.Errorf("deleting %s: %v", id, err) + } + return nil + }, + } +} + +func (m HybridRunbookWorkerGroupResource) IDValidationFunc() pluginsdk.SchemaValidateFunc { + return hybridrunbookworkergroup.ValidateHybridRunbookWorkerGroupID +} diff --git a/internal/services/automation/automation_hybrid_runbook_worker_group_test.go b/internal/services/automation/automation_hybrid_runbook_worker_group_test.go new file mode 100644 index 000000000000..956b849ef8ab --- /dev/null +++ b/internal/services/automation/automation_hybrid_runbook_worker_group_test.go @@ -0,0 +1,129 @@ +package automation_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/hybridrunbookworkergroup" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/automation" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type HybridRunbookWorkerGroupResource struct{} + +func (a HybridRunbookWorkerGroupResource) Exists(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + id, err := hybridrunbookworkergroup.ParseHybridRunbookWorkerGroupID(state.ID) + if err != nil { + return nil, err + } + resp, err := client.Automation.RunBookWgClient.Get(ctx, *id) + if err != nil { + return nil, fmt.Errorf("retrieving HybridRunbookWorkerGroup %s: %+v", id, err) + } + return utils.Bool(resp.Model != nil), nil +} + +func (a HybridRunbookWorkerGroupResource) template(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-auto-%[1]d" + location = "%[2]s" +} + +resource "azurerm_automation_account" "test" { + name = "acctestAA-%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku_name = "Basic" +} + +resource "azurerm_automation_credential" "test" { + name = "acctest-%[1]d" + resource_group_name = azurerm_resource_group.test.name + automation_account_name = azurerm_automation_account.test.name + username = "test_user" + password = "test_pwd" +} +`, data.RandomInteger, data.Locations.Primary) +} + +func (a HybridRunbookWorkerGroupResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` + + +%s + +resource "azurerm_automation_hybrid_runbook_worker_group" "test" { + resource_group_name = azurerm_resource_group.test.name + automation_account_name = azurerm_automation_account.test.name + name = "acctest-%[2]d" + credential_name = azurerm_automation_credential.test.name +} +`, a.template(data), data.RandomInteger, data.Locations.Primary) +} + +func (a HybridRunbookWorkerGroupResource) update(data acceptance.TestData) string { + return fmt.Sprintf(` + + +%s + +resource "azurerm_automation_credential" "test2" { + name = "acctest2-%d" + resource_group_name = azurerm_resource_group.test.name + automation_account_name = azurerm_automation_account.test.name + username = "test_user" + password = "test_pwd" +} + +resource "azurerm_automation_hybrid_runbook_worker_group" "test" { + resource_group_name = azurerm_resource_group.test.name + automation_account_name = azurerm_automation_account.test.name + name = "acctest-%[2]d" + credential_name = azurerm_automation_credential.test2.name +} +`, a.template(data), data.RandomInteger) +} + +func TestAccHybridRunbookWorkerGroup_basic(t *testing.T) { + data := acceptance.BuildTestData(t, automation.HybridRunbookWorkerGroupResource{}.ResourceType(), "test") + r := HybridRunbookWorkerGroupResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + }) +} + +func TestAccHybridRunbookWorkerGroup_update(t *testing.T) { + data := acceptance.BuildTestData(t, automation.HybridRunbookWorkerGroupResource{}.ResourceType(), "test") + r := HybridRunbookWorkerGroupResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.update(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} diff --git a/internal/services/automation/client/client.go b/internal/services/automation/client/client.go index ab9d59911c7c..689c2a94654e 100644 --- a/internal/services/automation/client/client.go +++ b/internal/services/automation/client/client.go @@ -2,11 +2,13 @@ package client import ( "github.com/Azure/azure-sdk-for-go/services/preview/automation/mgmt/2020-01-13-preview/automation" + "github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/automationaccount" + "github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/hybridrunbookworkergroup" "github.com/hashicorp/terraform-provider-azurerm/internal/common" ) type Client struct { - AccountClient *automation.AccountClient + AccountClient *automationaccount.AutomationAccountClient AgentRegistrationInfoClient *automation.AgentRegistrationInformationClient CertificateClient *automation.CertificateClient ConnectionClient *automation.ConnectionClient @@ -18,13 +20,14 @@ type Client struct { ModuleClient *automation.ModuleClient RunbookClient *automation.RunbookClient RunbookDraftClient *automation.RunbookDraftClient + RunBookWgClient *hybridrunbookworkergroup.HybridRunbookWorkerGroupClient ScheduleClient *automation.ScheduleClient VariableClient *automation.VariableClient WebhookClient *automation.WebhookClient } func NewClient(o *common.ClientOptions) *Client { - accountClient := automation.NewAccountClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + accountClient := automationaccount.NewAutomationAccountClientWithBaseURI(o.ResourceManagerEndpoint) o.ConfigureClient(&accountClient.Client, o.ResourceManagerAuthorizer) agentRegistrationInfoClient := automation.NewAgentRegistrationInformationClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) @@ -60,6 +63,9 @@ func NewClient(o *common.ClientOptions) *Client { runbookDraftClient := automation.NewRunbookDraftClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&runbookDraftClient.Client, o.ResourceManagerAuthorizer) + runbookWgClient := hybridrunbookworkergroup.NewHybridRunbookWorkerGroupClientWithBaseURI(o.ResourceManagerEndpoint) + o.ConfigureClient(&runbookWgClient.Client, o.ResourceManagerAuthorizer) + scheduleClient := automation.NewScheduleClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&scheduleClient.Client, o.ResourceManagerAuthorizer) @@ -82,6 +88,7 @@ func NewClient(o *common.ClientOptions) *Client { ModuleClient: &moduleClient, RunbookClient: &runbookClient, RunbookDraftClient: &runbookDraftClient, + RunBookWgClient: &runbookWgClient, ScheduleClient: &scheduleClient, VariableClient: &variableClient, WebhookClient: &webhookClient, diff --git a/internal/services/automation/parse/connection_type.go b/internal/services/automation/parse/connection_type.go new file mode 100644 index 000000000000..15d87fe68785 --- /dev/null +++ b/internal/services/automation/parse/connection_type.go @@ -0,0 +1,75 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + "strings" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +type ConnectionTypeId struct { + SubscriptionId string + ResourceGroup string + AutomationAccountName string + Name string +} + +func NewConnectionTypeID(subscriptionId, resourceGroup, automationAccountName, name string) ConnectionTypeId { + return ConnectionTypeId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + AutomationAccountName: automationAccountName, + Name: name, + } +} + +func (id ConnectionTypeId) String() string { + segments := []string{ + fmt.Sprintf("Name %q", id.Name), + fmt.Sprintf("Automation Account Name %q", id.AutomationAccountName), + fmt.Sprintf("Resource Group %q", id.ResourceGroup), + } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "Connection Type", segmentsStr) +} + +func (id ConnectionTypeId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Automation/automationAccounts/%s/connectionTypes/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.AutomationAccountName, id.Name) +} + +// ConnectionTypeID parses a ConnectionType ID into an ConnectionTypeId struct +func ConnectionTypeID(input string) (*ConnectionTypeId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := ConnectionTypeId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + if resourceId.AutomationAccountName, err = id.PopSegment("automationAccounts"); err != nil { + return nil, err + } + if resourceId.Name, err = id.PopSegment("connectionTypes"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} diff --git a/internal/services/automation/parse/connection_type_test.go b/internal/services/automation/parse/connection_type_test.go new file mode 100644 index 000000000000..6efb7ac7047a --- /dev/null +++ b/internal/services/automation/parse/connection_type_test.go @@ -0,0 +1,128 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "testing" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +var _ resourceids.Id = ConnectionTypeId{} + +func TestConnectionTypeIDFormatter(t *testing.T) { + actual := NewConnectionTypeID("12345678-1234-9876-4563-123456789012", "group1", "account1", "type1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Automation/automationAccounts/account1/connectionTypes/type1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestConnectionTypeID(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *ConnectionTypeId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing AutomationAccountName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Automation/", + Error: true, + }, + + { + // missing value for AutomationAccountName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Automation/automationAccounts/", + Error: true, + }, + + { + // missing Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Automation/automationAccounts/account1/", + Error: true, + }, + + { + // missing value for Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Automation/automationAccounts/account1/connectionTypes/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Automation/automationAccounts/account1/connectionTypes/type1", + Expected: &ConnectionTypeId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "group1", + AutomationAccountName: "account1", + Name: "type1", + }, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/GROUP1/PROVIDERS/MICROSOFT.AUTOMATION/AUTOMATIONACCOUNTS/ACCOUNT1/CONNECTIONTYPES/TYPE1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := ConnectionTypeID(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.AutomationAccountName != v.Expected.AutomationAccountName { + t.Fatalf("Expected %q but got %q for AutomationAccountName", v.Expected.AutomationAccountName, actual.AutomationAccountName) + } + if actual.Name != v.Expected.Name { + t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name) + } + } +} diff --git a/internal/services/automation/registration.go b/internal/services/automation/registration.go index aade13c936ed..b3d3cc41487b 100644 --- a/internal/services/automation/registration.go +++ b/internal/services/automation/registration.go @@ -8,6 +8,18 @@ import ( type Registration struct{} var _ sdk.UntypedServiceRegistrationWithAGitHubLabel = Registration{} +var _ sdk.TypedServiceRegistrationWithAGitHubLabel = Registration{} + +func (r Registration) DataSources() []sdk.DataSource { + return []sdk.DataSource{} +} + +func (r Registration) Resources() []sdk.Resource { + return []sdk.Resource{ + AutomationConnectionTypeResource{}, + HybridRunbookWorkerGroupResource{}, + } +} func (r Registration) AssociatedGitHubLabel() string { return "service/automation" diff --git a/internal/services/automation/resourceids.go b/internal/services/automation/resourceids.go index e73f570e098b..55b7f0fdd235 100644 --- a/internal/services/automation/resourceids.go +++ b/internal/services/automation/resourceids.go @@ -1,6 +1,7 @@ package automation //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Connection -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Automation/automationAccounts/account1/connections/connection1 +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ConnectionType -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Automation/automationAccounts/account1/connectionTypes/type1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=AutomationAccount -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Automation/automationAccounts/account1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Certificate -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Automation/automationAccounts/account1/certificates/cert1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Credential -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Automation/automationAccounts/account1/credentials/cred1 diff --git a/internal/services/automation/transition.go b/internal/services/automation/transition.go new file mode 100644 index 000000000000..abffe49b9038 --- /dev/null +++ b/internal/services/automation/transition.go @@ -0,0 +1,50 @@ +package automation + +import ( + "fmt" + + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" +) + +func tagValueToString(v interface{}) (string, error) { + switch value := v.(type) { + case string: + return value, nil + case int: + return fmt.Sprintf("%d", value), nil + default: + return "", fmt.Errorf("unknown tag type %T in tag value", value) + } +} + +func expandTags(tagsMap map[string]interface{}) map[string]string { + output := make(map[string]string, len(tagsMap)) + + for i, v := range tagsMap { + // Validate should have ignored this error already + value, _ := tagValueToString(v) + output[i] = value + } + + return output +} + +func flattenTags(tagMap map[string]string) map[string]interface{} { + // If tagsMap is nil, len(tagsMap) will be 0. + output := make(map[string]interface{}, len(tagMap)) + + for i, v := range tagMap { + output[i] = v + } + + return output +} + +func flattenAndSetTags(d *pluginsdk.ResourceData, tagMap map[string]string) error { + flattened := flattenTags(tagMap) + if err := d.Set("tags", flattened); err != nil { + return fmt.Errorf("setting `tags`: %s", err) + } + + return nil +} diff --git a/internal/services/automation/validate/connection_type_id.go b/internal/services/automation/validate/connection_type_id.go new file mode 100644 index 000000000000..bc9a00066983 --- /dev/null +++ b/internal/services/automation/validate/connection_type_id.go @@ -0,0 +1,23 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + + "github.com/hashicorp/terraform-provider-azurerm/internal/services/automation/parse" +) + +func ConnectionTypeID(input interface{}, key string) (warnings []string, errors []error) { + v, ok := input.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected %q to be a string", key)) + return + } + + if _, err := parse.ConnectionTypeID(v); err != nil { + errors = append(errors, err) + } + + return +} diff --git a/internal/services/automation/validate/connection_type_id_test.go b/internal/services/automation/validate/connection_type_id_test.go new file mode 100644 index 000000000000..ba083425d8d5 --- /dev/null +++ b/internal/services/automation/validate/connection_type_id_test.go @@ -0,0 +1,88 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import "testing" + +func TestConnectionTypeID(t *testing.T) { + cases := []struct { + Input string + Valid bool + }{ + + { + // empty + Input: "", + Valid: false, + }, + + { + // missing SubscriptionId + Input: "/", + Valid: false, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Valid: false, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Valid: false, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Valid: false, + }, + + { + // missing AutomationAccountName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Automation/", + Valid: false, + }, + + { + // missing value for AutomationAccountName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Automation/automationAccounts/", + Valid: false, + }, + + { + // missing Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Automation/automationAccounts/account1/", + Valid: false, + }, + + { + // missing value for Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Automation/automationAccounts/account1/connectionTypes/", + Valid: false, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Automation/automationAccounts/account1/connectionTypes/type1", + Valid: true, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/GROUP1/PROVIDERS/MICROSOFT.AUTOMATION/AUTOMATIONACCOUNTS/ACCOUNT1/CONNECTIONTYPES/TYPE1", + Valid: false, + }, + } + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.Input) + _, errors := ConnectionTypeID(tc.Input, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} diff --git a/internal/services/automation/validate/connection_type_name.go b/internal/services/automation/validate/connection_type_name.go new file mode 100644 index 000000000000..8a02e48ddceb --- /dev/null +++ b/internal/services/automation/validate/connection_type_name.go @@ -0,0 +1,19 @@ +package validate + +import ( + "fmt" + "regexp" +) + +func ConnectionTypeName(i interface{}, k string) (_ []string, errors []error) { + v, ok := i.(string) + if !ok { + return nil, append(errors, fmt.Errorf("expected type of %s to be string", k)) + } + + if !regexp.MustCompile(`^[\w\-]{1,128}$`).MatchString(v) { + errors = append(errors, fmt.Errorf("%s contain only letters, numbers hyphens and underscore. The value must be between 1 and 128 characters long", k)) + } + + return nil, errors +} diff --git a/internal/services/batch/batch_account_data_source_test.go b/internal/services/batch/batch_account_data_source_test.go index e42cd7cba39a..deb30a1e0c4b 100644 --- a/internal/services/batch/batch_account_data_source_test.go +++ b/internal/services/batch/batch_account_data_source_test.go @@ -125,11 +125,12 @@ resource "azurerm_storage_account" "test" { } resource "azurerm_batch_account" "test" { - name = "testaccbatch%s" - resource_group_name = azurerm_resource_group.test.name - location = azurerm_resource_group.test.location - pool_allocation_mode = "BatchService" - storage_account_id = azurerm_storage_account.test.id + name = "testaccbatch%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + pool_allocation_mode = "BatchService" + storage_account_id = azurerm_storage_account.test.id + storage_account_authentication_mode = "StorageKeys" tags = { env = "test" @@ -246,11 +247,12 @@ resource "azurerm_user_assigned_identity" "test" { } resource "azurerm_batch_account" "test" { - name = "testaccbatch%s" - resource_group_name = azurerm_resource_group.test.name - location = azurerm_resource_group.test.location - pool_allocation_mode = "BatchService" - storage_account_id = azurerm_storage_account.test.id + name = "testaccbatch%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + pool_allocation_mode = "BatchService" + storage_account_id = azurerm_storage_account.test.id + storage_account_authentication_mode = "StorageKeys" identity { type = "UserAssigned" identity_ids = [azurerm_user_assigned_identity.test.id] diff --git a/internal/services/batch/batch_account_resource.go b/internal/services/batch/batch_account_resource.go index 5aedcd47bfda..e2d2df2a78b8 100644 --- a/internal/services/batch/batch_account_resource.go +++ b/internal/services/batch/batch_account_resource.go @@ -3,10 +3,12 @@ package batch import ( "fmt" "log" + "strings" "time" "github.com/Azure/azure-sdk-for-go/services/batch/mgmt/2022-01-01/batch" "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/identity" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" @@ -58,6 +60,38 @@ func resourceBatchAccount() *pluginsdk.Resource { Type: pluginsdk.TypeString, Optional: true, ValidateFunc: storageValidate.StorageAccountID, + RequiredWith: []string{"storage_account_authentication_mode"}, + }, + + "storage_account_authentication_mode": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + string(batch.AutoStorageAuthenticationModeStorageKeys), + string(batch.AutoStorageAuthenticationModeBatchAccountManagedIdentity), + }, false), + RequiredWith: []string{"storage_account_id"}, + }, + + "storage_account_node_identity": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: commonids.ValidateUserAssignedIdentityID, + RequiredWith: []string{"storage_account_id"}, + }, + + "allowed_authentication_modes": { + Type: pluginsdk.TypeSet, + Optional: true, + Computed: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringInSlice([]string{ + string(batch.AuthenticationModeSharedKey), + string(batch.AuthenticationModeAAD), + string(batch.AuthenticationModeTaskAuthenticationToken), + }, false), + }, }, "pool_allocation_mode": { @@ -174,9 +208,10 @@ func resourceBatchAccountCreate(d *pluginsdk.ResourceData, meta interface{}) err parameters := batch.AccountCreateParameters{ Location: &location, AccountCreateProperties: &batch.AccountCreateProperties{ - PoolAllocationMode: batch.PoolAllocationMode(poolAllocationMode), - PublicNetworkAccess: batch.PublicNetworkAccessTypeEnabled, - Encryption: encryption, + PoolAllocationMode: batch.PoolAllocationMode(poolAllocationMode), + PublicNetworkAccess: batch.PublicNetworkAccessTypeEnabled, + Encryption: encryption, + AllowedAuthenticationModes: expandAllowedAuthenticationModes(d.Get("allowed_authentication_modes").(*pluginsdk.Set).List()), }, Identity: identity, Tags: tags.Expand(t), @@ -199,11 +234,37 @@ func resourceBatchAccountCreate(d *pluginsdk.ResourceData, meta interface{}) err } parameters.KeyVaultReference = keyVaultReference + + if v, ok := d.GetOk("allowed_authentication_modes"); ok { + authModes := v.(*pluginsdk.Set).List() + for _, mode := range authModes { + if batch.AuthenticationMode(mode.(string)) == batch.AuthenticationModeSharedKey { + return fmt.Errorf("creating %s: When setting pool allocation mode to UserSubscription, `allowed_authentication_modes=[StorageKeys]` is not allowed. ", id) + } + } + } + } + + authMode := d.Get("storage_account_authentication_mode").(string) + if batch.AutoStorageAuthenticationMode(authMode) == batch.AutoStorageAuthenticationModeBatchAccountManagedIdentity && + identity.Type == batch.ResourceIdentityTypeNone { + return fmt.Errorf(" storage_account_authentication_mode=`BatchAccountManagedIdentity` can only be set when identity.type is `SystemAssigned` or `UserAssigned`") } if storageAccountId != "" { + if authMode == "" { + return fmt.Errorf("`storage_account_authentication_mode` is required when `storage_account_id` ") + } parameters.AccountCreateProperties.AutoStorage = &batch.AutoStorageBaseProperties{ - StorageAccountID: &storageAccountId, + StorageAccountID: &storageAccountId, + AuthenticationMode: batch.AutoStorageAuthenticationMode(authMode), + } + } + + nodeIdentity := d.Get("storage_account_node_identity").(string) + if nodeIdentity != "" { + parameters.AccountCreateProperties.AutoStorage.NodeIdentityReference = &batch.ComputeNodeIdentityReference{ + ResourceID: utils.String(nodeIdentity), } } @@ -258,11 +319,17 @@ func resourceBatchAccountRead(d *pluginsdk.ResourceData, meta interface{}) error if props := resp.AccountProperties; props != nil { d.Set("account_endpoint", props.AccountEndpoint) - accountID := "" if autoStorage := props.AutoStorage; autoStorage != nil { - accountID = *autoStorage.StorageAccountID + d.Set("storage_account_id", *autoStorage.StorageAccountID) + d.Set("storage_account_authentication_mode", autoStorage.AuthenticationMode) + + if autoStorage.NodeIdentityReference != nil { + d.Set("storage_account_node_identity", autoStorage.NodeIdentityReference.ResourceID) + } + } else { + d.Set("storage_account_authentication_mode", "") + d.Set("storage_account_id", "") } - d.Set("storage_account_id", accountID) if props.PublicNetworkAccess != "" { d.Set("public_network_access_enabled", props.PublicNetworkAccess == batch.PublicNetworkAccessTypeEnabled) @@ -273,9 +340,14 @@ func resourceBatchAccountRead(d *pluginsdk.ResourceData, meta interface{}) error if err := d.Set("encryption", flattenEncryption(props.Encryption)); err != nil { return fmt.Errorf("setting `encryption`: %+v", err) } + + if err := d.Set("allowed_authentication_modes", flattenAllowedAuthenticationModes(props.AllowedAuthenticationModes)); err != nil { + return fmt.Errorf("setting `allowed_authentication_modes`: %+v", err) + } } - if d.Get("pool_allocation_mode").(string) == string(batch.PoolAllocationModeBatchService) { + if d.Get("pool_allocation_mode").(string) == string(batch.PoolAllocationModeBatchService) && + isShardKeyAllowed(d.Get("allowed_authentication_modes").(*pluginsdk.Set).List()) { keys, err := client.GetKeys(ctx, id.ResourceGroup, id.BatchAccountName) if err != nil { return fmt.Errorf("Cannot read keys for Batch account %q (resource group %q): %v", id.BatchAccountName, id.ResourceGroup, err) @@ -299,6 +371,7 @@ func resourceBatchAccountUpdate(d *pluginsdk.ResourceData, meta interface{}) err if err != nil { return err } + t := d.Get("tags").(map[string]interface{}) identity, err := expandBatchAccountIdentity(d.Get("identity").([]interface{})) @@ -317,6 +390,16 @@ func resourceBatchAccountUpdate(d *pluginsdk.ResourceData, meta interface{}) err Tags: tags.Expand(t), } + if d.HasChange("allowed_authentication_modes") { + allowedAuthModes := d.Get("allowed_authentication_modes").(*pluginsdk.Set).List() + if len(allowedAuthModes) == 0 { + parameters.AllowedAuthenticationModes = &[]batch.AuthenticationMode{} // remove all modes need explicit set it to empty array not nil + } else { + parameters.AllowedAuthenticationModes = expandAllowedAuthenticationModes(d.Get("allowed_authentication_modes").(*pluginsdk.Set).List()) + } + + } + if d.HasChange("storage_account_id") { if v, ok := d.GetOk("storage_account_id"); ok { parameters.AccountUpdateProperties.AutoStorage = &batch.AutoStorageBaseProperties{ @@ -330,6 +413,27 @@ func resourceBatchAccountUpdate(d *pluginsdk.ResourceData, meta interface{}) err } } + authMode := d.Get("storage_account_authentication_mode").(string) + if batch.AutoStorageAuthenticationMode(authMode) == batch.AutoStorageAuthenticationModeBatchAccountManagedIdentity && + identity.Type == batch.ResourceIdentityTypeNone { + return fmt.Errorf(" storage_account_authentication_mode=`BatchAccountManagedIdentity` can only be set when identity.type is `SystemAssigned` or `UserAssigned`") + } + + storageAccountId := d.Get("storage_account_id").(string) + if storageAccountId != "" { + parameters.AutoStorage = &batch.AutoStorageBaseProperties{ + StorageAccountID: &storageAccountId, + AuthenticationMode: batch.AutoStorageAuthenticationMode(authMode), + } + } + + nodeIdentity := d.Get("storage_account_node_identity").(string) + if nodeIdentity != "" { + parameters.AutoStorage.NodeIdentityReference = &batch.ComputeNodeIdentityReference{ + ResourceID: utils.String(nodeIdentity), + } + } + if _, err = client.Update(ctx, id.ResourceGroup, id.BatchAccountName, parameters); err != nil { return fmt.Errorf("updating Batch account %q (Resource Group %q): %+v", id.BatchAccountName, id.ResourceGroup, err) } @@ -429,6 +533,30 @@ func expandEncryption(e []interface{}) *batch.EncryptionProperties { return &encryptionProperty } +func expandAllowedAuthenticationModes(input []interface{}) *[]batch.AuthenticationMode { + if len(input) == 0 { + return nil + } + + allowedAuthModes := make([]batch.AuthenticationMode, 0) + for _, mode := range input { + allowedAuthModes = append(allowedAuthModes, batch.AuthenticationMode(mode.(string))) + } + return &allowedAuthModes +} + +func flattenAllowedAuthenticationModes(input *[]batch.AuthenticationMode) []string { + if input == nil || len(*input) == 0 { + return []string{} + } + + allowedAuthModes := make([]string, 0) + for _, mode := range *input { + allowedAuthModes = append(allowedAuthModes, string(mode)) + } + return allowedAuthModes +} + func flattenEncryption(encryptionProperties *batch.EncryptionProperties) []interface{} { if encryptionProperties == nil || encryptionProperties.KeySource == batch.KeySourceMicrosoftBatch { return []interface{}{} @@ -440,3 +568,15 @@ func flattenEncryption(encryptionProperties *batch.EncryptionProperties) []inter }, } } + +func isShardKeyAllowed(input []interface{}) bool { + if len(input) == 0 { + return false + } + for _, authMod := range input { + if strings.EqualFold(authMod.(string), string(batch.AuthenticationModeSharedKey)) { + return true + } + } + return false +} diff --git a/internal/services/batch/batch_account_resource_test.go b/internal/services/batch/batch_account_resource_test.go index 8cbdce1b035c..bb9637f1acd0 100644 --- a/internal/services/batch/batch_account_resource_test.go +++ b/internal/services/batch/batch_account_resource_test.go @@ -174,6 +174,72 @@ func TestAccBatchAccount_cmk(t *testing.T) { }) } +func TestAccBatchAccount_authenticationModes(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_batch_account", "test") + r := BatchAccountResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.authenticationModes(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("allowed_authentication_modes.#").HasValue("3"), + ), + }, + }) +} + +func TestAccBatchAccount_authenticationModesUpdate(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_batch_account", "test") + r := BatchAccountResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.authenticationModes(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("allowed_authentication_modes.#").HasValue("3"), + ), + }, + { + Config: r.authenticationModesUpdate(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("allowed_authentication_modes.#").HasValue("0")), + }, + }) +} + +func TestAccBatchAccount_autoStorage(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_batch_account", "test") + r := BatchAccountResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.autoStorage(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("storage_account_authentication_mode").HasValue("StorageKeys"), + ), + }, + }) +} + +func TestAccBatchAccount_autoStorageBatchAuthMode(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_batch_account", "test") + r := BatchAccountResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.autoStorageBatchAuthMode(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("storage_account_authentication_mode").HasValue("BatchAccountManagedIdentity"), + ), + }, + }) +} + func TestAccBatchAccount_removeStorageAccount(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_batch_account", "test") r := BatchAccountResource{} @@ -303,11 +369,12 @@ resource "azurerm_storage_account" "test" { } resource "azurerm_batch_account" "test" { - name = "testaccbatch%s" - resource_group_name = azurerm_resource_group.test.name - location = azurerm_resource_group.test.location - pool_allocation_mode = "BatchService" - storage_account_id = azurerm_storage_account.test.id + name = "testaccbatch%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + pool_allocation_mode = "BatchService" + storage_account_id = azurerm_storage_account.test.id + storage_account_authentication_mode = "StorageKeys" public_network_access_enabled = false @@ -338,11 +405,12 @@ resource "azurerm_storage_account" "test" { } resource "azurerm_batch_account" "test" { - name = "testaccbatch%s" - resource_group_name = azurerm_resource_group.test.name - location = azurerm_resource_group.test.location - pool_allocation_mode = "BatchService" - storage_account_id = azurerm_storage_account.test.id + name = "testaccbatch%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + pool_allocation_mode = "BatchService" + storage_account_id = azurerm_storage_account.test.id + storage_account_authentication_mode = "StorageKeys" public_network_access_enabled = false @@ -461,11 +529,12 @@ resource "azurerm_user_assigned_identity" "test" { } resource "azurerm_batch_account" "test" { - name = "testaccbatch%s" - resource_group_name = azurerm_resource_group.test.name - location = azurerm_resource_group.test.location - pool_allocation_mode = "BatchService" - storage_account_id = azurerm_storage_account.test.id + name = "testaccbatch%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + pool_allocation_mode = "BatchService" + storage_account_id = azurerm_storage_account.test.id + storage_account_authentication_mode = "StorageKeys" identity { type = "UserAssigned" identity_ids = [azurerm_user_assigned_identity.test.id] @@ -508,11 +577,12 @@ resource "azurerm_user_assigned_identity" "test" { } resource "azurerm_batch_account" "test" { - name = "testaccbatch%s" - resource_group_name = azurerm_resource_group.test.name - location = azurerm_resource_group.test.location - pool_allocation_mode = "BatchService" - storage_account_id = azurerm_storage_account.test.id + name = "testaccbatch%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + pool_allocation_mode = "BatchService" + storage_account_id = azurerm_storage_account.test.id + storage_account_authentication_mode = "StorageKeys" identity { type = "UserAssigned" identity_ids = [azurerm_user_assigned_identity.test.id] @@ -604,3 +674,148 @@ resource "azurerm_batch_account" "test" { } `, data.RandomInteger, data.Locations.Primary, data.RandomString) } + +func (BatchAccountResource) authenticationModes(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +data "azurerm_client_config" "current" { +} + +resource "azurerm_resource_group" "test" { + name = "testaccRG-batch-%d" + location = "%s" +} + +resource "azurerm_batch_account" "test" { + name = "testaccbatch%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + pool_allocation_mode = "BatchService" + allowed_authentication_modes = [ + "AAD", + "SharedKey", + "TaskAuthenticationToken" + ] +} +`, data.RandomInteger, data.Locations.Primary, data.RandomString) +} + +func (BatchAccountResource) authenticationModesUpdate(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +data "azurerm_client_config" "current" { +} + +resource "azurerm_resource_group" "test" { + name = "testaccRG-batch-%d" + location = "%s" +} + +resource "azurerm_batch_account" "test" { + name = "testaccbatch%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + pool_allocation_mode = "BatchService" + allowed_authentication_modes = [] +} +`, data.RandomInteger, data.Locations.Primary, data.RandomString) +} + +func (BatchAccountResource) autoStorage(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +data "azurerm_client_config" "current" { +} + +resource "azurerm_resource_group" "test" { + name = "testaccRG-batch-%d" + location = "%s" +} + +resource "azurerm_storage_account" "test" { + name = "testaccsa%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + account_tier = "Standard" + account_replication_type = "LRS" +} + +resource "azurerm_user_assigned_identity" "test" { + name = "acctest%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location +} + +resource "azurerm_batch_account" "test" { + name = "testaccbatch%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + storage_account_id = azurerm_storage_account.test.id + storage_account_authentication_mode = "StorageKeys" + storage_account_node_identity = azurerm_user_assigned_identity.test.id + pool_allocation_mode = "BatchService" + allowed_authentication_modes = [ + "AAD", + "SharedKey", + "TaskAuthenticationToken" + ] +} +`, data.RandomInteger, data.Locations.Secondary, data.RandomString, data.RandomString, data.RandomString) +} + +func (BatchAccountResource) autoStorageBatchAuthMode(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +data "azurerm_client_config" "current" { +} + +resource "azurerm_resource_group" "test" { + name = "testaccRG-batch-%d" + location = "%s" +} + +resource "azurerm_storage_account" "test" { + name = "testaccsa%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + account_tier = "Standard" + account_replication_type = "LRS" +} + +resource "azurerm_user_assigned_identity" "test" { + name = "acctest%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location +} + +resource "azurerm_batch_account" "test" { + name = "testaccbatch%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + storage_account_id = azurerm_storage_account.test.id + storage_account_authentication_mode = "BatchAccountManagedIdentity" + pool_allocation_mode = "BatchService" + allowed_authentication_modes = [ + "AAD", + "SharedKey", + "TaskAuthenticationToken" + ] + + identity { + type = "SystemAssigned" + } +} +`, data.RandomInteger, data.Locations.Secondary, data.RandomString, data.RandomString, data.RandomString) +} diff --git a/internal/services/batch/batch_application_data_source_test.go b/internal/services/batch/batch_application_data_source_test.go index 13515dbfe111..014aa6919938 100644 --- a/internal/services/batch/batch_application_data_source_test.go +++ b/internal/services/batch/batch_application_data_source_test.go @@ -44,11 +44,12 @@ resource "azurerm_storage_account" "test" { } resource "azurerm_batch_account" "test" { - name = "acctestba%s" - resource_group_name = azurerm_resource_group.test.name - location = azurerm_resource_group.test.location - pool_allocation_mode = "BatchService" - storage_account_id = azurerm_storage_account.test.id + name = "acctestba%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + pool_allocation_mode = "BatchService" + storage_account_id = azurerm_storage_account.test.id + storage_account_authentication_mode = "StorageKeys" } resource "azurerm_batch_application" "test" { diff --git a/internal/services/batch/batch_application_resource_test.go b/internal/services/batch/batch_application_resource_test.go index e89e11f169d7..883d03c6eac3 100644 --- a/internal/services/batch/batch_application_resource_test.go +++ b/internal/services/batch/batch_application_resource_test.go @@ -101,11 +101,12 @@ resource "azurerm_storage_account" "test" { } resource "azurerm_batch_account" "test" { - name = "acctestba%s" - resource_group_name = azurerm_resource_group.test.name - location = azurerm_resource_group.test.location - pool_allocation_mode = "BatchService" - storage_account_id = azurerm_storage_account.test.id + name = "acctestba%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + pool_allocation_mode = "BatchService" + storage_account_id = azurerm_storage_account.test.id + storage_account_authentication_mode = "StorageKeys" } resource "azurerm_batch_application" "test" { @@ -137,11 +138,12 @@ resource "azurerm_storage_account" "test" { } resource "azurerm_batch_account" "test" { - name = "acctestba%[3]s" - resource_group_name = azurerm_resource_group.test.name - location = azurerm_resource_group.test.location - pool_allocation_mode = "BatchService" - storage_account_id = azurerm_storage_account.test.id + name = "acctestba%[3]s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + pool_allocation_mode = "BatchService" + storage_account_id = azurerm_storage_account.test.id + storage_account_authentication_mode = "StorageKeys" } resource "azurerm_batch_application" "test" { diff --git a/internal/services/batch/batch_pool.go b/internal/services/batch/batch_pool.go index 85faf6ee25e1..f4b9784d5973 100644 --- a/internal/services/batch/batch_pool.go +++ b/internal/services/batch/batch_pool.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/Azure/azure-sdk-for-go/services/batch/mgmt/2022-01-01/batch" + "github.com/hashicorp/go-azure-helpers/lang/pointer" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -252,15 +253,13 @@ func flattenBatchPoolContainerRegistry(d *pluginsdk.ResourceData, armContainerRe } if userName := armContainerRegistry.UserName; userName != nil { result["user_name"] = *userName + // Locate the password only if user_name is defined + result["password"] = findBatchPoolContainerRegistryPassword(d, result["registry_server"].(string), result["user_name"].(string)) } - - // If we didn't specify a registry server and user name, just return what we have now rather than trying to locate the password - if len(result) != 2 { - return result + if identity := armContainerRegistry.IdentityReference; identity != nil { + result["user_assigned_identity_id"] = identity.ResourceID } - result["password"] = findBatchPoolContainerRegistryPassword(d, result["registry_server"].(string), result["user_name"].(string)) - return result } @@ -363,11 +362,23 @@ func expandBatchPoolContainerRegistry(ref map[string]interface{}) (*batch.Contai return nil, fmt.Errorf("Error: container registry reference should be defined") } - containerRegistry := batch.ContainerRegistry{ - RegistryServer: utils.String(ref["registry_server"].(string)), - UserName: utils.String(ref["user_name"].(string)), - Password: utils.String(ref["password"].(string)), + containerRegistry := batch.ContainerRegistry{} + + if v := ref["registry_server"]; v != nil && v != "" { + containerRegistry.RegistryServer = pointer.FromString(v.(string)) + } + if v := ref["user_name"]; v != nil && v != "" { + containerRegistry.UserName = pointer.FromString(v.(string)) } + if v := ref["password"]; v != nil && v != "" { + containerRegistry.Password = pointer.FromString(v.(string)) + } + if v := ref["user_assigned_identity_id"]; v != nil && v != "" { + containerRegistry.IdentityReference = &batch.ComputeNodeIdentityReference{ + ResourceID: pointer.FromString(v.(string)), + } + } + return &containerRegistry, nil } diff --git a/internal/services/batch/batch_pool_data_source.go b/internal/services/batch/batch_pool_data_source.go index 35f859e26c07..a72e7eba4851 100644 --- a/internal/services/batch/batch_pool_data_source.go +++ b/internal/services/batch/batch_pool_data_source.go @@ -144,6 +144,10 @@ func dataSourceBatchPool() *pluginsdk.Resource { Type: pluginsdk.TypeString, Computed: true, }, + "user_assigned_identity_id": { + Type: pluginsdk.TypeString, + Computed: true, + }, "user_name": { Type: pluginsdk.TypeString, Computed: true, diff --git a/internal/services/batch/batch_pool_data_source_test.go b/internal/services/batch/batch_pool_data_source_test.go index 7416b0450d24..d0b8e19c8be8 100644 --- a/internal/services/batch/batch_pool_data_source_test.go +++ b/internal/services/batch/batch_pool_data_source_test.go @@ -94,11 +94,12 @@ resource "azurerm_storage_account" "test" { } resource "azurerm_batch_account" "test" { - name = "testaccbatch%s" - resource_group_name = azurerm_resource_group.test.name - location = azurerm_resource_group.test.location - pool_allocation_mode = "BatchService" - storage_account_id = azurerm_storage_account.test.id + name = "testaccbatch%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + pool_allocation_mode = "BatchService" + storage_account_id = azurerm_storage_account.test.id + storage_account_authentication_mode = "StorageKeys" tags = { env = "test" diff --git a/internal/services/batch/batch_pool_resource.go b/internal/services/batch/batch_pool_resource.go index 3094dabea019..fe71ed78677c 100644 --- a/internal/services/batch/batch_pool_resource.go +++ b/internal/services/batch/batch_pool_resource.go @@ -10,6 +10,7 @@ import ( "github.com/Azure/azure-sdk-for-go/services/batch/mgmt/2022-01-01/batch" "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/identity" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" @@ -159,15 +160,22 @@ func resourceBatchPool() *pluginsdk.Resource { ForceNew: true, ValidateFunc: validation.StringIsNotEmpty, }, + "user_assigned_identity_id": { + Type: pluginsdk.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: commonids.ValidateUserAssignedIdentityID, + Description: "The User Assigned Identity to use for Container Registry access.", + }, "user_name": { Type: pluginsdk.TypeString, - Required: true, + Optional: true, ForceNew: true, ValidateFunc: validation.StringIsNotEmpty, }, "password": { Type: pluginsdk.TypeString, - Required: true, + Optional: true, ForceNew: true, Sensitive: true, ValidateFunc: validation.StringIsNotEmpty, diff --git a/internal/services/batch/batch_pool_resource_test.go b/internal/services/batch/batch_pool_resource_test.go index 07b51ccd63f1..893911d382c0 100644 --- a/internal/services/batch/batch_pool_resource_test.go +++ b/internal/services/batch/batch_pool_resource_test.go @@ -334,13 +334,13 @@ func TestAccBatchPool_validateResourceFileWithoutSource(t *testing.T) { }) } -func TestAccBatchPool_container(t *testing.T) { +func TestAccBatchPool_containerWithUser(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_batch_pool", "test") r := BatchPoolResource{} data.ResourceTest(t, r, []acceptance.TestStep{ { - Config: r.containerConfiguration(data), + Config: r.containerConfigurationWithRegistryUser(data), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), check.That(data.ResourceName).Key("container_configuration.0.type").HasValue("DockerCompatible"), @@ -349,6 +349,7 @@ func TestAccBatchPool_container(t *testing.T) { check.That(data.ResourceName).Key("container_configuration.0.container_registries.0.registry_server").HasValue("myContainerRegistry.azurecr.io"), check.That(data.ResourceName).Key("container_configuration.0.container_registries.0.user_name").HasValue("myUserName"), check.That(data.ResourceName).Key("container_configuration.0.container_registries.0.password").HasValue("myPassword"), + check.That(data.ResourceName).Key("container_configuration.0.container_registries.0.user_assigned_identity_id").IsEmpty(), ), }, data.ImportStep( @@ -358,6 +359,29 @@ func TestAccBatchPool_container(t *testing.T) { }) } +func TestAccBatchPool_containerWithUAMI(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_batch_pool", "test") + r := BatchPoolResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.containerConfigurationWithRegistryUAMI(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("container_configuration.0.type").HasValue("DockerCompatible"), + check.That(data.ResourceName).Key("container_configuration.0.container_image_names.#").HasValue("1"), + check.That(data.ResourceName).Key("container_configuration.0.container_registries.#").HasValue("1"), + check.That(data.ResourceName).Key("container_configuration.0.container_registries.0.registry_server").HasValue("myContainerRegistry.azurecr.io"), + check.That(data.ResourceName).Key("container_configuration.0.container_registries.0.user_name").IsEmpty(), + check.That(data.ResourceName).Key("container_configuration.0.container_registries.0.user_assigned_identity_id").IsSet(), + ), + }, + data.ImportStep( + "stop_pending_resize_operation", + ), + }) +} + func TestAccBatchPool_validateResourceFileWithMultipleSources(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_batch_pool", "test") r := BatchPoolResource{} @@ -502,11 +526,12 @@ resource "azurerm_storage_account" "test" { } resource "azurerm_batch_account" "test" { - name = "testaccbatch%s" - resource_group_name = azurerm_resource_group.test.name - location = azurerm_resource_group.test.location - pool_allocation_mode = "BatchService" - storage_account_id = azurerm_storage_account.test.id + name = "testaccbatch%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + pool_allocation_mode = "BatchService" + storage_account_id = azurerm_storage_account.test.id + storage_account_authentication_mode = "StorageKeys" tags = { env = "test" @@ -562,11 +587,12 @@ resource "azurerm_storage_account" "test" { } resource "azurerm_batch_account" "test" { - name = "testaccbatch%s" - resource_group_name = azurerm_resource_group.test.name - location = azurerm_resource_group.test.location - pool_allocation_mode = "BatchService" - storage_account_id = azurerm_storage_account.test.id + name = "testaccbatch%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + pool_allocation_mode = "BatchService" + storage_account_id = azurerm_storage_account.test.id + storage_account_authentication_mode = "StorageKeys" tags = { env = "test" @@ -620,11 +646,12 @@ resource "azurerm_storage_account" "test" { } resource "azurerm_batch_account" "test" { - name = "testaccbatch%s" - resource_group_name = azurerm_resource_group.test.name - location = azurerm_resource_group.test.location - pool_allocation_mode = "BatchService" - storage_account_id = azurerm_storage_account.test.id + name = "testaccbatch%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + pool_allocation_mode = "BatchService" + storage_account_id = azurerm_storage_account.test.id + storage_account_authentication_mode = "StorageKeys" tags = { env = "test" @@ -1268,7 +1295,7 @@ resource "azurerm_batch_pool" "test" { `, data.RandomInteger, data.Locations.Primary, data.RandomString, data.RandomString) } -func (BatchPoolResource) containerConfiguration(data acceptance.TestData) string { +func (BatchPoolResource) containerConfigurationWithRegistryUser(data acceptance.TestData) string { return fmt.Sprintf(` provider "azurerm" { features {} @@ -1323,6 +1350,73 @@ resource "azurerm_batch_pool" "test" { `, data.RandomInteger, data.Locations.Primary, data.RandomString, data.RandomString, data.RandomString) } +func (BatchPoolResource) containerConfigurationWithRegistryUAMI(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "testaccbatch%d" + location = "%s" +} + +resource "azurerm_user_assigned_identity" "test" { + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + name = "testaccuami%d" +} + +resource "azurerm_container_registry" "test" { + name = "testregistry%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + sku = "Basic" + + identity { + type = "UserAssigned" + identity_ids = [ + azurerm_user_assigned_identity.test.id + ] + } +} + +resource "azurerm_batch_account" "test" { + name = "testaccbatch%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location +} + +resource "azurerm_batch_pool" "test" { + name = "testaccpool%s" + resource_group_name = azurerm_resource_group.test.name + account_name = azurerm_batch_account.test.name + node_agent_sku_id = "batch.node.ubuntu 20.04" + vm_size = "Standard_A1" + + fixed_scale { + target_dedicated_nodes = 1 + } + + storage_image_reference { + publisher = "microsoft-azure-batch" + offer = "ubuntu-server-container" + sku = "20-04-lts" + version = "latest" + } + + container_configuration { + type = "DockerCompatible" + container_image_names = ["centos7"] + container_registries { + registry_server = "myContainerRegistry.azurecr.io" + user_assigned_identity_id = azurerm_user_assigned_identity.test.id + } + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomString, data.RandomString, data.RandomString) +} + func (BatchPoolResource) customImageConfiguration(data acceptance.TestData) string { return fmt.Sprintf(` provider "azurerm" { diff --git a/internal/services/blueprints/blueprint_definition_data_source.go b/internal/services/blueprints/blueprint_definition_data_source.go index e8285ed16c8b..d76986f3bbbc 100644 --- a/internal/services/blueprints/blueprint_definition_data_source.go +++ b/internal/services/blueprints/blueprint_definition_data_source.go @@ -77,6 +77,7 @@ func dataSourceBlueprintDefinition() *pluginsdk.Resource { func dataSourceBlueprintDefinitionRead(d *pluginsdk.ResourceData, meta interface{}) error { client := meta.(*clients.Client).Blueprints.BlueprintsClient + publishedClient := meta.(*clients.Client).Blueprints.PublishedBlueprintsClient ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() @@ -112,9 +113,20 @@ func dataSourceBlueprintDefinitionRead(d *pluginsdk.ResourceData, meta interface d.Set("target_scope", resp.TargetScope) - if resp.Versions != nil { - d.Set("versions", resp.Versions) + versionList := make([]string, 0) + versions, err := publishedClient.List(ctx, scope, name) + if err != nil { + return fmt.Errorf("listing blue print versions for %s error: %+v", *resp.ID, err) } + for _, version := range versions.Values() { + if version.PublishedBlueprintProperties == nil || version.Name == nil { + continue + } + versionList = append(versionList, *version.Name) + } + + d.Set("versions", versionList) + return nil } diff --git a/internal/services/blueprints/blueprint_definition_data_source_test.go b/internal/services/blueprints/blueprint_definition_data_source_test.go index 30e640a4cb78..4f7f836a8a06 100644 --- a/internal/services/blueprints/blueprint_definition_data_source_test.go +++ b/internal/services/blueprints/blueprint_definition_data_source_test.go @@ -21,6 +21,7 @@ func TestAccBlueprintDefinitionDataSource_basic(t *testing.T) { Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).Key("description").HasValue("Acceptance Test stub for Blueprints at Subscription"), check.That(data.ResourceName).Key("name").HasValue("testAcc_basicSubscription"), + check.That(data.ResourceName).Key("versions.#").HasValue("2"), check.That(data.ResourceName).Key("last_modified").Exists(), check.That(data.ResourceName).Key("target_scope").HasValue("subscription"), check.That(data.ResourceName).Key("time_created").Exists(), diff --git a/internal/services/bot/bot_channel_test.go b/internal/services/bot/bot_channel_test.go index 5c1afa88746a..e9fb39e20b71 100644 --- a/internal/services/bot/bot_channel_test.go +++ b/internal/services/bot/bot_channel_test.go @@ -17,10 +17,11 @@ func TestAccBotChannelsRegistration(t *testing.T) { "streamingEndpointEnabled": testAccBotChannelsRegistration_streamingEndpointEnabled, }, "bot": { - "basic": testAccBotServiceAzureBot_basic, - "completeUpdate": testAccBotServiceAzureBot_completeUpdate, - "msaAppType": testAccBotServiceAzureBot_msaAppType, - "requiresImport": testAccBotServiceAzureBot_requiresImport, + "basic": testAccBotServiceAzureBot_basic, + "completeUpdate": testAccBotServiceAzureBot_completeUpdate, + "msaAppType": testAccBotServiceAzureBot_msaAppType, + "requiresImport": testAccBotServiceAzureBot_requiresImport, + "streamingEndpointEnabled": testAccBotServiceAzureBot_streamingEndpointEnabled, }, "connection": { "basic": testAccBotConnection_basic, diff --git a/internal/services/bot/bot_service_azure_bot_resource_test.go b/internal/services/bot/bot_service_azure_bot_resource_test.go index 3196a0ca4926..23d3f710857b 100644 --- a/internal/services/bot/bot_service_azure_bot_resource_test.go +++ b/internal/services/bot/bot_service_azure_bot_resource_test.go @@ -88,6 +88,28 @@ func testAccBotServiceAzureBot_msaAppType(t *testing.T) { }) } +func testAccBotServiceAzureBot_streamingEndpointEnabled(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_bot_service_azure_bot", "test") + r := BotServiceAzureBotResource{} + + data.ResourceSequentialTest(t, r, []acceptance.TestStep{ + { + Config: r.steamingEndpointEnabled(data, true), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.steamingEndpointEnabled(data, false), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func (t BotServiceAzureBotResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { id, err := parse.BotServiceID(state.ID) if err != nil { @@ -223,3 +245,28 @@ resource "azurerm_bot_service_azure_bot" "test" { } `, data.RandomInteger, data.Locations.Primary) } + +func (BotServiceAzureBotResource) steamingEndpointEnabled(data acceptance.TestData, streamingEndpointEnabled bool) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +data "azurerm_client_config" "current" { +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%[1]d" + location = "%[2]s" +} + +resource "azurerm_bot_service_azure_bot" "test" { + name = "acctestdf%[1]d" + resource_group_name = azurerm_resource_group.test.name + location = "global" + sku = "F0" + microsoft_app_id = data.azurerm_client_config.current.client_id + streaming_endpoint_enabled = %[3]t +} +`, data.RandomInteger, data.Locations.Primary, streamingEndpointEnabled) +} diff --git a/internal/services/bot/bot_service_base_resource.go b/internal/services/bot/bot_service_base_resource.go index e8eaaa3ba8f7..1ad13f335327 100644 --- a/internal/services/bot/bot_service_base_resource.go +++ b/internal/services/bot/bot_service_base_resource.go @@ -120,6 +120,12 @@ func (br botBaseResource) arguments(fields map[string]*pluginsdk.Schema) map[str ValidateFunc: validation.StringIsNotEmpty, }, + "streaming_endpoint_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: false, + }, + "tags": tags.Schema(), } @@ -173,6 +179,7 @@ func (br botBaseResource) createFunc(resourceName, botKind string) sdk.ResourceF DeveloperAppInsightsApplicationID: utils.String(metadata.ResourceData.Get("developer_app_insights_application_id").(string)), LuisAppIds: utils.ExpandStringSlice(metadata.ResourceData.Get("luis_app_ids").([]interface{})), LuisKey: utils.String(metadata.ResourceData.Get("luis_key").(string)), + IsStreamingSupported: utils.Bool(metadata.ResourceData.Get("streaming_endpoint_enabled").(bool)), }, Tags: tags.Expand(metadata.ResourceData.Get("tags").(map[string]interface{})), } @@ -290,6 +297,12 @@ func (br botBaseResource) readFunc() sdk.ResourceFunc { luisAppIds = *v } metadata.ResourceData.Set("luis_app_ids", utils.FlattenStringSlice(&luisAppIds)) + + streamingEndpointEnabled := false + if v := props.IsStreamingSupported; v != nil { + streamingEndpointEnabled = *v + } + metadata.ResourceData.Set("streaming_endpoint_enabled", streamingEndpointEnabled) } return nil @@ -359,6 +372,10 @@ func (br botBaseResource) updateFunc() sdk.ResourceFunc { existing.Properties.LuisKey = utils.String(metadata.ResourceData.Get("luis_key").(string)) } + if metadata.ResourceData.HasChange("streaming_endpoint_enabled") { + existing.Properties.IsStreamingSupported = utils.Bool(metadata.ResourceData.Get("streaming_endpoint_enabled").(bool)) + } + if _, err := client.Update(ctx, id.ResourceGroup, id.Name, existing); err != nil { return fmt.Errorf("updating %s: %+v", *id, err) } diff --git a/internal/services/cdn/cdn_endpoint_custom_domain_resource.go b/internal/services/cdn/cdn_endpoint_custom_domain_resource.go index 58a5a87119bc..3dc453544d50 100644 --- a/internal/services/cdn/cdn_endpoint_custom_domain_resource.go +++ b/internal/services/cdn/cdn_endpoint_custom_domain_resource.go @@ -9,6 +9,7 @@ import ( "github.com/Azure/azure-sdk-for-go/services/cdn/mgmt/2020-09-01/cdn" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/features" "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/validate" keyvaultClient "github.com/hashicorp/terraform-provider-azurerm/internal/services/keyvault/client" @@ -21,6 +22,112 @@ import ( ) func resourceArmCdnEndpointCustomDomain() *pluginsdk.Resource { + schema := map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.CdnEndpointCustomDomainName(), + }, + + "cdn_endpoint_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.EndpointID, + }, + + "host_name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + "cdn_managed_https": { + Type: pluginsdk.TypeList, + Optional: true, + MinItems: 1, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "certificate_type": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(cdn.CertificateTypeShared), + string(cdn.CertificateTypeDedicated), + }, false), + }, + "protocol_type": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(cdn.ProtocolTypeServerNameIndication), + string(cdn.ProtocolTypeIPBased), + }, false), + }, + "tls_version": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + string(cdn.MinimumTLSVersionTLS10), + string(cdn.MinimumTLSVersionTLS12), + string(cdn.MinimumTLSVersionNone), + }, false), + Default: string(cdn.MinimumTLSVersionTLS12), + }, + }, + }, + ConflictsWith: []string{"user_managed_https"}, + }, + + "user_managed_https": { + Type: pluginsdk.TypeList, + Optional: true, + MinItems: 1, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "tls_version": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + string(cdn.MinimumTLSVersionTLS10), + string(cdn.MinimumTLSVersionTLS12), + string(cdn.MinimumTLSVersionNone), + }, false), + Default: string(cdn.MinimumTLSVersionTLS12), + }, + }, + }, + ConflictsWith: []string{"cdn_managed_https"}, + }, + } + if !features.FourPointOhBeta() { + schema["user_managed_https"].Elem.(*pluginsdk.Resource).Schema["key_vault_certificate_id"] = &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + Optional: true, + Computed: true, + ValidateFunc: keyvaultValidate.NestedItemIdWithOptionalVersion, + ExactlyOneOf: []string{"user_managed_https.0.key_vault_certificate_id", "user_managed_https.0.key_vault_secret_id"}, + Deprecated: "This is deprecated in favor of `key_vault_secret_id` as the service is actually looking for a secret, not a certificate", + } + + schema["user_managed_https"].Elem.(*pluginsdk.Resource).Schema["key_vault_secret_id"] = &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + Optional: true, + Computed: true, + ValidateFunc: keyvaultValidate.NestedItemIdWithOptionalVersion, + ExactlyOneOf: []string{"user_managed_https.0.key_vault_certificate_id", "user_managed_https.0.key_vault_secret_id"}, + } + } else { + schema["user_managed_https"].Elem.(*pluginsdk.Resource).Schema["key_vault_secret_id"] = &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: keyvaultValidate.NestedItemIdWithOptionalVersion, + } + } + return &pluginsdk.Resource{ Create: resourceArmCdnEndpointCustomDomainCreate, Read: resourceArmCdnEndpointCustomDomainRead, @@ -39,92 +146,7 @@ func resourceArmCdnEndpointCustomDomain() *pluginsdk.Resource { Delete: pluginsdk.DefaultTimeout(12 * time.Hour), }, - Schema: map[string]*pluginsdk.Schema{ - "name": { - Type: pluginsdk.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validate.CdnEndpointCustomDomainName(), - }, - - "cdn_endpoint_id": { - Type: pluginsdk.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validate.EndpointID, - }, - - "host_name": { - Type: pluginsdk.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validation.StringIsNotEmpty, - }, - "cdn_managed_https": { - Type: pluginsdk.TypeList, - Optional: true, - MinItems: 1, - MaxItems: 1, - Elem: &pluginsdk.Resource{ - Schema: map[string]*pluginsdk.Schema{ - "certificate_type": { - Type: pluginsdk.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - string(cdn.CertificateTypeShared), - string(cdn.CertificateTypeDedicated), - }, false), - }, - "protocol_type": { - Type: pluginsdk.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - string(cdn.ProtocolTypeServerNameIndication), - string(cdn.ProtocolTypeIPBased), - }, false), - }, - "tls_version": { - Type: pluginsdk.TypeString, - Optional: true, - ValidateFunc: validation.StringInSlice([]string{ - string(cdn.MinimumTLSVersionTLS10), - string(cdn.MinimumTLSVersionTLS12), - string(cdn.MinimumTLSVersionNone), - }, false), - Default: string(cdn.MinimumTLSVersionTLS12), - }, - }, - }, - ConflictsWith: []string{"user_managed_https"}, - }, - - "user_managed_https": { - Type: pluginsdk.TypeList, - Optional: true, - MinItems: 1, - MaxItems: 1, - Elem: &pluginsdk.Resource{ - Schema: map[string]*pluginsdk.Schema{ - "key_vault_certificate_id": { - Type: pluginsdk.TypeString, - Required: true, - ValidateFunc: keyvaultValidate.NestedItemIdWithOptionalVersion, - }, - "tls_version": { - Type: pluginsdk.TypeString, - Optional: true, - ValidateFunc: validation.StringInSlice([]string{ - string(cdn.MinimumTLSVersionTLS10), - string(cdn.MinimumTLSVersionTLS12), - string(cdn.MinimumTLSVersionNone), - }, false), - Default: string(cdn.MinimumTLSVersionTLS12), - }, - }, - }, - ConflictsWith: []string{"cdn_managed_https"}, - }, - }, + Schema: schema, } } @@ -351,12 +373,21 @@ func resourceArmCdnEndpointCustomDomainRead(d *pluginsdk.ResourceData, meta inte case cdn.UserManagedHTTPSParameters: var isVersioned bool if b := d.Get("user_managed_https").([]interface{}); len(b) == 1 { - if certIdRaw := b[0].(map[string]interface{})["key_vault_certificate_id"].(string); certIdRaw != "" { - certId, err := keyvaultParse.ParseOptionallyVersionedNestedItemID(certIdRaw) + b := b[0].(map[string]interface{}) + + secretIdRaw := b["key_vault_secret_id"].(string) + if !features.FourPointOhBeta() { + if secretIdRaw == "" { + secretIdRaw = b["key_vault_certificate_id"].(string) + } + } + + if secretIdRaw != "" { + id, err := keyvaultParse.ParseOptionallyVersionedNestedItemID(secretIdRaw) if err != nil { - return fmt.Errorf("parsing Key Vault Certificate Id %q: %v", certIdRaw, err) + return fmt.Errorf("parsing Key Vault Secret Id %q: %v", secretIdRaw, err) } - isVersioned = certId.Version != "" + isVersioned = id.Version != "" } } settings, err := flattenArmCdnEndpointCustomDomainUserManagedHttpsSettings(ctx, params, keyVaultsClient, isVersioned) @@ -422,17 +453,24 @@ func expandArmCdnEndpointCustomDomainUserManagedHttpsSettings(ctx context.Contex raw := input[0].(map[string]interface{}) - keyVaultCertId, err := keyvaultParse.ParseOptionallyVersionedNestedItemID(raw["key_vault_certificate_id"].(string)) + idLiteral := raw["key_vault_secret_id"].(string) + if !features.FourPointOhBeta() { + if idLiteral == "" { + idLiteral = raw["key_vault_certificate_id"].(string) + } + } + + keyVaultSecretId, err := keyvaultParse.ParseOptionallyVersionedNestedItemID(idLiteral) if err != nil { return nil, err } - keyVaultIdRaw, err := clients.KeyVault.KeyVaultIDFromBaseUrl(ctx, clients.Resource, keyVaultCertId.KeyVaultBaseUrl) + keyVaultIdRaw, err := clients.KeyVault.KeyVaultIDFromBaseUrl(ctx, clients.Resource, keyVaultSecretId.KeyVaultBaseUrl) if err != nil { - return nil, fmt.Errorf("retrieving the Resource ID the Key Vault at URL %q: %s", keyVaultCertId.KeyVaultBaseUrl, err) + return nil, fmt.Errorf("retrieving the Resource ID the Key Vault at URL %q: %s", keyVaultSecretId.KeyVaultBaseUrl, err) } if keyVaultIdRaw == nil { - return nil, fmt.Errorf("unexpected nil Key Vault ID retrieved at URL %q", keyVaultCertId.KeyVaultBaseUrl) + return nil, fmt.Errorf("unexpected nil Key Vault ID retrieved at URL %q", keyVaultSecretId.KeyVaultBaseUrl) } keyVaultId, err := keyvaultParse.VaultID(*keyVaultIdRaw) if err != nil { @@ -445,8 +483,8 @@ func expandArmCdnEndpointCustomDomainUserManagedHttpsSettings(ctx context.Contex SubscriptionID: &keyVaultId.SubscriptionId, ResourceGroupName: &keyVaultId.ResourceGroup, VaultName: &keyVaultId.Name, - SecretName: &keyVaultCertId.Name, - SecretVersion: &keyVaultCertId.Version, + SecretName: &keyVaultSecretId.Name, + SecretVersion: &keyVaultSecretId.Version, UpdateRule: utils.String("NoAction"), DeleteRule: utils.String("NoAction"), }, @@ -507,31 +545,50 @@ func flattenArmCdnEndpointCustomDomainUserManagedHttpsSettings(ctx context.Conte keyVaultId := keyvaultParse.NewVaultID(subscriptionId, resourceGroupName, vaultName) keyVaultBaseUrl, err := keyVaultsClient.BaseUriForKeyVault(ctx, keyVaultId) if err != nil { - return nil, fmt.Errorf("looking up Key Vault Certificate %q vault url from id %q: %+v", vaultName, keyVaultId, err) + return nil, fmt.Errorf("looking up Key Vault Secret %q vault url from id %q: %+v", vaultName, keyVaultId, err) } - cert, err := keyVaultsClient.ManagementClient.GetCertificate(ctx, *keyVaultBaseUrl, secretName, secretVersion) + + secret, err := keyVaultsClient.ManagementClient.GetSecret(ctx, *keyVaultBaseUrl, secretName, secretVersion) if err != nil { return nil, err } - if cert.ID == nil { - return nil, fmt.Errorf("unexpected null Key Vault Certificate retrieved for Key Vault %s / Secret Name %s / Secret Version %s", keyVaultId, secretName, secretVersion) + if secret.ID == nil { + return nil, fmt.Errorf("unexpected null Key Vault Secret retrieved for Key Vault %s / Secret Name %s / Secret Version %s", keyVaultId, secretName, secretVersion) } - certId, err := keyvaultParse.ParseOptionallyVersionedNestedItemID(*cert.ID) + secretId, err := keyvaultParse.ParseOptionallyVersionedNestedItemID(*secret.ID) if err != nil { return nil, err } - certIdLiteral := certId.ID() + secretIdLiteral := secretId.ID() if !isVersioned { - certIdLiteral = certId.VersionlessID() + secretIdLiteral = secretId.VersionlessID() } - return []interface{}{ - map[string]interface{}{ - "key_vault_certificate_id": certIdLiteral, - "tls_version": string(input.MinimumTLSVersion), - }, - }, nil + m := map[string]interface{}{ + "key_vault_secret_id": secretIdLiteral, + "tls_version": string(input.MinimumTLSVersion), + } + + if features.FourPointOhBeta() { + return []interface{}{m}, nil + } + + // We try to retrieve the certificate with the given secret name and version. If it returns error, then we tolerate the error and simply setting empty string for the certificate id. + // As in this case, the users might be using a secret rather than a certificate. + var certIdLiteral string + cert, err := keyVaultsClient.ManagementClient.GetCertificate(ctx, *keyVaultBaseUrl, secretName, secretVersion) + if err == nil && cert.ID != nil { + certId, err := keyvaultParse.ParseOptionallyVersionedNestedItemID(*cert.ID) + if err == nil { + } + certIdLiteral = certId.ID() + if !isVersioned { + certIdLiteral = certId.VersionlessID() + } + } + m["key_vault_certificate_id"] = certIdLiteral + return []interface{}{m}, nil } func enableArmCdnEndpointCustomDomainHttps(ctx context.Context, client *cdn.CustomDomainsClient, id parse.CustomDomainId, params cdn.BasicCustomDomainHTTPSParameters) error { diff --git a/internal/services/cdn/cdn_endpoint_custom_domain_resource_test.go b/internal/services/cdn/cdn_endpoint_custom_domain_resource_test.go index 67d4e9e17fdd..cd85001600ef 100644 --- a/internal/services/cdn/cdn_endpoint_custom_domain_resource_test.go +++ b/internal/services/cdn/cdn_endpoint_custom_domain_resource_test.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/features" "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" @@ -85,7 +86,7 @@ func TestAccCdnEndpointCustomDomain_httpsCdn(t *testing.T) { }) } -func TestAccCdnEndpointCustomDomain_httpsUserManaged(t *testing.T) { +func TestAccCdnEndpointCustomDomain_httpsUserManagedCertificate(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_cdn_endpoint_custom_domain", "test") r := NewCdnEndpointCustomDomainResource(os.Getenv("ARM_TEST_DNS_ZONE_RESOURCE_GROUP_NAME"), os.Getenv("ARM_TEST_DNS_ZONE_NAME")) @@ -95,15 +96,56 @@ func TestAccCdnEndpointCustomDomain_httpsUserManaged(t *testing.T) { data.ResourceTest(t, r, []acceptance.TestStep{ { - Config: r.httpsUserManaged(data), + Config: r.httpsUserManagedCertificate(data), Check: resource.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), ), }, - // The "key_vault_certificate_id" is skipped here since during import, there is no knowledge about whether users want - // versioned or versionless certificate id. That means the imported "key_vault_certificate_id" is what it is at the + // The "key_vault_secret_id" is skipped here since during import, there is no knowledge about whether users want + // versioned or versionless certificate id. That means the imported "key_vault_secret_id" is what it is at the // remote API representation, which might be different than it as defined in the configuration. - data.ImportStep("user_managed_https.0.key_vault_certificate_id"), + data.ImportStep("user_managed_https.0.key_vault_secret_id", "user_managed_https.0.key_vault_certificate_id"), + }) +} + +func TestAccCdnEndpointCustomDomain_httpsUserManagedCertificateDeprecated(t *testing.T) { + if features.FourPointOhBeta() { + t.Skipf("This test is skipped since v4.0") + } + data := acceptance.BuildTestData(t, "azurerm_cdn_endpoint_custom_domain", "test") + + r := NewCdnEndpointCustomDomainResource(os.Getenv("ARM_TEST_DNS_ZONE_RESOURCE_GROUP_NAME"), os.Getenv("ARM_TEST_DNS_ZONE_NAME")) + r.CertificateP12 = os.Getenv("ARM_TEST_DNS_CERTIFICATE") + r.SubDomainName = os.Getenv("ARM_TEST_DNS_SUBDOMAIN_NAME") + r.preCheckUserManagedCertificate(t) + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.httpsUserManagedCertificateDeprecated(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("user_managed_https.0.key_vault_secret_id", "user_managed_https.0.key_vault_certificate_id"), + }) +} + +func TestAccCdnEndpointCustomDomain_httpsUserManagedSecret(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_cdn_endpoint_custom_domain", "test") + + r := NewCdnEndpointCustomDomainResource(os.Getenv("ARM_TEST_DNS_ZONE_RESOURCE_GROUP_NAME"), os.Getenv("ARM_TEST_DNS_ZONE_NAME")) + r.CertificateP12 = os.Getenv("ARM_TEST_DNS_CERTIFICATE") + r.SubDomainName = os.Getenv("ARM_TEST_DNS_SUBDOMAIN_NAME") + r.preCheckUserManagedCertificate(t) + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.httpsUserManagedSecret(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("user_managed_https.0.key_vault_secret_id", "user_managed_https.0.key_vault_certificate_id"), }) } @@ -131,12 +173,12 @@ func TestAccCdnEndpointCustomDomain_httpsUpdate(t *testing.T) { }, data.ImportStep(), { - Config: r.httpsUserManaged(data), + Config: r.httpsUserManagedCertificate(data), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), ), }, - data.ImportStep("user_managed_https.0.key_vault_certificate_id"), + data.ImportStep("user_managed_https.0.key_vault_secret_id", "user_managed_https.0.key_vault_certificate_id"), { Config: r.basic(data), Check: acceptance.ComposeTestCheckFunc( @@ -241,7 +283,7 @@ resource "azurerm_cdn_endpoint_custom_domain" "test" { `, template, data.RandomIntOfLength(8)) } -func (r CdnEndpointCustomDomainResource) httpsUserManaged(data acceptance.TestData) string { +func (r CdnEndpointCustomDomainResource) httpsUserManagedBase(data acceptance.TestData) string { template := r.template(data) return fmt.Sprintf(` %[1]s @@ -275,6 +317,8 @@ resource "azurerm_key_vault" "test" { secret_permissions = [ "Get", "Set", + "Delete", + "Purge", ] } access_policy { @@ -290,6 +334,52 @@ resource "azurerm_key_vault" "test" { ] } } +`, template, data.RandomIntOfLength(8)) +} + +func (r CdnEndpointCustomDomainResource) httpsUserManagedCertificate(data acceptance.TestData) string { + template := r.httpsUserManagedBase(data) + return fmt.Sprintf(` +%[1]s + +resource "azurerm_key_vault_certificate" "test" { + name = "testkeyvaultcert-%[2]d" + key_vault_id = azurerm_key_vault.test.id + certificate { + contents = file("%[3]s") + password = "" + } + certificate_policy { + issuer_parameters { + name = "Self" + } + key_properties { + exportable = true + key_size = 2048 + key_type = "RSA" + reuse_key = false + } + secret_properties { + content_type = "application/x-pkcs12" + } + } +} +resource "azurerm_cdn_endpoint_custom_domain" "test" { + name = "testcustomdomain-%[2]d" + cdn_endpoint_id = azurerm_cdn_endpoint.test.id + host_name = "${azurerm_dns_cname_record.test.name}.${data.azurerm_dns_zone.test.name}" + user_managed_https { + key_vault_secret_id = azurerm_key_vault_certificate.test.secret_id + } +} +`, template, data.RandomIntOfLength(8), r.CertificateP12) +} + +func (r CdnEndpointCustomDomainResource) httpsUserManagedCertificateDeprecated(data acceptance.TestData) string { + template := r.httpsUserManagedBase(data) + return fmt.Sprintf(` +%[1]s + resource "azurerm_key_vault_certificate" "test" { name = "testkeyvaultcert-%[2]d" key_vault_id = azurerm_key_vault.test.id @@ -323,6 +413,28 @@ resource "azurerm_cdn_endpoint_custom_domain" "test" { `, template, data.RandomIntOfLength(8), r.CertificateP12) } +func (r CdnEndpointCustomDomainResource) httpsUserManagedSecret(data acceptance.TestData) string { + template := r.httpsUserManagedBase(data) + return fmt.Sprintf(` +%[1]s + +resource "azurerm_key_vault_secret" "test" { + name = "testkeyvaultsecret-%[2]d" + key_vault_id = azurerm_key_vault.test.id + content_type = "application/x-pkcs12" + value = file("%[3]s") +} +resource "azurerm_cdn_endpoint_custom_domain" "test" { + name = "testcustomdomain-%[2]d" + cdn_endpoint_id = azurerm_cdn_endpoint.test.id + host_name = "${azurerm_dns_cname_record.test.name}.${data.azurerm_dns_zone.test.name}" + user_managed_https { + key_vault_secret_id = azurerm_key_vault_secret.test.id + } +} +`, template, data.RandomIntOfLength(8), r.CertificateP12) +} + func (r CdnEndpointCustomDomainResource) template(data acceptance.TestData) string { return fmt.Sprintf(` provider "azurerm" { diff --git a/internal/services/cdn/cdn_frontdoor_endpoint_resource_test.go b/internal/services/cdn/cdn_frontdoor_endpoint_resource_test.go index 1a46e9230f8b..eb4ef334b578 100644 --- a/internal/services/cdn/cdn_frontdoor_endpoint_resource_test.go +++ b/internal/services/cdn/cdn_frontdoor_endpoint_resource_test.go @@ -175,8 +175,8 @@ resource "azurerm_resource_group" "test" { resource "azurerm_cdn_frontdoor_profile" "test" { name = "acctest-cdnfdprofile-%d" - sku_name = "Standard_AzureFrontDoor" resource_group_name = azurerm_resource_group.test.name + sku_name = "Standard_AzureFrontDoor" } `, data.RandomInteger, data.Locations.Primary, data.RandomInteger) } diff --git a/internal/services/cdn/cdn_frontdoor_firewall_policy_resource.go b/internal/services/cdn/cdn_frontdoor_firewall_policy_resource.go new file mode 100644 index 000000000000..7dad3bf00b0b --- /dev/null +++ b/internal/services/cdn/cdn_frontdoor_firewall_policy_resource.go @@ -0,0 +1,1094 @@ +package cdn + +import ( + "fmt" + "log" + "time" + + "github.com/Azure/azure-sdk-for-go/services/frontdoor/mgmt/2020-11-01/frontdoor" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/validate" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +func resourceCdnFrontDoorFirewallPolicy() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Create: resourceCdnFrontDoorFirewallPolicyCreate, + Read: resourceCdnFrontDoorFirewallPolicyRead, + Update: resourceCdnFrontDoorFirewallPolicyUpdate, + Delete: resourceCdnFrontDoorFirewallPolicyDelete, + + Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { + _, err := parse.FrontDoorFirewallPolicyID(id) + return err + }), + + Timeouts: &pluginsdk.ResourceTimeout{ + Create: pluginsdk.DefaultTimeout(30 * time.Minute), + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + Update: pluginsdk.DefaultTimeout(30 * time.Minute), + Delete: pluginsdk.DefaultTimeout(30 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.FrontDoorFirewallPolicyName, + }, + + "resource_group_name": commonschema.ResourceGroupName(), + + "sku_name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{ + string(frontdoor.SkuNameStandardAzureFrontDoor), + string(frontdoor.SkuNamePremiumAzureFrontDoor), + }, false), + }, + + "mode": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(frontdoor.PolicyModeDetection), + string(frontdoor.PolicyModePrevention), + }, false), + }, + + "enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: true, + }, + + "redirect_url": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.IsURLWithScheme([]string{"http", "https"}), + }, + + "custom_block_response_status_code": { + Type: pluginsdk.TypeInt, + Optional: true, + ValidateFunc: validation.IntInSlice([]int{ + 200, + 403, + 405, + 406, + 429, + }), + }, + + "custom_block_response_body": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.StringIsBase64, + }, + + "custom_rule": { + Type: pluginsdk.TypeList, + MaxItems: 100, + Optional: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: true, + }, + + "priority": { + Type: pluginsdk.TypeInt, + Optional: true, + Default: 1, + }, + + "type": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(frontdoor.RuleTypeMatchRule), + string(frontdoor.RuleTypeRateLimitRule), + }, false), + }, + + "rate_limit_duration_in_minutes": { + Type: pluginsdk.TypeInt, + Optional: true, + Default: 1, + }, + + "rate_limit_threshold": { + Type: pluginsdk.TypeInt, + Optional: true, + Default: 10, + }, + + "action": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(frontdoor.ActionTypeAllow), + string(frontdoor.ActionTypeBlock), + string(frontdoor.ActionTypeLog), + string(frontdoor.ActionTypeRedirect), + }, false), + }, + + "match_condition": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 10, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "match_variable": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(frontdoor.MatchVariableCookies), + string(frontdoor.MatchVariablePostArgs), + string(frontdoor.MatchVariableQueryString), + string(frontdoor.MatchVariableRemoteAddr), + string(frontdoor.MatchVariableRequestBody), + string(frontdoor.MatchVariableRequestHeader), + string(frontdoor.MatchVariableRequestMethod), + string(frontdoor.MatchVariableRequestURI), + string(frontdoor.MatchVariableSocketAddr), + }, false), + }, + + "match_values": { + Type: pluginsdk.TypeList, + Required: true, + MaxItems: 600, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringLenBetween(1, 256), + }, + }, + + "operator": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(frontdoor.OperatorAny), + string(frontdoor.OperatorBeginsWith), + string(frontdoor.OperatorContains), + string(frontdoor.OperatorEndsWith), + string(frontdoor.OperatorEqual), + string(frontdoor.OperatorGeoMatch), + string(frontdoor.OperatorGreaterThan), + string(frontdoor.OperatorGreaterThanOrEqual), + string(frontdoor.OperatorIPMatch), + string(frontdoor.OperatorLessThan), + string(frontdoor.OperatorLessThanOrEqual), + string(frontdoor.OperatorRegEx), + }, false), + }, + + "selector": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "negation_condition": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: false, + }, + + "transforms": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 5, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringInSlice([]string{ + string(frontdoor.TransformTypeLowercase), + string(frontdoor.TransformTypeRemoveNulls), + string(frontdoor.TransformTypeTrim), + string(frontdoor.TransformTypeUppercase), + string(frontdoor.TransformTypeURLDecode), + string(frontdoor.TransformTypeURLEncode), + }, false), + }, + }, + }, + }, + }, + }, + }, + }, + + "managed_rule": { + Type: pluginsdk.TypeList, + MaxItems: 100, + Optional: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "type": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "version": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "action": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(frontdoor.ActionTypeAllow), + string(frontdoor.ActionTypeLog), + string(frontdoor.ActionTypeBlock), + string(frontdoor.ActionTypeRedirect), + }, false), + }, + + "exclusion": { + Type: pluginsdk.TypeList, + MaxItems: 100, + Optional: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "match_variable": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(frontdoor.ManagedRuleExclusionMatchVariableQueryStringArgNames), + string(frontdoor.ManagedRuleExclusionMatchVariableRequestBodyPostArgNames), + string(frontdoor.ManagedRuleExclusionMatchVariableRequestCookieNames), + string(frontdoor.ManagedRuleExclusionMatchVariableRequestHeaderNames), + }, false), + }, + "operator": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(frontdoor.ManagedRuleExclusionSelectorMatchOperatorContains), + string(frontdoor.ManagedRuleExclusionSelectorMatchOperatorEndsWith), + string(frontdoor.ManagedRuleExclusionSelectorMatchOperatorEquals), + string(frontdoor.ManagedRuleExclusionSelectorMatchOperatorEqualsAny), + string(frontdoor.ManagedRuleExclusionSelectorMatchOperatorStartsWith), + }, false), + }, + "selector": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, + }, + }, + + "override": { + Type: pluginsdk.TypeList, + MaxItems: 100, + Optional: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "rule_group_name": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "exclusion": { + Type: pluginsdk.TypeList, + MaxItems: 100, + Optional: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "match_variable": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(frontdoor.ManagedRuleExclusionMatchVariableQueryStringArgNames), + string(frontdoor.ManagedRuleExclusionMatchVariableRequestBodyPostArgNames), + string(frontdoor.ManagedRuleExclusionMatchVariableRequestCookieNames), + string(frontdoor.ManagedRuleExclusionMatchVariableRequestHeaderNames), + }, false), + }, + "operator": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(frontdoor.ManagedRuleExclusionSelectorMatchOperatorContains), + string(frontdoor.ManagedRuleExclusionSelectorMatchOperatorEndsWith), + string(frontdoor.ManagedRuleExclusionSelectorMatchOperatorEquals), + string(frontdoor.ManagedRuleExclusionSelectorMatchOperatorEqualsAny), + string(frontdoor.ManagedRuleExclusionSelectorMatchOperatorStartsWith), + }, false), + }, + "selector": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, + }, + }, + + "rule": { + Type: pluginsdk.TypeList, + MaxItems: 1000, + Optional: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "rule_id": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: false, + }, + + "exclusion": { + Type: pluginsdk.TypeList, + MaxItems: 100, + Optional: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "match_variable": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(frontdoor.ManagedRuleExclusionMatchVariableQueryStringArgNames), + string(frontdoor.ManagedRuleExclusionMatchVariableRequestBodyPostArgNames), + string(frontdoor.ManagedRuleExclusionMatchVariableRequestCookieNames), + string(frontdoor.ManagedRuleExclusionMatchVariableRequestHeaderNames), + }, false), + }, + "operator": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(frontdoor.ManagedRuleExclusionSelectorMatchOperatorContains), + string(frontdoor.ManagedRuleExclusionSelectorMatchOperatorEndsWith), + string(frontdoor.ManagedRuleExclusionSelectorMatchOperatorEquals), + string(frontdoor.ManagedRuleExclusionSelectorMatchOperatorEqualsAny), + string(frontdoor.ManagedRuleExclusionSelectorMatchOperatorStartsWith), + }, false), + }, + "selector": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, + }, + }, + + "action": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(frontdoor.ActionTypeAllow), + string(frontdoor.ActionTypeLog), + string(frontdoor.ActionTypeBlock), + string(frontdoor.ActionTypeRedirect), + }, false), + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + + "frontend_endpoint_ids": { + Type: pluginsdk.TypeList, + Computed: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + }, + }, + + "tags": commonschema.Tags(), + }, + } +} + +func resourceCdnFrontDoorFirewallPolicyCreate(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Cdn.FrontDoorLegacyFirewallPoliciesClient + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) + defer cancel() + + name := d.Get("name").(string) + resourceGroup := d.Get("resource_group_name").(string) + + log.Printf("[INFO] preparing args for Cdn Frontdoor %q Firewall Policy(Resource Group: %q)", name, resourceGroup) + id := parse.NewFrontDoorFirewallPolicyID(subscriptionId, resourceGroup, name) + + if d.IsNewResource() { + existing, err := client.Get(ctx, id.ResourceGroup, id.FrontDoorWebApplicationFirewallPolicyName) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("checking for existing %s: %+v", id, err) + } + } + + if !utils.ResponseWasNotFound(existing.Response) { + return tf.ImportAsExistsError("azurerm_cdn_frontdoor_firewall_policy", id.ID()) + } + } + + enabled := frontdoor.PolicyEnabledStateDisabled + + if d.Get("enabled").(bool) { + enabled = frontdoor.PolicyEnabledStateEnabled + } + + sku := d.Get("sku_name").(string) + mode := frontdoor.PolicyMode(d.Get("mode").(string)) + redirectUrl := d.Get("redirect_url").(string) + customBlockResponseStatusCode := d.Get("custom_block_response_status_code").(int) + customBlockResponseBody := d.Get("custom_block_response_body").(string) + customRules := d.Get("custom_rule").([]interface{}) + managedRules := expandCdnFrontDoorFirewallManagedRules(d.Get("managed_rule").([]interface{})) + + if sku != string(frontdoor.SkuNamePremiumAzureFrontDoor) && managedRules != nil { + return fmt.Errorf("the `managed_rule` field is only supported with the %q sku, got %q", frontdoor.SkuNamePremiumAzureFrontDoor, sku) + } + + t := d.Get("tags").(map[string]interface{}) + + payload := frontdoor.WebApplicationFirewallPolicy{ + Location: utils.String(location.Normalize("Global")), + Sku: &frontdoor.Sku{ + Name: frontdoor.SkuName(sku), + }, + WebApplicationFirewallPolicyProperties: &frontdoor.WebApplicationFirewallPolicyProperties{ + PolicySettings: &frontdoor.PolicySettings{ + EnabledState: enabled, + Mode: mode, + }, + CustomRules: expandCdnFrontDoorFirewallCustomRules(customRules), + }, + Tags: expandFrontDoorTags(tags.Expand(t)), + } + + if managedRules != nil { + payload.WebApplicationFirewallPolicyProperties.ManagedRules = managedRules + } + + if redirectUrl != "" { + payload.WebApplicationFirewallPolicyProperties.PolicySettings.RedirectURL = utils.String(redirectUrl) + } + + if customBlockResponseBody != "" { + payload.WebApplicationFirewallPolicyProperties.PolicySettings.CustomBlockResponseBody = utils.String(customBlockResponseBody) + } + + if customBlockResponseStatusCode > 0 { + payload.WebApplicationFirewallPolicyProperties.PolicySettings.CustomBlockResponseStatusCode = utils.Int32(int32(customBlockResponseStatusCode)) + } + + future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.FrontDoorWebApplicationFirewallPolicyName, payload) + if err != nil { + return fmt.Errorf("creating %s: %+v", id, err) + } + + if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for the creation of %s: %+v", id, err) + } + + d.SetId(id.ID()) + return resourceCdnFrontDoorFirewallPolicyRead(d, meta) +} + +func resourceCdnFrontDoorFirewallPolicyUpdate(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Cdn.FrontDoorLegacyFirewallPoliciesClient + ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.FrontDoorFirewallPolicyID(d.Id()) + if err != nil { + return err + } + + existing, err := client.Get(ctx, id.ResourceGroup, id.FrontDoorWebApplicationFirewallPolicyName) + if err != nil { + return fmt.Errorf("retrieving %s: %+v", *id, err) + } + + if existing.Sku == nil { + return fmt.Errorf("retrieving %s: `sku` was nil", *id) + } + + if existing.WebApplicationFirewallPolicyProperties == nil { + return fmt.Errorf("retrieving %s: `properties` was nil", *id) + } + + props := *existing.WebApplicationFirewallPolicyProperties + + if d.HasChanges("custom_block_response_body", "custom_block_response_status_code", "enabled", "mode", "redirect_url") { + enabled := frontdoor.PolicyEnabledStateDisabled + if d.Get("enabled").(bool) { + enabled = frontdoor.PolicyEnabledStateEnabled + } + props.PolicySettings = &frontdoor.PolicySettings{ + EnabledState: enabled, + Mode: frontdoor.PolicyMode(d.Get("mode").(string)), + } + + if redirectUrl := d.Get("redirect_url").(string); redirectUrl != "" { + props.PolicySettings.RedirectURL = utils.String(redirectUrl) + } + + if body := d.Get("custom_block_response_body").(string); body != "" { + props.PolicySettings.CustomBlockResponseBody = utils.String(body) + } + + if statusCode := d.Get("custom_block_response_status_code").(int); statusCode > 0 { + props.PolicySettings.CustomBlockResponseStatusCode = utils.Int32(int32(statusCode)) + } + } + + if d.HasChange("custom_rule") { + props.CustomRules = expandCdnFrontDoorFirewallCustomRules(d.Get("custom_rule").([]interface{})) + } + + if d.HasChange("managed_rule") { + managedRules := expandCdnFrontDoorFirewallManagedRules(d.Get("managed_rule").([]interface{})) + if existing.Sku.Name != frontdoor.SkuNamePremiumAzureFrontDoor && managedRules != nil { + return fmt.Errorf("the `managed_rule` field is only supported when using the sku %q, got %q", frontdoor.SkuNamePremiumAzureFrontDoor, existing.Sku.Name) + } + if managedRules != nil { + props.ManagedRules = managedRules + } + } + + if d.HasChange("tags") { + t := d.Get("tags").(map[string]interface{}) + existing.Tags = expandFrontDoorTags(tags.Expand(t)) + } + + existing.WebApplicationFirewallPolicyProperties = &props + future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.FrontDoorWebApplicationFirewallPolicyName, existing) + if err != nil { + return fmt.Errorf("updating %s: %+v", *id, err) + } + if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for the update of %s: %+v", *id, err) + } + + return resourceCdnFrontDoorFirewallPolicyRead(d, meta) +} + +func resourceCdnFrontDoorFirewallPolicyRead(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Cdn.FrontDoorLegacyFirewallPoliciesClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.FrontDoorFirewallPolicyID(d.Id()) + if err != nil { + return err + } + + resp, err := client.Get(ctx, id.ResourceGroup, id.FrontDoorWebApplicationFirewallPolicyName) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[INFO] Cdn Frontdoor Firewall Policy %q does not exist - removing from state", d.Id()) + d.SetId("") + return nil + } + return fmt.Errorf("retrieving %s: %+v", *id, err) + } + + d.Set("name", id.FrontDoorWebApplicationFirewallPolicyName) + d.Set("resource_group_name", id.ResourceGroup) + + skuName := "" + if sku := resp.Sku; sku != nil { + skuName = string(sku.Name) + } + d.Set("sku_name", skuName) + + if properties := resp.WebApplicationFirewallPolicyProperties; properties != nil { + if policy := properties.PolicySettings; policy != nil { + d.Set("enabled", policy.EnabledState == frontdoor.PolicyEnabledStateEnabled) + d.Set("mode", string(policy.Mode)) + d.Set("redirect_url", policy.RedirectURL) + d.Set("custom_block_response_status_code", policy.CustomBlockResponseStatusCode) + d.Set("custom_block_response_body", policy.CustomBlockResponseBody) + } + + if err := d.Set("custom_rule", flattenCdnFrontDoorFirewallCustomRules(properties.CustomRules)); err != nil { + return fmt.Errorf("flattening `custom_rule`: %+v", err) + } + + if err := d.Set("frontend_endpoint_ids", flattenFrontendEndpointLinkSlice(properties.FrontendEndpointLinks)); err != nil { + return fmt.Errorf("flattening `frontend_endpoint_ids`: %+v", err) + } + + if err := d.Set("managed_rule", flattenCdnFrontDoorFirewallManagedRules(properties.ManagedRules)); err != nil { + return fmt.Errorf("flattening `managed_rule`: %+v", err) + } + } + + if err := tags.FlattenAndSet(d, flattenFrontDoorTags(resp.Tags)); err != nil { + return err + } + + return nil +} + +func resourceCdnFrontDoorFirewallPolicyDelete(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Cdn.FrontDoorLegacyFirewallPoliciesClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.FrontDoorFirewallPolicyID(d.Id()) + if err != nil { + return err + } + + future, err := client.Delete(ctx, id.ResourceGroup, id.FrontDoorWebApplicationFirewallPolicyName) + if err != nil { + return fmt.Errorf("deleting %s: %+v", *id, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for the deletion of %s: %+v", *id, err) + } + + return nil +} + +func expandCdnFrontDoorFirewallCustomRules(input []interface{}) *frontdoor.CustomRuleList { + if len(input) == 0 { + return nil + } + + output := make([]frontdoor.CustomRule, 0) + + for _, cr := range input { + custom := cr.(map[string]interface{}) + + enabled := frontdoor.CustomRuleEnabledStateDisabled + if custom["enabled"].(bool) { + enabled = frontdoor.CustomRuleEnabledStateEnabled + } + + name := custom["name"].(string) + priority := int32(custom["priority"].(int)) + ruleType := custom["type"].(string) + rateLimitDurationInMinutes := int32(custom["rate_limit_duration_in_minutes"].(int)) + rateLimitThreshold := int32(custom["rate_limit_threshold"].(int)) + matchConditions := expandCdnFrontDoorFirewallMatchConditions(custom["match_condition"].([]interface{})) + action := custom["action"].(string) + + output = append(output, frontdoor.CustomRule{ + Name: utils.String(name), + Priority: &priority, + EnabledState: enabled, + RuleType: frontdoor.RuleType(ruleType), + RateLimitDurationInMinutes: utils.Int32(rateLimitDurationInMinutes), + RateLimitThreshold: utils.Int32(rateLimitThreshold), + MatchConditions: &matchConditions, + Action: frontdoor.ActionType(action), + }) + } + + return &frontdoor.CustomRuleList{ + Rules: &output, + } +} + +func expandCdnFrontDoorFirewallMatchConditions(input []interface{}) []frontdoor.MatchCondition { + result := make([]frontdoor.MatchCondition, 0) + if len(input) == 0 { + return nil + } + + for _, v := range input { + match := v.(map[string]interface{}) + + matchVariable := match["match_variable"].(string) + selector := match["selector"].(string) + operator := match["operator"].(string) + negateCondition := match["negation_condition"].(bool) + matchValues := match["match_values"].([]interface{}) + transforms := match["transforms"].([]interface{}) + + matchCondition := frontdoor.MatchCondition{ + Operator: frontdoor.Operator(operator), + NegateCondition: &negateCondition, + MatchValue: utils.ExpandStringSlice(matchValues), + Transforms: expandCdnFrontDoorFirewallTransforms(transforms), + } + + if matchVariable != "" { + matchCondition.MatchVariable = frontdoor.MatchVariable(matchVariable) + } + if selector != "" { + matchCondition.Selector = utils.String(selector) + } + + result = append(result, matchCondition) + } + + return result +} + +func expandCdnFrontDoorFirewallTransforms(input []interface{}) *[]frontdoor.TransformType { + result := make([]frontdoor.TransformType, 0) + if len(input) == 0 { + return nil + } + + for _, v := range input { + result = append(result, frontdoor.TransformType(v.(string))) + } + + return &result +} + +func expandCdnFrontDoorFirewallManagedRules(input []interface{}) *frontdoor.ManagedRuleSetList { + if len(input) == 0 { + return nil + } + + result := make([]frontdoor.ManagedRuleSet, 0) + for _, mr := range input { + managedRule := mr.(map[string]interface{}) + + ruleType := managedRule["type"].(string) + version := managedRule["version"].(string) + action := managedRule["action"].(string) + overrides := managedRule["override"].([]interface{}) + exclusions := expandCdnFrontDoorFirewallManagedRuleGroupExclusion(managedRule["exclusion"].([]interface{})) + ruleGroupOverrides := expandCdnFrontDoorFirewallManagedRuleGroupOverride(overrides) + + managedRuleSet := frontdoor.ManagedRuleSet{ + Exclusions: exclusions, + RuleSetVersion: &version, + RuleGroupOverrides: ruleGroupOverrides, + RuleSetType: &ruleType, + } + + if action != "" { + managedRuleSet.RuleSetAction = frontdoor.ManagedRuleSetActionType(action) + } + + result = append(result, managedRuleSet) + } + + return &frontdoor.ManagedRuleSetList{ + ManagedRuleSets: &result, + } +} + +func expandCdnFrontDoorFirewallManagedRuleGroupExclusion(input []interface{}) *[]frontdoor.ManagedRuleExclusion { + results := make([]frontdoor.ManagedRuleExclusion, 0) + if len(input) == 0 { + return nil + } + + for _, v := range input { + exclusion := v.(map[string]interface{}) + + matchVariable := exclusion["match_variable"].(string) + operator := exclusion["operator"].(string) + selector := exclusion["selector"].(string) + + results = append(results, frontdoor.ManagedRuleExclusion{ + MatchVariable: frontdoor.ManagedRuleExclusionMatchVariable(matchVariable), + SelectorMatchOperator: frontdoor.ManagedRuleExclusionSelectorMatchOperator(operator), + Selector: &selector, + }) + } + + return &results +} + +func expandCdnFrontDoorFirewallManagedRuleGroupOverride(input []interface{}) *[]frontdoor.ManagedRuleGroupOverride { + result := make([]frontdoor.ManagedRuleGroupOverride, 0) + if len(input) == 0 { + return nil + } + + for _, v := range input { + override := v.(map[string]interface{}) + + exclusions := expandCdnFrontDoorFirewallManagedRuleGroupExclusion(override["exclusion"].([]interface{})) + ruleGroupName := override["rule_group_name"].(string) + rules := expandCdnFrontDoorFirewallRuleOverride(override["rule"].([]interface{})) + + result = append(result, frontdoor.ManagedRuleGroupOverride{ + Exclusions: exclusions, + RuleGroupName: &ruleGroupName, + Rules: rules, + }) + } + + return &result +} + +func expandCdnFrontDoorFirewallRuleOverride(input []interface{}) *[]frontdoor.ManagedRuleOverride { + result := make([]frontdoor.ManagedRuleOverride, 0) + if len(input) == 0 { + return nil + } + + for _, v := range input { + rule := v.(map[string]interface{}) + + enabled := frontdoor.ManagedRuleEnabledStateDisabled + if rule["enabled"].(bool) { + enabled = frontdoor.ManagedRuleEnabledStateEnabled + } + ruleId := rule["rule_id"].(string) + action := frontdoor.ActionType(rule["action"].(string)) + exclusions := expandCdnFrontDoorFirewallManagedRuleGroupExclusion(rule["exclusion"].([]interface{})) + + result = append(result, frontdoor.ManagedRuleOverride{ + RuleID: &ruleId, + EnabledState: enabled, + Action: action, + Exclusions: exclusions, + }) + } + + return &result +} + +func flattenCdnFrontDoorFirewallCustomRules(input *frontdoor.CustomRuleList) []interface{} { + if input == nil || input.Rules == nil { + return []interface{}{} + } + + results := make([]interface{}, 0) + for _, v := range *input.Rules { + action := "" + if v.Action != "" { + action = string(v.Action) + } + + enabled := false + if v.EnabledState != "" { + enabled = v.EnabledState == frontdoor.CustomRuleEnabledStateEnabled + } + + name := "" + if v.Name != nil { + name = *v.Name + } + + priority := 0 + if v.Priority != nil { + priority = int(*v.Priority) + } + + rateLimitDurationInMinutes := 0 + if v.RateLimitDurationInMinutes != nil { + rateLimitDurationInMinutes = int(*v.RateLimitDurationInMinutes) + } + + rateLimitThreshold := 0 + if v.RateLimitThreshold != nil { + rateLimitThreshold = int(*v.RateLimitThreshold) + } + + ruleType := "" + if v.RuleType != "" { + ruleType = string(v.RuleType) + } + + results = append(results, map[string]interface{}{ + "action": action, + "enabled": enabled, + "match_condition": flattenCdnFrontDoorFirewallMatchConditions(v.MatchConditions), + "rate_limit_duration_in_minutes": rateLimitDurationInMinutes, + "rate_limit_threshold": rateLimitThreshold, + "priority": priority, + "name": name, + "type": ruleType, + }) + } + + return results +} + +func flattenCdnFrontDoorFirewallMatchConditions(input *[]frontdoor.MatchCondition) []interface{} { + if input == nil { + return []interface{}{} + } + + results := make([]interface{}, 0) + for _, v := range *input { + selector := "" + if v.Selector != nil { + selector = *v.Selector + } + + negateCondition := false + if v.NegateCondition != nil { + negateCondition = *v.NegateCondition + } + + results = append(results, map[string]interface{}{ + "match_variable": string(v.MatchVariable), + "match_values": v.MatchValue, + "negation_condition": negateCondition, + "operator": string(v.Operator), + "selector": selector, + "transforms": flattenTransformSlice(v.Transforms), + }) + } + + return results +} + +func flattenCdnFrontDoorFirewallManagedRules(input *frontdoor.ManagedRuleSetList) []interface{} { + if input == nil || input.ManagedRuleSets == nil { + return []interface{}{} + } + + results := make([]interface{}, 0) + for _, r := range *input.ManagedRuleSets { + ruleSetType := "" + if r.RuleSetType != nil { + ruleSetType = *r.RuleSetType + } + + ruleSetVersion := "" + if r.RuleSetVersion != nil { + ruleSetVersion = *r.RuleSetVersion + } + + ruleSetAction := "" + if r.RuleSetAction != "" { + ruleSetAction = string(r.RuleSetAction) + } + + results = append(results, map[string]interface{}{ + "exclusion": flattenCdnFrontDoorFirewallExclusions(r.Exclusions), + "override": flattenCdnFrontDoorFirewallOverrides(r.RuleGroupOverrides), + "type": ruleSetType, + "version": ruleSetVersion, + "action": ruleSetAction, + }) + } + + return results +} + +func flattenCdnFrontDoorFirewallExclusions(input *[]frontdoor.ManagedRuleExclusion) []interface{} { + if input == nil { + return []interface{}{} + } + + results := make([]interface{}, 0) + for _, v := range *input { + matchVariable := "" + if v.MatchVariable != "" { + matchVariable = string(v.MatchVariable) + } + + operator := "" + if v.SelectorMatchOperator != "" { + operator = string(v.SelectorMatchOperator) + } + + selector := "" + if v.Selector != nil { + selector = *v.Selector + } + + results = append(results, map[string]interface{}{ + "match_variable": matchVariable, + "operator": operator, + "selector": selector, + }) + } + + return results +} + +func flattenCdnFrontDoorFirewallOverrides(input *[]frontdoor.ManagedRuleGroupOverride) []interface{} { + if input == nil { + return []interface{}{} + } + + results := make([]interface{}, 0) + for _, v := range *input { + ruleGroupName := "" + if v.RuleGroupName != nil { + ruleGroupName = *v.RuleGroupName + } + + results = append(results, map[string]interface{}{ + "rule_group_name": ruleGroupName, + "exclusion": flattenCdnFrontDoorFirewallExclusions(v.Exclusions), + "rule": flattenCdnFrontDoorFirewallRules(v.Rules), + }) + } + + return results +} + +func flattenCdnFrontDoorFirewallRules(input *[]frontdoor.ManagedRuleOverride) []interface{} { + if input == nil { + return []interface{}{} + } + + results := make([]interface{}, 0) + for _, v := range *input { + action := "" + if v.Action != "" { + action = string(v.Action) + } + + enabled := false + if v.EnabledState != "" { + enabled = v.EnabledState == frontdoor.ManagedRuleEnabledStateEnabled + } + + ruleId := "" + if v.RuleID != nil { + ruleId = *v.RuleID + } + + results = append(results, map[string]interface{}{ + "action": action, + "enabled": enabled, + "exclusion": flattenCdnFrontDoorFirewallExclusions(v.Exclusions), + "rule_id": ruleId, + }) + } + + return results +} diff --git a/internal/services/cdn/cdn_frontdoor_firewall_policy_resource_test.go b/internal/services/cdn/cdn_frontdoor_firewall_policy_resource_test.go new file mode 100644 index 000000000000..662635fcc8e7 --- /dev/null +++ b/internal/services/cdn/cdn_frontdoor_firewall_policy_resource_test.go @@ -0,0 +1,341 @@ +package cdn_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type CdnFrontDoorFirewallPolicyResource struct{} + +func TestAccCdnFrontDoorFirewallPolicy_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_firewall_policy", "test") + r := CdnFrontDoorFirewallPolicyResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccCdnFrontDoorFirewallPolicy_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_firewall_policy", "test") + r := CdnFrontDoorFirewallPolicyResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func TestAccCdnFrontDoorFirewallPolicy_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_firewall_policy", "test") + r := CdnFrontDoorFirewallPolicyResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.update(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.update(data), + Check: acceptance.ComposeTestCheckFunc(), + }, + data.ImportStep(), + }) +} + +func TestAccCdnFrontDoorFirewallPolicy_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_firewall_policy", "test") + r := CdnFrontDoorFirewallPolicyResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func (CdnFrontDoorFirewallPolicyResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + id, err := parse.FrontDoorFirewallPolicyIDInsensitively(state.ID) + if err != nil { + return nil, err + } + + resp, err := clients.Cdn.FrontDoorLegacyFirewallPoliciesClient.Get(ctx, id.ResourceGroup, id.FrontDoorWebApplicationFirewallPolicyName) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return utils.Bool(false), nil + } + return nil, fmt.Errorf("retrieving %s: %+v", id, err) + } + + return utils.Bool(true), nil +} + +func (CdnFrontDoorFirewallPolicyResource) template(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-cdn-afdx-%d" + location = "%s" +} + +resource "azurerm_cdn_frontdoor_profile" "test" { + name = "accTestProfile-%[1]d" + resource_group_name = azurerm_resource_group.test.name + sku_name = "Premium_AzureFrontDoor" +} +`, data.RandomInteger, data.Locations.Primary) +} + +func (r CdnFrontDoorFirewallPolicyResource) basic(data acceptance.TestData) string { + tmp := r.template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_cdn_frontdoor_firewall_policy" "test" { + name = "accTestWAF%d" + resource_group_name = azurerm_resource_group.test.name + sku_name = azurerm_cdn_frontdoor_profile.test.sku_name + mode = "Prevention" +} +`, tmp, data.RandomInteger) +} + +func (r CdnFrontDoorFirewallPolicyResource) requiresImport(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_cdn_frontdoor_firewall_policy" "import" { + name = azurerm_cdn_frontdoor_firewall_policy.test.name + resource_group_name = azurerm_cdn_frontdoor_firewall_policy.test.resource_group_name + sku_name = azurerm_cdn_frontdoor_profile.test.sku_name + mode = "Prevention" +} +`, r.basic(data)) +} + +func (r CdnFrontDoorFirewallPolicyResource) update(data acceptance.TestData) string { + tmp := r.template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_cdn_frontdoor_firewall_policy" "test" { + name = "accTestWAF%d" + resource_group_name = azurerm_resource_group.test.name + sku_name = azurerm_cdn_frontdoor_profile.test.sku_name + enabled = true + mode = "Detection" + redirect_url = "https://www.contoso.com" + custom_block_response_status_code = 403 + custom_block_response_body = "PGh0bWw+CjxoZWFkZXI+PHRpdGxlPkhlbGxvPC90aXRsZT48L2hlYWRlcj4KPGJvZHk+CkhlbGxvIHdvcmxkCjwvYm9keT4KPC9odG1sPg==" + + custom_rule { + name = "Rule1" + enabled = true + priority = 1 + rate_limit_duration_in_minutes = 1 + rate_limit_threshold = 10 + type = "MatchRule" + action = "Block" + + match_condition { + match_variable = "RemoteAddr" + operator = "IPMatch" + negation_condition = false + match_values = ["192.168.1.0/24", "10.0.0.0/24"] + } + } + + managed_rule { + type = "DefaultRuleSet" + version = "preview-0.1" + action = "Block" + + override { + rule_group_name = "PHP" + + rule { + rule_id = "933111" + enabled = false + action = "Block" + } + } + } + + managed_rule { + type = "BotProtection" + version = "preview-0.1" + action = "Log" + } +} +`, tmp, data.RandomInteger) +} + +func (r CdnFrontDoorFirewallPolicyResource) complete(data acceptance.TestData) string { + tmp := r.template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_cdn_frontdoor_firewall_policy" "test" { + name = "accTestWAF%d" + resource_group_name = azurerm_resource_group.test.name + sku_name = azurerm_cdn_frontdoor_profile.test.sku_name + enabled = true + mode = "Prevention" + redirect_url = "https://www.contoso.com" + custom_block_response_status_code = 403 + custom_block_response_body = "PGh0bWw+CjxoZWFkZXI+PHRpdGxlPkhlbGxvPC90aXRsZT48L2hlYWRlcj4KPGJvZHk+CkhlbGxvIHdvcmxkCjwvYm9keT4KPC9odG1sPg==" + + custom_rule { + name = "Rule1" + enabled = true + priority = 1 + rate_limit_duration_in_minutes = 1 + rate_limit_threshold = 10 + type = "MatchRule" + action = "Block" + + match_condition { + match_variable = "RemoteAddr" + operator = "IPMatch" + negation_condition = false + match_values = ["192.168.1.0/24", "10.0.0.0/24"] + } + } + + custom_rule { + name = "Rule2" + enabled = true + priority = 2 + rate_limit_duration_in_minutes = 1 + rate_limit_threshold = 10 + type = "MatchRule" + action = "Block" + + match_condition { + match_variable = "RemoteAddr" + operator = "IPMatch" + negation_condition = false + match_values = ["192.168.1.0/24"] + } + + match_condition { + match_variable = "RequestHeader" + selector = "UserAgent" + operator = "Contains" + negation_condition = false + match_values = ["windows"] + transforms = ["Lowercase", "Trim"] + } + } + + custom_rule { + name = "Rule3" + enabled = true + priority = 3 + rate_limit_duration_in_minutes = 1 + rate_limit_threshold = 10 + type = "MatchRule" + action = "Block" + + match_condition { + match_variable = "SocketAddr" + operator = "IPMatch" + negation_condition = false + match_values = ["192.168.1.0/24"] + } + + match_condition { + match_variable = "RequestHeader" + selector = "UserAgent" + operator = "Contains" + negation_condition = false + match_values = ["windows"] + transforms = ["Lowercase", "Trim"] + } + } + + managed_rule { + type = "DefaultRuleSet" + version = "1.0" + action = "Block" + + exclusion { + match_variable = "QueryStringArgNames" + operator = "Equals" + selector = "not_suspicious" + } + + override { + rule_group_name = "PHP" + + rule { + rule_id = "933100" + enabled = false + action = "Block" + } + } + + override { + rule_group_name = "SQLI" + + exclusion { + match_variable = "QueryStringArgNames" + operator = "Equals" + selector = "really_not_suspicious" + } + + rule { + rule_id = "942200" + action = "Block" + + exclusion { + match_variable = "QueryStringArgNames" + operator = "Equals" + selector = "innocent" + } + } + } + } + + managed_rule { + type = "Microsoft_BotManagerRuleSet" + version = "1.0" + action = "Block" + } +} +`, tmp, data.RandomInteger) +} diff --git a/internal/services/cdn/cdn_frontdoor_helpers.go b/internal/services/cdn/cdn_frontdoor_helpers.go index 1f8b655f0513..ef922d70f694 100644 --- a/internal/services/cdn/cdn_frontdoor_helpers.go +++ b/internal/services/cdn/cdn_frontdoor_helpers.go @@ -1,6 +1,9 @@ package cdn -import "github.com/Azure/azure-sdk-for-go/services/cdn/mgmt/2021-06-01/cdn" +import ( + "github.com/Azure/azure-sdk-for-go/services/cdn/mgmt/2021-06-01/cdn" + "github.com/Azure/azure-sdk-for-go/services/frontdoor/mgmt/2020-11-01/frontdoor" +) func expandEnabledBool(isEnabled bool) cdn.EnabledState { if isEnabled { @@ -13,3 +16,59 @@ func expandEnabledBool(isEnabled bool) cdn.EnabledState { func flattenEnabledBool(input cdn.EnabledState) bool { return input == cdn.EnabledStateEnabled } + +func expandFrontDoorTags(tagMap *map[string]string) map[string]*string { + t := make(map[string]*string) + + if tagMap != nil { + for k, v := range *tagMap { + tagKey := k + tagValue := v + t[tagKey] = &tagValue + } + } + + return t +} + +func flattenFrontDoorTags(tagMap map[string]*string) *map[string]string { + t := make(map[string]string) + + for k, v := range tagMap { + tagKey := k + tagValue := v + if tagValue == nil { + continue + } + t[tagKey] = *tagValue + } + + return &t +} + +func flattenTransformSlice(input *[]frontdoor.TransformType) []interface{} { + result := make([]interface{}, 0) + + if input != nil { + for _, item := range *input { + result = append(result, string(item)) + } + } + return result +} + +func flattenFrontendEndpointLinkSlice(input *[]frontdoor.FrontendEndpointLink) []interface{} { + result := make([]interface{}, 0) + + if input != nil { + for _, item := range *input { + if item.ID == nil { + continue + } + + result = append(result, *item.ID) + } + } + + return result +} diff --git a/internal/services/cdn/cdn_frontdoor_origin_group_data_source.go b/internal/services/cdn/cdn_frontdoor_origin_group_data_source.go new file mode 100644 index 000000000000..2e5b07e9dee1 --- /dev/null +++ b/internal/services/cdn/cdn_frontdoor_origin_group_data_source.go @@ -0,0 +1,144 @@ +package cdn + +import ( + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/validate" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +func dataSourceCdnFrontDoorOriginGroup() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Read: dataSourceCdnFrontDoorOriginGroupRead, + + Timeouts: &pluginsdk.ResourceTimeout{ + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validate.FrontDoorOriginGroupName, + }, + + "profile_name": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validate.FrontDoorName, + }, + + "resource_group_name": commonschema.ResourceGroupNameForDataSource(), + + // Computed + "cdn_frontdoor_profile_id": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "health_probe": { + Type: pluginsdk.TypeList, + Computed: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "interval_in_seconds": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + "path": { + Type: pluginsdk.TypeString, + Computed: true, + }, + "protocol": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "request_type": { + Type: pluginsdk.TypeString, + Computed: true, + }, + }, + }, + }, + + "load_balancing": { + Type: pluginsdk.TypeList, + Computed: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "additional_latency_in_milliseconds": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "sample_size": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "successful_samples_required": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + }, + }, + }, + + "restore_traffic_time_to_healed_or_new_endpoint_in_minutes": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "session_affinity_enabled": { + Type: pluginsdk.TypeBool, + Computed: true, + }, + }, + } +} + +func dataSourceCdnFrontDoorOriginGroupRead(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Cdn.FrontDoorOriginGroupsClient + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id := parse.NewFrontDoorOriginGroupID(subscriptionId, d.Get("resource_group_name").(string), d.Get("profile_name").(string), d.Get("name").(string)) + resp, err := client.Get(ctx, id.ResourceGroup, id.ProfileName, id.OriginGroupName) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("%s was not found", id) + } + + return fmt.Errorf("retrieving %s: %+v", id, err) + } + + d.SetId(id.ID()) + d.Set("name", id.OriginGroupName) + d.Set("profile_name", id.ProfileName) + d.Set("resource_group_name", id.ResourceGroup) + d.Set("cdn_frontdoor_profile_id", parse.NewFrontDoorProfileID(id.SubscriptionId, id.ResourceGroup, id.ProfileName).ID()) + + if props := resp.AFDOriginGroupProperties; props != nil { + if err := d.Set("health_probe", flattenCdnFrontDoorOriginGroupHealthProbeParameters(props.HealthProbeSettings)); err != nil { + return fmt.Errorf("setting `health_probe`: %+v", err) + } + + if err := d.Set("load_balancing", flattenCdnFrontDoorOriginGroupLoadBalancingSettingsParameters(props.LoadBalancingSettings)); err != nil { + return fmt.Errorf("setting `load_balancing`: %+v", err) + } + + d.Set("session_affinity_enabled", flattenEnabledBool(props.SessionAffinityState)) + d.Set("restore_traffic_time_to_healed_or_new_endpoint_in_minutes", props.TrafficRestorationTimeToHealedOrNewEndpointsInMinutes) + } + + return nil +} diff --git a/internal/services/cdn/cdn_frontdoor_origin_group_data_source_test.go b/internal/services/cdn/cdn_frontdoor_origin_group_data_source_test.go new file mode 100644 index 000000000000..8b13006a5e0d --- /dev/null +++ b/internal/services/cdn/cdn_frontdoor_origin_group_data_source_test.go @@ -0,0 +1,37 @@ +package cdn_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" +) + +type CdnFrontDoorOriginGroupDataSource struct{} + +func TestAccCdnFrontDoorOriginGroupDataSource_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_cdn_frontdoor_origin_group", "test") + d := CdnFrontDoorOriginGroupDataSource{} + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: d.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("cdn_frontdoor_profile_id").MatchesOtherKey(check.That("azurerm_cdn_frontdoor_profile.test").Key("id")), + ), + }, + }) +} + +func (CdnFrontDoorOriginGroupDataSource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +data "azurerm_cdn_frontdoor_origin_group" "test" { + name = azurerm_cdn_frontdoor_origin_group.test.name + profile_name = azurerm_cdn_frontdoor_profile.test.name + resource_group_name = azurerm_cdn_frontdoor_profile.test.resource_group_name +} +`, CdnFrontDoorOriginGroupResource{}.complete(data)) +} diff --git a/internal/services/cdn/cdn_frontdoor_origin_group_resource.go b/internal/services/cdn/cdn_frontdoor_origin_group_resource.go new file mode 100644 index 000000000000..4d38f2b1bada --- /dev/null +++ b/internal/services/cdn/cdn_frontdoor_origin_group_resource.go @@ -0,0 +1,381 @@ +package cdn + +import ( + "fmt" + "time" + + "github.com/Azure/azure-sdk-for-go/services/cdn/mgmt/2021-06-01/cdn" + "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/validate" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +func resourceCdnFrontDoorOriginGroup() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Create: resourceCdnFrontDoorOriginGroupCreate, + Read: resourceCdnFrontDoorOriginGroupRead, + Update: resourceCdnFrontDoorOriginGroupUpdate, + Delete: resourceCdnFrontDoorOriginGroupDelete, + + Timeouts: &pluginsdk.ResourceTimeout{ + Create: pluginsdk.DefaultTimeout(30 * time.Minute), + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + Update: pluginsdk.DefaultTimeout(30 * time.Minute), + Delete: pluginsdk.DefaultTimeout(30 * time.Minute), + }, + + Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { + _, err := parse.FrontDoorOriginGroupID(id) + return err + }), + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.FrontDoorOriginGroupName, + }, + + "cdn_frontdoor_profile_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.FrontDoorProfileID, + }, + + "load_balancing": { + Type: pluginsdk.TypeList, + Required: true, + MaxItems: 1, + + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "additional_latency_in_milliseconds": { + Type: pluginsdk.TypeInt, + Optional: true, + Default: 50, + ValidateFunc: validation.IntBetween(0, 1000), + }, + + "sample_size": { + Type: pluginsdk.TypeInt, + Optional: true, + Default: 4, + ValidateFunc: validation.IntBetween(0, 255), + }, + + "successful_samples_required": { + Type: pluginsdk.TypeInt, + Optional: true, + Default: 3, + ValidateFunc: validation.IntBetween(0, 255), + }, + }, + }, + }, + + // Optional + "health_probe": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 1, + + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "protocol": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(cdn.ProbeProtocolHTTP), + string(cdn.ProbeProtocolHTTPS), + }, false), + }, + + "request_type": { + Type: pluginsdk.TypeString, + Optional: true, + Default: string(cdn.HealthProbeRequestTypeHEAD), + ValidateFunc: validation.StringInSlice([]string{ + string(cdn.HealthProbeRequestTypeGET), + string(cdn.HealthProbeRequestTypeHEAD), + }, false), + }, + + "interval_in_seconds": { + Type: pluginsdk.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(5, 31536000), + }, + + "path": { + Type: pluginsdk.TypeString, + Optional: true, + Default: "/", + ValidateFunc: validation.StringIsNotEmpty, + }, + }, + }, + }, + + "session_affinity_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: true, + }, + + "restore_traffic_time_to_healed_or_new_endpoint_in_minutes": { + Type: pluginsdk.TypeInt, + Optional: true, + Default: 10, + ValidateFunc: validation.IntBetween(0, 50), + }, + }, + } +} + +func resourceCdnFrontDoorOriginGroupCreate(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Cdn.FrontDoorOriginGroupsClient + ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) + defer cancel() + + profileId, err := parse.FrontDoorProfileID(d.Get("cdn_frontdoor_profile_id").(string)) + if err != nil { + return err + } + + id := parse.NewFrontDoorOriginGroupID(profileId.SubscriptionId, profileId.ResourceGroup, profileId.ProfileName, d.Get("name").(string)) + existing, err := client.Get(ctx, id.ResourceGroup, id.ProfileName, id.OriginGroupName) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("checking for existing %s: %+v", id, err) + } + } + + if !utils.ResponseWasNotFound(existing.Response) { + return tf.ImportAsExistsError("azurerm_cdn_frontdoor_origin_group", id.ID()) + } + + props := cdn.AFDOriginGroup{ + AFDOriginGroupProperties: &cdn.AFDOriginGroupProperties{ + HealthProbeSettings: expandCdnFrontDoorOriginGroupHealthProbeParameters(d.Get("health_probe").([]interface{})), + LoadBalancingSettings: expandCdnFrontDoorOriginGroupLoadBalancingSettingsParameters(d.Get("load_balancing").([]interface{})), + SessionAffinityState: expandEnabledBool(d.Get("session_affinity_enabled").(bool)), + TrafficRestorationTimeToHealedOrNewEndpointsInMinutes: utils.Int32(int32(d.Get("restore_traffic_time_to_healed_or_new_endpoint_in_minutes").(int))), + }, + } + + future, err := client.Create(ctx, id.ResourceGroup, id.ProfileName, id.OriginGroupName, props) + if err != nil { + return fmt.Errorf("creating %s: %+v", id, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for the creation of %s: %+v", id, err) + } + + d.SetId(id.ID()) + return resourceCdnFrontDoorOriginGroupRead(d, meta) +} + +func resourceCdnFrontDoorOriginGroupRead(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Cdn.FrontDoorOriginGroupsClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.FrontDoorOriginGroupID(d.Id()) + if err != nil { + return err + } + + resp, err := client.Get(ctx, id.ResourceGroup, id.ProfileName, id.OriginGroupName) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + d.SetId("") + return nil + } + return fmt.Errorf("retrieving %s: %+v", id, err) + } + + d.Set("name", id.OriginGroupName) + d.Set("cdn_frontdoor_profile_id", parse.NewFrontDoorProfileID(id.SubscriptionId, id.ResourceGroup, id.ProfileName).ID()) + + if props := resp.AFDOriginGroupProperties; props != nil { + if err := d.Set("health_probe", flattenCdnFrontDoorOriginGroupHealthProbeParameters(props.HealthProbeSettings)); err != nil { + return fmt.Errorf("setting `health_probe`: %+v", err) + } + + if err := d.Set("load_balancing", flattenCdnFrontDoorOriginGroupLoadBalancingSettingsParameters(props.LoadBalancingSettings)); err != nil { + return fmt.Errorf("setting `load_balancing`: %+v", err) + } + + d.Set("session_affinity_enabled", flattenEnabledBool(props.SessionAffinityState)) + d.Set("restore_traffic_time_to_healed_or_new_endpoint_in_minutes", props.TrafficRestorationTimeToHealedOrNewEndpointsInMinutes) + } + + return nil +} + +func resourceCdnFrontDoorOriginGroupUpdate(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Cdn.FrontDoorOriginGroupsClient + ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.FrontDoorOriginGroupID(d.Id()) + if err != nil { + return err + } + + params := &cdn.AFDOriginGroupUpdatePropertiesParameters{} + + if d.HasChange("health_probe") { + params.HealthProbeSettings = expandCdnFrontDoorOriginGroupHealthProbeParameters(d.Get("health_probe").([]interface{})) + } + + if d.HasChange("load_balancing") { + params.LoadBalancingSettings = expandCdnFrontDoorOriginGroupLoadBalancingSettingsParameters(d.Get("load_balancing").([]interface{})) + } + + if d.HasChange("restore_traffic_time_to_healed_or_new_endpoint_in_minutes") { + params.TrafficRestorationTimeToHealedOrNewEndpointsInMinutes = utils.Int32(int32(d.Get("restore_traffic_time_to_healed_or_new_endpoint_in_minutes").(int))) + } + + if d.HasChange("session_affinity_enabled") { + params.SessionAffinityState = expandEnabledBool(d.Get("session_affinity_enabled").(bool)) + } + + payload := cdn.AFDOriginGroupUpdateParameters{ + AFDOriginGroupUpdatePropertiesParameters: params, + } + + future, err := client.Update(ctx, id.ResourceGroup, id.ProfileName, id.OriginGroupName, payload) + if err != nil { + return fmt.Errorf("updating %s: %+v", *id, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for the update of %s: %+v", *id, err) + } + + return resourceCdnFrontDoorOriginGroupRead(d, meta) +} + +func resourceCdnFrontDoorOriginGroupDelete(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Cdn.FrontDoorOriginGroupsClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.FrontDoorOriginGroupID(d.Id()) + if err != nil { + return err + } + + future, err := client.Delete(ctx, id.ResourceGroup, id.ProfileName, id.OriginGroupName) + if err != nil { + return fmt.Errorf("deleting %s: %+v", *id, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for the deletion of %s: %+v", *id, err) + } + return nil +} + +func expandCdnFrontDoorOriginGroupHealthProbeParameters(input []interface{}) *cdn.HealthProbeParameters { + if len(input) == 0 || input[0] == nil { + return nil + } + + v := input[0].(map[string]interface{}) + + probeProtocolValue := cdn.ProbeProtocol(v["protocol"].(string)) + probeRequestTypeValue := cdn.HealthProbeRequestType(v["request_type"].(string)) + return &cdn.HealthProbeParameters{ + ProbeIntervalInSeconds: utils.Int32(int32(v["interval_in_seconds"].(int))), + ProbePath: utils.String(v["path"].(string)), + ProbeProtocol: probeProtocolValue, + ProbeRequestType: probeRequestTypeValue, + } +} + +func expandCdnFrontDoorOriginGroupLoadBalancingSettingsParameters(input []interface{}) *cdn.LoadBalancingSettingsParameters { + if len(input) == 0 || input[0] == nil { + return nil + } + + v := input[0].(map[string]interface{}) + + return &cdn.LoadBalancingSettingsParameters{ + AdditionalLatencyInMilliseconds: utils.Int32(int32(v["additional_latency_in_milliseconds"].(int))), + SampleSize: utils.Int32(int32(v["sample_size"].(int))), + SuccessfulSamplesRequired: utils.Int32(int32(v["successful_samples_required"].(int))), + } +} + +func flattenCdnFrontDoorOriginGroupLoadBalancingSettingsParameters(input *cdn.LoadBalancingSettingsParameters) []interface{} { + if input == nil { + return []interface{}{} + } + + additionalLatencyInMilliseconds := 0 + if input.AdditionalLatencyInMilliseconds != nil { + additionalLatencyInMilliseconds = int(*input.AdditionalLatencyInMilliseconds) + } + + sampleSize := 0 + if input.SampleSize != nil { + sampleSize = int(*input.SampleSize) + } + + successfulSamplesRequired := 0 + if input.SuccessfulSamplesRequired != nil { + successfulSamplesRequired = int(*input.SuccessfulSamplesRequired) + } + return []interface{}{ + map[string]interface{}{ + "additional_latency_in_milliseconds": additionalLatencyInMilliseconds, + "sample_size": sampleSize, + "successful_samples_required": successfulSamplesRequired, + }, + } +} + +func flattenCdnFrontDoorOriginGroupHealthProbeParameters(input *cdn.HealthProbeParameters) []interface{} { + if input == nil { + return []interface{}{} + } + + intervalInSeconds := 0 + if input.ProbeIntervalInSeconds != nil { + intervalInSeconds = int(*input.ProbeIntervalInSeconds) + } + + path := "" + if input.ProbePath != nil { + path = *input.ProbePath + } + + protocol := "" + if input.ProbeProtocol != "" { + protocol = string(input.ProbeProtocol) + } + + requestType := "" + if input.ProbeRequestType != "" { + requestType = string(input.ProbeRequestType) + } + + return []interface{}{ + map[string]interface{}{ + "interval_in_seconds": intervalInSeconds, + "path": path, + "protocol": protocol, + "request_type": requestType, + }, + } +} diff --git a/internal/services/cdn/cdn_frontdoor_origin_group_resource_test.go b/internal/services/cdn/cdn_frontdoor_origin_group_resource_test.go new file mode 100644 index 000000000000..3952cb60f74a --- /dev/null +++ b/internal/services/cdn/cdn_frontdoor_origin_group_resource_test.go @@ -0,0 +1,212 @@ +package cdn_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type CdnFrontDoorOriginGroupResource struct{} + +func TestAccCdnFrontDoorOriginGroup_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_origin_group", "test") + r := CdnFrontDoorOriginGroupResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccCdnFrontDoorOriginGroup_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_origin_group", "test") + r := CdnFrontDoorOriginGroupResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func TestAccCdnFrontDoorOriginGroup_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_origin_group", "test") + r := CdnFrontDoorOriginGroupResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccCdnFrontDoorOriginGroup_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_origin_group", "test") + r := CdnFrontDoorOriginGroupResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.update(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func (r CdnFrontDoorOriginGroupResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + id, err := parse.FrontDoorOriginGroupID(state.ID) + if err != nil { + return nil, err + } + + client := clients.Cdn.FrontDoorOriginGroupsClient + resp, err := client.Get(ctx, id.ResourceGroup, id.ProfileName, id.OriginGroupName) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return utils.Bool(false), nil + } + return nil, fmt.Errorf("retrieving %s: %+v", id, err) + } + return utils.Bool(true), nil +} + +func (r CdnFrontDoorOriginGroupResource) basic(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +%s + +resource "azurerm_cdn_frontdoor_origin_group" "test" { + name = "acctest-origingroup-%d" + cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.test.id + + load_balancing { + } +} +`, template, data.RandomInteger) +} + +func (r CdnFrontDoorOriginGroupResource) requiresImport(data acceptance.TestData) string { + config := r.basic(data) + return fmt.Sprintf(` +%s + +resource "azurerm_cdn_frontdoor_origin_group" "import" { + name = azurerm_cdn_frontdoor_origin_group.test.name + cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_origin_group.test.cdn_frontdoor_profile_id + + load_balancing { + additional_latency_in_milliseconds = 0 + sample_size = 16 + successful_samples_required = 3 + } +} +`, config) +} + +func (r CdnFrontDoorOriginGroupResource) complete(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +%s + +resource "azurerm_cdn_frontdoor_origin_group" "test" { + name = "acctest-origingroup-%d" + cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.test.id + session_affinity_enabled = true + + restore_traffic_time_to_healed_or_new_endpoint_in_minutes = 10 + + health_probe { + interval_in_seconds = 240 + path = "/" + protocol = "Https" + request_type = "GET" + } + + load_balancing { + additional_latency_in_milliseconds = 0 + sample_size = 16 + successful_samples_required = 3 + } +} +`, template, data.RandomInteger) +} + +func (r CdnFrontDoorOriginGroupResource) update(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +%s + +resource "azurerm_cdn_frontdoor_origin_group" "test" { + name = "acctest-origingroup-%d" + cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.test.id + session_affinity_enabled = false + + restore_traffic_time_to_healed_or_new_endpoint_in_minutes = 15 + + health_probe { + interval_in_seconds = 120 + path = "/healthProbe" + protocol = "Http" + request_type = "HEAD" + } + + load_balancing { + additional_latency_in_milliseconds = 32 + sample_size = 32 + successful_samples_required = 5 + } +} +`, template, data.RandomInteger) +} + +func (r CdnFrontDoorOriginGroupResource) template(data acceptance.TestData) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestrg-cdn-afdx-%d" + location = "%s" +} + +resource "azurerm_cdn_frontdoor_profile" "test" { + name = "acctest-cdnfdprofile-%d" + resource_group_name = azurerm_resource_group.test.name + sku_name = "Standard_AzureFrontDoor" +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger) +} diff --git a/internal/services/cdn/cdn_frontdoor_origin_resource.go b/internal/services/cdn/cdn_frontdoor_origin_resource.go new file mode 100644 index 000000000000..57488160ad27 --- /dev/null +++ b/internal/services/cdn/cdn_frontdoor_origin_resource.go @@ -0,0 +1,455 @@ +package cdn + +import ( + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + + "github.com/Azure/azure-sdk-for-go/services/cdn/mgmt/2021-06-01/cdn" + "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" + "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/validate" + privateLinkServiceParse "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +func resourceCdnFrontDoorOrigin() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Create: resourceCdnFrontDoorOriginCreate, + Read: resourceCdnFrontDoorOriginRead, + Update: resourceCdnFrontDoorOriginUpdate, + Delete: resourceCdnFrontDoorOriginDelete, + + Timeouts: &pluginsdk.ResourceTimeout{ + Create: pluginsdk.DefaultTimeout(30 * time.Minute), + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + Update: pluginsdk.DefaultTimeout(30 * time.Minute), + Delete: pluginsdk.DefaultTimeout(30 * time.Minute), + }, + + Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { + _, err := parse.FrontDoorOriginID(id) + return err + }), + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.FrontDoorOriginName, + }, + + "cdn_frontdoor_origin_group_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.FrontDoorOriginGroupID, + }, + + "host_name": { + Type: pluginsdk.TypeString, + // HostName cannot be null or empty. + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "certificate_name_check_enabled": { + Type: pluginsdk.TypeBool, + Required: true, + }, + + "health_probes_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: true, + }, + + "http_port": { + Type: pluginsdk.TypeInt, + Optional: true, + Default: 80, + ValidateFunc: validation.IntBetween(1, 65535), + }, + + "https_port": { + Type: pluginsdk.TypeInt, + Optional: true, + Default: 443, + ValidateFunc: validation.IntBetween(1, 65535), + }, + + // Must be a valid domain name, IPv4 or IPv6 IP Address + "origin_host_header": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.Any(validation.IsIPv6Address, validation.IsIPv4Address, validation.StringIsNotEmpty), + }, + + "priority": { + Type: pluginsdk.TypeInt, + Optional: true, + Default: 1, + ValidateFunc: validation.IntBetween(1, 5), + }, + + "private_link": { + Type: pluginsdk.TypeList, + MaxItems: 1, + Optional: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "location": commonschema.Location(), + + "private_link_target_id": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: azure.ValidateResourceID, + }, + + "request_message": { + Type: pluginsdk.TypeString, + Optional: true, + Default: "Access request for CDN FrontDoor Private Link Origin", + ValidateFunc: validation.StringLenBetween(1, 140), + }, + + "target_type": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + "blob", + "blob_secondary", + "sites", + "web", + }, false), + }, + }, + }, + }, + + "weight": { + Type: pluginsdk.TypeInt, + Optional: true, + Default: 500, + ValidateFunc: validation.IntBetween(1, 1000), + }, + }, + } +} + +func resourceCdnFrontDoorOriginCreate(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Cdn.FrontDoorOriginsClient + profileClient := meta.(*clients.Client).Cdn.FrontDoorProfileClient + ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) + defer cancel() + + originGroupId, err := parse.FrontDoorOriginGroupID(d.Get("cdn_frontdoor_origin_group_id").(string)) + if err != nil { + return err + } + + id := parse.NewFrontDoorOriginID(originGroupId.SubscriptionId, originGroupId.ResourceGroup, originGroupId.ProfileName, originGroupId.OriginGroupName, d.Get("name").(string)) + existing, err := client.Get(ctx, id.ResourceGroup, id.ProfileName, id.OriginGroupName, id.OriginName) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("checking for existing %s: %+v", id, err) + } + } + + if !utils.ResponseWasNotFound(existing.Response) { + return tf.ImportAsExistsError("azurerm_cdn_frontdoor_origin", id.ID()) + } + + // I need to get the profile SKU so I know if it is valid or not to define a private link as + // private links are only allowed in the premium sku... + profileId := parse.NewFrontDoorProfileID(id.SubscriptionId, id.ResourceGroup, id.ProfileName) + + profile, err := profileClient.Get(ctx, profileId.ResourceGroup, profileId.ProfileName) + if err != nil { + if utils.ResponseWasNotFound(profile.Response) { + return fmt.Errorf("retrieving parent %s: not found", profileId) + } + + return fmt.Errorf("retrieving parent %s: %+v", profileId, err) + } + + if profile.Sku == nil { + return fmt.Errorf("retrieving parent %s: `sku` was nil", profileId) + } + skuName := profile.Sku.Name + + enableCertNameCheck := d.Get("certificate_name_check_enabled").(bool) + props := &cdn.AFDOriginProperties{ + EnabledState: expandEnabledBool(d.Get("health_probes_enabled").(bool)), + EnforceCertificateNameCheck: utils.Bool(enableCertNameCheck), + HostName: utils.String(d.Get("host_name").(string)), + HTTPPort: utils.Int32(int32(d.Get("http_port").(int))), + HTTPSPort: utils.Int32(int32(d.Get("https_port").(int))), + Priority: utils.Int32(int32(d.Get("priority").(int))), + Weight: utils.Int32(int32(d.Get("weight").(int))), + } + + if originHostHeader := d.Get("origin_host_header").(string); originHostHeader != "" { + props.OriginHostHeader = utils.String(originHostHeader) + } + + expanded, err := expandPrivateLinkSettings(d.Get("private_link").([]interface{}), skuName, enableCertNameCheck) + if err != nil { + return err + } + props.SharedPrivateLinkResource = expanded + + payload := cdn.AFDOrigin{ + AFDOriginProperties: props, + } + + future, err := client.Create(ctx, id.ResourceGroup, id.ProfileName, id.OriginGroupName, id.OriginName, payload) + if err != nil { + return fmt.Errorf("creating %s: %+v", id, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for the creation of %s: %+v", id, err) + } + + d.SetId(id.ID()) + return resourceCdnFrontDoorOriginRead(d, meta) +} + +func resourceCdnFrontDoorOriginRead(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Cdn.FrontDoorOriginsClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.FrontDoorOriginID(d.Id()) + if err != nil { + return err + } + + resp, err := client.Get(ctx, id.ResourceGroup, id.ProfileName, id.OriginGroupName, id.OriginName) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + d.SetId("") + return nil + } + return fmt.Errorf("retrieving %s: %+v", *id, err) + } + + d.Set("name", id.OriginName) + d.Set("cdn_frontdoor_origin_group_id", parse.NewFrontDoorOriginGroupID(id.SubscriptionId, id.ResourceGroup, id.ProfileName, id.OriginGroupName).ID()) + + if props := resp.AFDOriginProperties; props != nil { + if err := d.Set("private_link", flattenPrivateLinkSettings(props.SharedPrivateLinkResource)); err != nil { + return fmt.Errorf("setting `private_link`: %+v", err) + } + + d.Set("certificate_name_check_enabled", props.EnforceCertificateNameCheck) + d.Set("health_probes_enabled", flattenEnabledBool(props.EnabledState)) + d.Set("host_name", props.HostName) + d.Set("http_port", props.HTTPPort) + d.Set("https_port", props.HTTPSPort) + d.Set("origin_host_header", props.OriginHostHeader) + d.Set("priority", props.Priority) + d.Set("weight", props.Weight) + } + + return nil +} + +func resourceCdnFrontDoorOriginUpdate(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Cdn.FrontDoorOriginsClient + profileClient := meta.(*clients.Client).Cdn.FrontDoorProfileClient + ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.FrontDoorOriginID(d.Id()) + if err != nil { + return err + } + + params := cdn.AFDOriginUpdatePropertiesParameters{} + + if d.HasChange("certificate_name_check_enabled") { + params.EnforceCertificateNameCheck = utils.Bool(d.Get("certificate_name_check_enabled").(bool)) + } + if d.HasChange("health_probes_enabled") { + params.EnabledState = expandEnabledBool(d.Get("health_probes_enabled").(bool)) + } + if d.HasChange("host_name") { + params.HostName = utils.String(d.Get("host_name").(string)) + } + if d.HasChange("http_port") { + params.HTTPPort = utils.Int32(int32(d.Get("http_port").(int))) + } + if d.HasChange("https_port") { + params.HTTPSPort = utils.Int32(int32(d.Get("https_port").(int))) + } + if d.HasChange("origin_host_header") { + params.OriginHostHeader = utils.String(d.Get("origin_host_header").(string)) + } + if d.HasChange("private_link") { + // I need to get the profile SKU so I know if it is valid or not to define a private link as + // private links are only allowed in the premium sku... + profileId := parse.NewFrontDoorProfileID(id.SubscriptionId, id.ResourceGroup, id.ProfileName) + profile, err := profileClient.Get(ctx, profileId.ResourceGroup, profileId.ProfileName) + if err != nil { + if utils.ResponseWasNotFound(profile.Response) { + return fmt.Errorf("retrieving parent %s: not found", profileId) + } + + return fmt.Errorf("retrieving parent %s: %+v", profileId, err) + } + if profile.Sku == nil { + return fmt.Errorf("retrieving parent %s: `sku` was nil", profileId) + } + skuName := profile.Sku.Name + + enableCertNameCheck := d.Get("certificate_name_check_enabled").(bool) + privateLinkSettings, err := expandPrivateLinkSettings(d.Get("private_link").([]interface{}), skuName, enableCertNameCheck) + if err != nil { + return err + } + params.SharedPrivateLinkResource = privateLinkSettings + } + if d.HasChange("priority") { + params.Priority = utils.Int32(int32(d.Get("priority").(int))) + } + if d.HasChange("weight") { + params.Weight = utils.Int32(int32(d.Get("weight").(int))) + } + + payload := cdn.AFDOriginUpdateParameters{ + AFDOriginUpdatePropertiesParameters: ¶ms, + } + future, err := client.Update(ctx, id.ResourceGroup, id.ProfileName, id.OriginGroupName, id.OriginName, payload) + if err != nil { + return fmt.Errorf("updating %s: %+v", *id, err) + } + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for the update of %s: %+v", *id, err) + } + + return resourceCdnFrontDoorOriginRead(d, meta) +} + +func resourceCdnFrontDoorOriginDelete(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Cdn.FrontDoorOriginsClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.FrontDoorOriginID(d.Id()) + if err != nil { + return err + } + + // @tombuildsstuff: JC/WS to dig into if we need to conditionally remove the Private Link + // via an Update before deletion - presumably we'd also need a Lock on the private link resource + + /* + original: + // TODO: Check to see if there is a Load Balancer Private Link connected, + // if so disconnect the Private Link association with the Frontdoor Origin + // else the destroy will fail because the Private Link Service has an active + // Private Link Endpoint connection... + + // It looks like Frontdoor does remove the Private link, I just need to poll here until it is removed... + // Investigate this further... + // WS: There is a bug in the service code, for only the load balancer scenario, the private link connection is not removed until the + // origin is totally destroyed. The workaround for this issue is to put a depends_on the private link service to the origin so the origin + // will be deleted first before the private link service is destroyed. + */ + + future, err := client.Delete(ctx, id.ResourceGroup, id.ProfileName, id.OriginGroupName, id.OriginName) + if err != nil { + return fmt.Errorf("deleting %s: %+v", *id, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for the deletion of %s: %+v", *id, err) + } + + return nil +} + +func expandPrivateLinkSettings(input []interface{}, skuName cdn.SkuName, enableCertNameCheck bool) (*cdn.SharedPrivateLinkResourceProperties, error) { + if len(input) == 0 { + // TODO: Should this return an empty object? + // WS: This cannot return an empty object, the service team requires this to be set to nil else you will get the following error during creation: + // Property 'AfdOrigin.SharedPrivateLinkResource.PrivateLink' is required but it was not set; Property 'AfdOrigin.SharedPrivateLinkResource.RequestMessage' is required but it was not set + return nil, nil + } + + if skuName != cdn.SkuNamePremiumAzureFrontDoor { + return nil, fmt.Errorf("the `private_link` field can only be configured when the Frontdoor Profile is using a %q SKU, got %q", cdn.SkuNamePremiumAzureFrontDoor, skuName) + } + + if !enableCertNameCheck { + return nil, fmt.Errorf("the `private_link` field can only be configured when `certificate_name_check_enabled` is set to `true`") + } + + // Check if this a Load Balancer Private Link or not, the Load Balancer Private Link requires + // that you stand up your own Private Link Service, which is why I am attempting to parse a + // Private Link Service ID here... + settings := input[0].(map[string]interface{}) + targetType := settings["target_type"].(string) + _, err := privateLinkServiceParse.PrivateLinkServiceID(settings["private_link_target_id"].(string)) + if err != nil && targetType == "" { + // It is not a Load Balancer and the Target Type is empty, which is invalid... + return nil, fmt.Errorf("either `private_link` or `target_type` must be specified") + } + + config := input[0].(map[string]interface{}) + + resourceId := config["private_link_target_id"].(string) + location := location.Normalize(config["location"].(string)) + groupId := config["target_type"].(string) + requestMessage := config["request_message"].(string) + + return &cdn.SharedPrivateLinkResourceProperties{ + PrivateLink: &cdn.ResourceReference{ + ID: utils.String(resourceId), + }, + GroupID: utils.String(groupId), + PrivateLinkLocation: utils.String(location), + RequestMessage: utils.String(requestMessage), + }, nil +} + +func flattenPrivateLinkSettings(input *cdn.SharedPrivateLinkResourceProperties) []interface{} { + if input == nil { + return []interface{}{} + } + + privateLinkTargetId := "" + if input.PrivateLink != nil && input.PrivateLink.ID != nil { + privateLinkTargetId = *input.PrivateLink.ID + } + + requestMessage := "" + if input.RequestMessage != nil { + requestMessage = *input.RequestMessage + } + + targetType := "" + if input.GroupID != nil { + targetType = *input.GroupID + } + + return []interface{}{ + map[string]interface{}{ + "location": location.NormalizeNilable(input.PrivateLinkLocation), + "private_link_target_id": privateLinkTargetId, + "request_message": requestMessage, + "target_type": targetType, + }, + } +} diff --git a/internal/services/cdn/cdn_frontdoor_origin_resource_test.go b/internal/services/cdn/cdn_frontdoor_origin_resource_test.go new file mode 100644 index 000000000000..1c696a792ef0 --- /dev/null +++ b/internal/services/cdn/cdn_frontdoor_origin_resource_test.go @@ -0,0 +1,636 @@ +package cdn_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type CdnFrontDoorOriginResource struct { +} + +func TestAccCdnFrontDoorOrigin_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_origin", "test") + r := CdnFrontDoorOriginResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccCdnFrontDoorOrigin_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_origin", "test") + r := CdnFrontDoorOriginResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func TestAccCdnFrontDoorOrigin_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_origin", "test") + r := CdnFrontDoorOriginResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccCdnFrontDoorOrigin_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_origin", "test") + r := CdnFrontDoorOriginResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.update(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccCdnFrontDoorOrigin_privateLinkBlobPrimary(t *testing.T) { + t.Skip("@tombuildsstuff: temporarily skipping until the private link is manually approved as part of the test step") + + data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_origin", "test") + r := CdnFrontDoorOriginResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.privateLinkBlobPrimary(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + // TODO: approve the connection by looking up and updating the private link + // data.CheckWithClient(func(ctx context.Context, clients *clients.Client, state *terraform.InstanceState) error { + // clients.Network.PrivateLinkServiceClient.UpdatePrivateEndpointConnection() + // }), + ), + }, + data.ImportStep(), + }) +} + +func TestAccCdnFrontDoorOrigin_privateLinkStorageStaticWebSite(t *testing.T) { + t.Skip("@tombuildsstuff: temporarily skipping until the private link is manually approved as part of the test step") + + data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_origin", "test") + r := CdnFrontDoorOriginResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.privateLinkStaticWebSite(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + // TODO: approve the connection by looking up and updating the private link + // data.CheckWithClient(func(ctx context.Context, clients *clients.Client, state *terraform.InstanceState) error { + // clients.Network.PrivateLinkServiceClient.UpdatePrivateEndpointConnection() + // }), + ), + }, + data.ImportStep(), + }) +} + +func TestAccCdnFrontDoorOrigin_privateLinkAppServices(t *testing.T) { + t.Skip("@tombuildsstuff: temporarily skipping until the private link is manually approved as part of the test step") + + data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_origin", "test") + r := CdnFrontDoorOriginResource{} + // NOTE: The Private Link will not be approved at this point but it will + // be created. There is currently no way to automate the approval process. + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.privateLinkAppServices(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + // TODO: approve the connection by looking up and updating the private link + // data.CheckWithClient(func(ctx context.Context, clients *clients.Client, state *terraform.InstanceState) error { + // clients.Network.PrivateLinkServiceClient.UpdatePrivateEndpointConnection() + // }), + ), + }, + data.ImportStep(), + }) +} + +func TestAccCdnFrontDoorOrigin_privateLinkLoadBalancer(t *testing.T) { + t.Skip("@tombuildsstuff: temporarily skipping until the private link is manually approved as part of the test step") + + data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_origin", "test") + r := CdnFrontDoorOriginResource{} + + // NOTE: The Private Link will not be approved at this point but it will + // be created. There is currently no way to automate the approval process. + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.privateLinkLoadBalancer(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + // TODO: approve the connection by looking up and updating the private link + // data.CheckWithClient(func(ctx context.Context, clients *clients.Client, state *terraform.InstanceState) error { + // clients.Network.PrivateLinkServiceClient.UpdatePrivateEndpointConnection() + // }), + ), + }, + data.ImportStep(), + }) +} + +func (r CdnFrontDoorOriginResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + id, err := parse.FrontDoorOriginID(state.ID) + if err != nil { + return nil, err + } + + client := clients.Cdn.FrontDoorOriginsClient + resp, err := client.Get(ctx, id.ResourceGroup, id.ProfileName, id.OriginGroupName, id.OriginName) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return utils.Bool(false), nil + } + return nil, fmt.Errorf("retrieving %s: %+v", id, err) + } + + return utils.Bool(true), nil +} + +func (r CdnFrontDoorOriginResource) templatePrivateLinkStorage(data acceptance.TestData) string { + template := r.template(data, "Premium_AzureFrontDoor", false) + return fmt.Sprintf(` + +%s + +resource "azurerm_storage_account" "test" { + name = "acctestsa%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + account_tier = "Premium" + account_replication_type = "LRS" + + allow_nested_items_to_be_public = false + + network_rules { + default_action = "Deny" + } + + tags = { + environment = "Test" + } +} +`, template, data.RandomString) +} + +func (r CdnFrontDoorOriginResource) templatePrivateLinkStorageStaticWebSite(data acceptance.TestData) string { + template := r.template(data, "Premium_AzureFrontDoor", false) + return fmt.Sprintf(` + +%s + +resource "azurerm_storage_account" "test" { + name = "acctestsa%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + account_tier = "Standard" + account_replication_type = "LRS" + account_kind = "StorageV2" + + allow_nested_items_to_be_public = false + + network_rules { + default_action = "Deny" + } + + static_website { + index_document = "index.html" + error_404_document = "404.html" + } + + tags = { + environment = "Test" + } +} +`, template, data.RandomString) +} + +func (r CdnFrontDoorOriginResource) templatePrivateLinkLoadBalancer(data acceptance.TestData) string { + template := r.template(data, "Premium_AzureFrontDoor", true) + return fmt.Sprintf(` +data "azurerm_client_config" "current" {} + +%s + +resource "azurerm_virtual_network" "test" { + name = "acctestvn-%[2]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + address_space = ["10.5.0.0/16"] +} + +resource "azurerm_subnet" "test" { + name = "acctestsn-%[2]d" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.5.1.0/24"] + enforce_private_link_service_network_policies = true +} + +resource "azurerm_public_ip" "test" { + name = "acctestpi-%[2]d" + sku = "Standard" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + allocation_method = "Static" +} + +resource "azurerm_lb" "test" { + name = "acctestlb-%[2]d" + sku = "Standard" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + frontend_ip_configuration { + name = azurerm_public_ip.test.name + public_ip_address_id = azurerm_public_ip.test.id + } +} + +resource "azurerm_private_link_service" "test" { + name = "acctestPLS-%[2]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + + visibility_subscription_ids = [data.azurerm_client_config.current.subscription_id] + load_balancer_frontend_ip_configuration_ids = [azurerm_lb.test.frontend_ip_configuration.0.id] + + nat_ip_configuration { + name = "primary" + private_ip_address = "10.5.1.17" + private_ip_address_version = "IPv4" + subnet_id = azurerm_subnet.test.id + primary = true + } +} +`, template, data.RandomInteger) +} + +func (r CdnFrontDoorOriginResource) templatePrivateLinkWebApp(data acceptance.TestData) string { + template := r.template(data, "Premium_AzureFrontDoor", false) + return fmt.Sprintf(` + +%s + +resource "azurerm_service_plan" "test" { + name = "acctestASP-%[2]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + os_type = "Linux" + sku_name = "P1v3" +} + +resource "azurerm_storage_account" "test" { + name = "acctestsa%[3]s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + account_tier = "Standard" + account_replication_type = "LRS" +} + +resource "azurerm_storage_container" "test" { + name = "testaccsc%[3]s" + storage_account_name = azurerm_storage_account.test.name + container_access_type = "private" +} + +resource "azurerm_storage_share" "test" { + name = "test" + storage_account_name = azurerm_storage_account.test.name + quota = 1 +} + +data "azurerm_storage_account_sas" "test" { + connection_string = azurerm_storage_account.test.primary_connection_string + https_only = true + + resource_types { + service = false + container = false + object = true + } + + services { + blob = true + queue = false + table = false + file = false + } + + start = "2021-04-01" + expiry = "2024-03-30" + + permissions { + read = false + write = true + delete = false + list = false + add = false + create = false + update = false + process = false + tag = false + filter = false + } +} + +resource "azurerm_linux_web_app" "test" { + name = "acctestWA-%[2]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + service_plan_id = azurerm_service_plan.test.id + + site_config {} +} +`, template, data.RandomInteger, data.RandomString) +} + +func (r CdnFrontDoorOriginResource) basic(data acceptance.TestData) string { + template := r.template(data, "Standard_AzureFrontDoor", false) + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +%s + +resource "azurerm_cdn_frontdoor_origin" "test" { + name = "acctest-cdnfdorigin-%d" + cdn_frontdoor_origin_group_id = azurerm_cdn_frontdoor_origin_group.test.id + + health_probes_enabled = true + certificate_name_check_enabled = false + host_name = "contoso.com" + http_port = 80 + https_port = 443 + origin_host_header = "www.contoso.com" + priority = 1 + weight = 1 +} +`, template, data.RandomInteger) +} + +func (r CdnFrontDoorOriginResource) requiresImport(data acceptance.TestData) string { + config := r.basic(data) + return fmt.Sprintf(` +%s + +resource "azurerm_cdn_frontdoor_origin" "import" { + name = azurerm_cdn_frontdoor_origin.test.name + cdn_frontdoor_origin_group_id = azurerm_cdn_frontdoor_origin_group.test.id + + health_probes_enabled = true + certificate_name_check_enabled = false + host_name = "contoso.com" + http_port = 80 + https_port = 443 + origin_host_header = "www.contoso.com" + priority = 1 + weight = 1 +} +`, config) +} + +func (r CdnFrontDoorOriginResource) complete(data acceptance.TestData) string { + template := r.template(data, "Standard_AzureFrontDoor", false) + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +%s + +resource "azurerm_cdn_frontdoor_origin" "test" { + name = "acctest-cdnfdorigin-%d" + cdn_frontdoor_origin_group_id = azurerm_cdn_frontdoor_origin_group.test.id + + health_probes_enabled = true + certificate_name_check_enabled = false + host_name = "contoso.com" + http_port = 80 + https_port = 443 + origin_host_header = "www.contoso.com" + priority = 1 + weight = 1 +} +`, template, data.RandomInteger) +} + +func (r CdnFrontDoorOriginResource) update(data acceptance.TestData) string { + template := r.template(data, "Standard_AzureFrontDoor", false) + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +%s + +resource "azurerm_cdn_frontdoor_origin" "test" { + name = "acctest-cdnfdorigin-%d" + cdn_frontdoor_origin_group_id = azurerm_cdn_frontdoor_origin_group.test.id + + health_probes_enabled = true + certificate_name_check_enabled = false + host_name = "contoso.com" + http_port = 80 + https_port = 443 + origin_host_header = "www.contoso.com" + priority = 1 + weight = 1 +} +`, template, data.RandomInteger) +} + +func (r CdnFrontDoorOriginResource) privateLinkBlobPrimary(data acceptance.TestData) string { + template := r.templatePrivateLinkStorage(data) + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +%s + +resource "azurerm_cdn_frontdoor_origin" "test" { + name = "acctest-cdnfdorigin-%d" + cdn_frontdoor_origin_group_id = azurerm_cdn_frontdoor_origin_group.test.id + + health_probes_enabled = true + certificate_name_check_enabled = true + host_name = azurerm_storage_account.test.primary_blob_host + origin_host_header = azurerm_storage_account.test.primary_blob_host + priority = 1 + weight = 500 + + private_link { + request_message = "Request access for CDN Frontdoor Private Link Origin" + target_type = "blob" + location = azurerm_resource_group.test.location + private_link_target_id = azurerm_storage_account.test.id + } +} +`, template, data.RandomInteger) +} + +func (r CdnFrontDoorOriginResource) privateLinkStaticWebSite(data acceptance.TestData) string { + template := r.templatePrivateLinkStorageStaticWebSite(data) + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +%s + +resource "azurerm_cdn_frontdoor_origin" "test" { + name = "acctest-cdnfdorigin-%d" + cdn_frontdoor_origin_group_id = azurerm_cdn_frontdoor_origin_group.test.id + + health_probes_enabled = true + certificate_name_check_enabled = true + host_name = azurerm_storage_account.test.primary_web_host + origin_host_header = azurerm_storage_account.test.primary_web_host + priority = 1 + weight = 500 + + private_link { + request_message = "Request access for CDN Frontdoor Private Link Origin" + target_type = "web" + location = azurerm_resource_group.test.location + private_link_target_id = azurerm_storage_account.test.id + } +} +`, template, data.RandomInteger) +} + +func (r CdnFrontDoorOriginResource) privateLinkAppServices(data acceptance.TestData) string { + template := r.templatePrivateLinkWebApp(data) + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +%s + +resource "azurerm_cdn_frontdoor_origin" "test" { + name = "acctest-cdnfdorigin-%d" + cdn_frontdoor_origin_group_id = azurerm_cdn_frontdoor_origin_group.test.id + + health_probes_enabled = true + certificate_name_check_enabled = true + host_name = azurerm_linux_web_app.test.default_hostname + origin_host_header = azurerm_linux_web_app.test.default_hostname + priority = 1 + weight = 500 + + private_link { + request_message = "Request access for CDN Frontdoor Private Link Origin" + target_type = "sites" + location = azurerm_resource_group.test.location + private_link_target_id = azurerm_linux_web_app.test.id + } +} +`, template, data.RandomInteger) +} + +func (r CdnFrontDoorOriginResource) privateLinkLoadBalancer(data acceptance.TestData) string { + template := r.templatePrivateLinkLoadBalancer(data) + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +%s + +resource "azurerm_cdn_frontdoor_origin" "test" { + name = "acctest-cdnfdorigin-%d" + cdn_frontdoor_origin_group_id = azurerm_cdn_frontdoor_origin_group.test.id + + health_probes_enabled = true + certificate_name_check_enabled = true + host_name = azurerm_private_link_service.test.nat_ip_configuration.0.private_ip_address + origin_host_header = azurerm_private_link_service.test.nat_ip_configuration.0.private_ip_address + priority = 1 + weight = 500 + + private_link { + request_message = "Request access for CDN Frontdoor Private Link Origin" + location = azurerm_resource_group.test.location + private_link_target_id = azurerm_private_link_service.test.id + } +} +`, template, data.RandomInteger) +} + +func (CdnFrontDoorOriginResource) template(data acceptance.TestData, profileSku string, isLoadBalancer bool) string { + // NOTE: This is a hack for what I believe is a bug in the CDN Frontdoor API. I am currently speaking with the service + // team about how to correctly fix this issue, but in the meantime this is what we need to do to get this scenario to + // work. + var loadBalancerDependsOn string + if isLoadBalancer { + loadBalancerDependsOn = "depends_on = [azurerm_private_link_service.test]" + } + + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestrg-cdn-afdx-%d" + location = "%s" +} + +resource "azurerm_cdn_frontdoor_profile" "test" { + %s + name = "acctest-cdnfdprofile-%d" + resource_group_name = azurerm_resource_group.test.name + sku_name = %q +} + +resource "azurerm_cdn_frontdoor_origin_group" "test" { + name = "acctest-cdnfd-group-%d" + cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.test.id + + load_balancing { + additional_latency_in_milliseconds = 0 + sample_size = 16 + successful_samples_required = 3 + } +} +`, data.RandomInteger, data.Locations.Primary, loadBalancerDependsOn, data.RandomInteger, profileSku, data.RandomInteger) +} diff --git a/internal/services/cdn/cdn_frontdoor_rule_set_data_source_test.go b/internal/services/cdn/cdn_frontdoor_rule_set_data_source_test.go index e8c1b47ccfb3..9ddf20b3ad01 100644 --- a/internal/services/cdn/cdn_frontdoor_rule_set_data_source_test.go +++ b/internal/services/cdn/cdn_frontdoor_rule_set_data_source_test.go @@ -30,8 +30,8 @@ func (CdnFrontDoorRuleSetDataSource) basic(data acceptance.TestData) string { data "azurerm_cdn_frontdoor_rule_set" "test" { name = azurerm_cdn_frontdoor_rule_set.test.name - profile_name = azurerm_cdn_frontdoor_rule_set.test.profile_name - resource_group_name = azurerm_cdn_frontdoor_rule_set.test.resource_group_name + profile_name = azurerm_cdn_frontdoor_profile.test.name + resource_group_name = azurerm_cdn_frontdoor_profile.test.resource_group_name } `, CdnFrontDoorRuleSetResource{}.complete(data)) } diff --git a/internal/services/cdn/cdn_frontdoor_security_policy_resource.go b/internal/services/cdn/cdn_frontdoor_security_policy_resource.go new file mode 100644 index 000000000000..493d02081da9 --- /dev/null +++ b/internal/services/cdn/cdn_frontdoor_security_policy_resource.go @@ -0,0 +1,281 @@ +package cdn + +import ( + "fmt" + "strings" + "time" + + "github.com/Azure/azure-sdk-for-go/services/cdn/mgmt/2021-06-01/cdn" + "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + cdnfrontdoorsecurityparams "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/frontdoorsecurityparams" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/validate" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +func resourceCdnFrontDoorSecurityPolicy() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Create: resourceCdnFrontdoorSecurityPolicyCreate, + Read: resourceCdnFrontdoorSecurityPolicyRead, + Delete: resourceCdnFrontdoorSecurityPolicyDelete, + + Timeouts: &pluginsdk.ResourceTimeout{ + Create: pluginsdk.DefaultTimeout(30 * time.Minute), + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + Delete: pluginsdk.DefaultTimeout(30 * time.Minute), + }, + + Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { + _, err := parse.FrontDoorSecurityPolicyID(id) + return err + }), + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "cdn_frontdoor_profile_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.FrontDoorProfileID, + }, + + "security_policies": { + Type: pluginsdk.TypeList, + Required: true, + ForceNew: true, + MaxItems: 1, + + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + + "firewall": { + Type: pluginsdk.TypeList, + Required: true, + ForceNew: true, + MaxItems: 1, + + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + + "cdn_frontdoor_firewall_policy_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.FrontDoorFirewallPolicyID, + }, + + "association": { + Type: pluginsdk.TypeList, + Required: true, + ForceNew: true, + MaxItems: 1, + + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + + // NOTE: The max number of domains vary depending on sku: 100 Standard, 500 Premium + "domain": { + Type: pluginsdk.TypeList, + Required: true, + ForceNew: true, + MaxItems: 500, + + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "cdn_frontdoor_domain_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.FrontDoorSecurityPolicyDomainID, + }, + + "active": { + Type: pluginsdk.TypeBool, + Computed: true, + }, + }, + }, + }, + + // NOTE: Per the service team the only acceptable value as of GA is "/*" + "patterns_to_match": { + Type: pluginsdk.TypeList, + Required: true, + ForceNew: true, + MaxItems: 1, + + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringInSlice([]string{ + "/*", + }, false), + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func resourceCdnFrontdoorSecurityPolicyCreate(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Cdn.FrontDoorSecurityPoliciesClient + ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) + defer cancel() + + // NOTE: The profile id is used to retrieve properties from the related profile that must match in this security policy + profileId, err := parse.FrontDoorProfileID(d.Get("cdn_frontdoor_profile_id").(string)) + if err != nil { + return err + } + + securityPolicyName := d.Get("name").(string) + id := parse.NewFrontDoorSecurityPolicyID(profileId.SubscriptionId, profileId.ResourceGroup, profileId.ProfileName, securityPolicyName) + + existing, err := client.Get(ctx, id.ResourceGroup, id.ProfileName, id.SecurityPolicyName) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("checking for existing %s: %+v", id, err) + } + } + + if !utils.ResponseWasNotFound(existing.Response) { + return tf.ImportAsExistsError("azurerm_cdn_frontdoor_security_policy", id.ID()) + } + + profileClient := meta.(*clients.Client).Cdn.FrontDoorProfileClient + profile, err := profileClient.Get(ctx, profileId.ResourceGroup, profileId.ProfileName) + if err != nil { + return fmt.Errorf("unable to retrieve the %q from the linked %q: %+v", "sku_name", "azurerm_cdn_frontdoor_profile", err) + } + + if profile.Sku == nil { + return fmt.Errorf("retreving the parent %q: `sku` was nil", *profileId) + } + + isStandardSku := strings.HasPrefix(strings.ToLower(string(profile.Sku.Name)), "standard") + + params, err := cdnfrontdoorsecurityparams.ExpandCdnFrontdoorFirewallPolicyParameters(d.Get("security_policies").([]interface{}), isStandardSku) + if err != nil { + return fmt.Errorf("expanding %q: %+v", "security_policies", err) + } + + props := cdn.SecurityPolicy{ + SecurityPolicyProperties: &cdn.SecurityPolicyProperties{ + Parameters: params, + }, + } + + future, err := client.Create(ctx, id.ResourceGroup, id.ProfileName, id.SecurityPolicyName, props) + if err != nil { + return fmt.Errorf("creating %s: %+v", id, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for the creation of %s: %+v", id, err) + } + + d.SetId(id.ID()) + return resourceCdnFrontdoorSecurityPolicyRead(d, meta) +} + +func resourceCdnFrontdoorSecurityPolicyRead(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Cdn.FrontDoorSecurityPoliciesClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.FrontDoorSecurityPolicyID(d.Id()) + if err != nil { + return err + } + + resp, err := client.Get(ctx, id.ResourceGroup, id.ProfileName, id.SecurityPolicyName) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + d.SetId("") + return nil + } + return fmt.Errorf("retrieving %s: %+v", *id, err) + } + + d.Set("name", id.SecurityPolicyName) + d.Set("cdn_frontdoor_profile_id", parse.NewFrontDoorProfileID(id.SubscriptionId, id.ResourceGroup, id.ProfileName).ID()) + + if props := resp.SecurityPolicyProperties; props != nil { + waf, ok := props.Parameters.AsSecurityPolicyWebApplicationFirewallParameters() + if !ok { + return fmt.Errorf("flattening %s: %s", id, "expected security policy web application firewall parameters") + } + + // we know it's a firewall policy at this point, + // create the objects to hold the policy data + associations := make([]interface{}, 0) + + wafPolicyId := "" + if waf.WafPolicy != nil && waf.WafPolicy.ID != nil { + wafPolicyId = *waf.WafPolicy.ID + } + + if waf.Associations != nil { + for _, item := range *waf.Associations { + associations = append(associations, map[string]interface{}{ + "domain": cdnfrontdoorsecurityparams.FlattenSecurityPoliciesActivatedResourceReference(item.Domains), + "patterns_to_match": utils.FlattenStringSlice(item.PatternsToMatch), + }) + } + } + + securityPolicy := []interface{}{ + map[string]interface{}{ + "firewall": []interface{}{ + map[string]interface{}{ + "association": associations, + "cdn_frontdoor_firewall_policy_id": wafPolicyId, + }, + }, + }, + } + + d.Set("security_policies", securityPolicy) + } + + return nil +} + +func resourceCdnFrontdoorSecurityPolicyDelete(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Cdn.FrontDoorSecurityPoliciesClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.FrontDoorSecurityPolicyID(d.Id()) + if err != nil { + return err + } + + future, err := client.Delete(ctx, id.ResourceGroup, id.ProfileName, id.SecurityPolicyName) + if err != nil { + return fmt.Errorf("deleting %s: %+v", *id, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for the deletion of %s: %+v", *id, err) + } + + return nil +} diff --git a/internal/services/cdn/cdn_frontdoor_security_policy_resource_test.go b/internal/services/cdn/cdn_frontdoor_security_policy_resource_test.go new file mode 100644 index 000000000000..5ec0df6682e0 --- /dev/null +++ b/internal/services/cdn/cdn_frontdoor_security_policy_resource_test.go @@ -0,0 +1,460 @@ +package cdn_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type CdnFrontDoorSecurityPolicyResource struct{} + +func TestAccCdnFrontDoorSecurityPolicy_basic(t *testing.T) { + t.Skip("@WodansSon: Skipping test until Cdn FrontDoor Custom Domain resource is implemented") + + data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_security_policy", "test") + r := CdnFrontDoorSecurityPolicyResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + // TODO: we can remove these import-ignores by fixing the resource + // WS: Fixed, custom domain needs the profile id during create because it needs the name + data.ImportStep("azurerm_cdn_frontdoor_custom_domain.test.cdn_frontdoor_profile_id"), + }) +} + +func TestAccCdnFrontDoorSecurityPolicy_basicEndpoint(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_security_policy", "test") + r := CdnFrontDoorSecurityPolicyResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basicEndpoint(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccCdnFrontDoorSecurityPolicy_requiresImport(t *testing.T) { + t.Skip("@WodansSon: Skipping test until Cdn FrontDoor Custom Domain resource is implemented") + + data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_security_policy", "test") + r := CdnFrontDoorSecurityPolicyResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func TestAccCdnFrontDoorSecurityPolicy_requiresImportEndpoint(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_security_policy", "test") + r := CdnFrontDoorSecurityPolicyResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basicEndpoint(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImportEndpoint), + }) +} + +func TestAccCdnFrontDoorSecurityPolicy_complete(t *testing.T) { + t.Skip("@WodansSon: Skipping test until Cdn FrontDoor Custom Domain resource is implemented") + + data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_security_policy", "test") + r := CdnFrontDoorSecurityPolicyResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + // TODO: we can remove these import-ignores by fixing the resource + // WS: Fixed, custom domain needs the profile id during create because it needs the name + data.ImportStep("azurerm_cdn_frontdoor_custom_domain.test.cdn_frontdoor_profile_id"), + }) +} + +func TestAccCdnFrontDoorSecurityPolicy_completeEndpoint(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_security_policy", "test") + r := CdnFrontDoorSecurityPolicyResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.completeEndpoint(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + // TODO: we can remove these import-ignores by fixing the resource + // WS: Fixed, custom domain needs the profile id during create because it needs the name + data.ImportStep(), + }) +} + +func (r CdnFrontDoorSecurityPolicyResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + id, err := parse.FrontDoorSecurityPolicyID(state.ID) + if err != nil { + return nil, err + } + + client := clients.Cdn.FrontDoorSecurityPoliciesClient + resp, err := client.Get(ctx, id.ResourceGroup, id.ProfileName, id.SecurityPolicyName) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return utils.Bool(false), nil + } + return nil, fmt.Errorf("retrieving %s: %+v", id, err) + } + + return utils.Bool(true), nil +} + +func (r CdnFrontDoorSecurityPolicyResource) template(data acceptance.TestData) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-cdn-afdx-%[1]d" + location = "%s" +} + +resource "azurerm_cdn_frontdoor_firewall_policy" "test" { + name = "accTestWAF%[1]d" + resource_group_name = azurerm_resource_group.test.name + sku_name = azurerm_cdn_frontdoor_profile.test.sku_name + enabled = true + mode = "Prevention" + redirect_url = "https://www.fabrikam.com" + custom_block_response_status_code = 403 + custom_block_response_body = "PGh0bWw+CjxoZWFkZXI+PHRpdGxlPkhlbGxvPC90aXRsZT48L2hlYWRlcj4KPGJvZHk+CkhlbGxvIHdvcmxkCjwvYm9keT4KPC9odG1sPg==" + + custom_rule { + name = "Rule1" + enabled = true + priority = 1 + rate_limit_duration_in_minutes = 1 + rate_limit_threshold = 10 + type = "MatchRule" + action = "Block" + + match_condition { + match_variable = "RemoteAddr" + operator = "IPMatch" + negation_condition = false + match_values = ["192.168.1.0/24", "10.0.0.0/24"] + } + } + + managed_rule { + type = "DefaultRuleSet" + version = "preview-0.1" + action = "Block" + + override { + rule_group_name = "PHP" + + rule { + rule_id = "933111" + enabled = false + action = "Block" + } + } + } + + managed_rule { + type = "BotProtection" + version = "preview-0.1" + action = "Block" + } +} + +resource "azurerm_dns_zone" "test" { + name = "acctestzone%[1]d.com" + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_cdn_frontdoor_profile" "test" { + name = "accTestProfile-%[1]d" + resource_group_name = azurerm_resource_group.test.name + sku_name = "Premium_AzureFrontDoor" +} + +resource "azurerm_cdn_frontdoor_custom_domain" "test" { + name = "accTestCustomDomain-%[1]d" + cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.test.id + + dns_zone_id = azurerm_dns_zone.test.id + host_name = join(".", ["fabrikam", azurerm_dns_zone.test.name]) + + tls { + certificate_type = "ManagedCertificate" + minimum_tls_version = "TLS12" + } +} +`, data.RandomInteger, data.Locations.Primary) +} + +func (r CdnFrontDoorSecurityPolicyResource) templateEndpoint(data acceptance.TestData) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-cdn-afdx-%[1]d" + location = "%s" +} + +resource "azurerm_cdn_frontdoor_firewall_policy" "test" { + name = "accTestWAF%[1]d" + resource_group_name = azurerm_resource_group.test.name + sku_name = azurerm_cdn_frontdoor_profile.test.sku_name + enabled = true + mode = "Prevention" + redirect_url = "https://www.fabrikam.com" + custom_block_response_status_code = 403 + custom_block_response_body = "PGh0bWw+CjxoZWFkZXI+PHRpdGxlPkhlbGxvPC90aXRsZT48L2hlYWRlcj4KPGJvZHk+CkhlbGxvIHdvcmxkCjwvYm9keT4KPC9odG1sPg==" + + custom_rule { + name = "Rule1" + enabled = true + priority = 1 + rate_limit_duration_in_minutes = 1 + rate_limit_threshold = 10 + type = "MatchRule" + action = "Block" + + match_condition { + match_variable = "RemoteAddr" + operator = "IPMatch" + negation_condition = false + match_values = ["192.168.1.0/24", "10.0.0.0/24"] + } + } + + managed_rule { + type = "DefaultRuleSet" + version = "preview-0.1" + action = "Block" + + override { + rule_group_name = "PHP" + + rule { + rule_id = "933111" + enabled = false + action = "Block" + } + } + } + + managed_rule { + type = "BotProtection" + version = "preview-0.1" + action = "Block" + } +} + +resource "azurerm_dns_zone" "test" { + name = "acctestzone%[1]d.com" + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_cdn_frontdoor_profile" "test" { + name = "accTestProfile-%[1]d" + resource_group_name = azurerm_resource_group.test.name + sku_name = "Premium_AzureFrontDoor" +} + +resource "azurerm_cdn_frontdoor_endpoint" "test" { + name = "acctest-cdnfdendpoint-%[1]d" + cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.test.id +} +`, data.RandomInteger, data.Locations.Primary) +} + +func (r CdnFrontDoorSecurityPolicyResource) basic(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +%s + +resource "azurerm_cdn_frontdoor_security_policy" "test" { + name = "accTestSecPol%d" + cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.test.id + + security_policies { + firewall { + cdn_frontdoor_firewall_policy_id = azurerm_cdn_frontdoor_firewall_policy.test.id + + association { + domain { + cdn_frontdoor_domain_id = azurerm_cdn_frontdoor_custom_domain.test.id + } + + patterns_to_match = ["/*"] + } + } + } +} +`, template, data.RandomInteger) +} + +func (r CdnFrontDoorSecurityPolicyResource) basicEndpoint(data acceptance.TestData) string { + template := r.templateEndpoint(data) + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +%s + +resource "azurerm_cdn_frontdoor_security_policy" "test" { + name = "accTestSecPol%d" + cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.test.id + + security_policies { + firewall { + cdn_frontdoor_firewall_policy_id = azurerm_cdn_frontdoor_firewall_policy.test.id + + association { + domain { + cdn_frontdoor_domain_id = azurerm_cdn_frontdoor_endpoint.test.id + } + + patterns_to_match = ["/*"] + } + } + } +} +`, template, data.RandomInteger) +} + +func (r CdnFrontDoorSecurityPolicyResource) requiresImport(data acceptance.TestData) string { + config := r.basic(data) + return fmt.Sprintf(` +%s + +resource "azurerm_cdn_frontdoor_security_policy" "import" { + name = "accTestSecPol%d" + cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.test.id + + security_policies { + firewall { + cdn_frontdoor_firewall_policy_id = azurerm_cdn_frontdoor_firewall_policy.test.id + + association { + domain { + cdn_frontdoor_domain_id = azurerm_cdn_frontdoor_custom_domain.test.id + } + + patterns_to_match = ["/*"] + } + } + } +} +`, config, data.RandomInteger) +} + +func (r CdnFrontDoorSecurityPolicyResource) requiresImportEndpoint(data acceptance.TestData) string { + config := r.basicEndpoint(data) + return fmt.Sprintf(` +%s + +resource "azurerm_cdn_frontdoor_security_policy" "import" { + name = "accTestSecPol%d" + cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.test.id + + security_policies { + firewall { + cdn_frontdoor_firewall_policy_id = azurerm_cdn_frontdoor_firewall_policy.test.id + + association { + domain { + cdn_frontdoor_domain_id = azurerm_cdn_frontdoor_endpoint.test.id + } + + patterns_to_match = ["/*"] + } + } + } +} +`, config, data.RandomInteger) +} + +func (r CdnFrontDoorSecurityPolicyResource) complete(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +%s + +resource "azurerm_cdn_frontdoor_security_policy" "test" { + name = "accTestSecPol%d" + cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.test.id + + security_policies { + firewall { + cdn_frontdoor_firewall_policy_id = azurerm_cdn_frontdoor_firewall_policy.test.id + + association { + domain { + cdn_frontdoor_domain_id = azurerm_cdn_frontdoor_custom_domain.test.id + } + + patterns_to_match = ["/*"] + } + } + } +} +`, template, data.RandomInteger) +} + +func (r CdnFrontDoorSecurityPolicyResource) completeEndpoint(data acceptance.TestData) string { + template := r.templateEndpoint(data) + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +%s + +resource "azurerm_cdn_frontdoor_security_policy" "test" { + name = "accTestSecPol%d" + cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.test.id + + security_policies { + firewall { + cdn_frontdoor_firewall_policy_id = azurerm_cdn_frontdoor_firewall_policy.test.id + + association { + domain { + cdn_frontdoor_domain_id = azurerm_cdn_frontdoor_endpoint.test.id + } + + patterns_to_match = ["/*"] + } + } + } +} +`, template, data.RandomInteger) +} diff --git a/internal/services/cdn/client/client.go b/internal/services/cdn/client/client.go index f805f89c9e1d..bf75b270da9d 100644 --- a/internal/services/cdn/client/client.go +++ b/internal/services/cdn/client/client.go @@ -8,20 +8,20 @@ import ( ) type Client struct { - FrontDoorEndpointsClient *cdnFrontDoorSdk.AFDEndpointsClient - FrontDoorOriginGroupsClient *cdnFrontDoorSdk.AFDOriginGroupsClient - FrontDoorOriginsClient *cdnFrontDoorSdk.AFDOriginsClient - FrontDoorCustomDomainsClient *cdnFrontDoorSdk.AFDCustomDomainsClient - FrontDoorSecurityPoliciesClient *cdnFrontDoorSdk.SecurityPoliciesClient - FrontDoorRoutesClient *cdnFrontDoorSdk.RoutesClient - FrontDoorRulesClient *cdnFrontDoorSdk.RulesClient - FrontDoorProfileClient *cdnFrontDoorSdk.ProfilesClient - FrontDoorSecretsClient *cdnFrontDoorSdk.SecretsClient - FrontDoorRuleSetsClient *cdnFrontDoorSdk.RuleSetsClient - FrontDoorLegacyPoliciesClient *frontdoor.PoliciesClient - CustomDomainsClient *cdnSdk.CustomDomainsClient - EndpointsClient *cdnSdk.EndpointsClient - ProfilesClient *cdnSdk.ProfilesClient + FrontDoorEndpointsClient *cdnFrontDoorSdk.AFDEndpointsClient + FrontDoorOriginGroupsClient *cdnFrontDoorSdk.AFDOriginGroupsClient + FrontDoorOriginsClient *cdnFrontDoorSdk.AFDOriginsClient + FrontDoorCustomDomainsClient *cdnFrontDoorSdk.AFDCustomDomainsClient + FrontDoorSecurityPoliciesClient *cdnFrontDoorSdk.SecurityPoliciesClient + FrontDoorRoutesClient *cdnFrontDoorSdk.RoutesClient + FrontDoorRulesClient *cdnFrontDoorSdk.RulesClient + FrontDoorProfileClient *cdnFrontDoorSdk.ProfilesClient + FrontDoorSecretsClient *cdnFrontDoorSdk.SecretsClient + FrontDoorRuleSetsClient *cdnFrontDoorSdk.RuleSetsClient + FrontDoorLegacyFirewallPoliciesClient *frontdoor.PoliciesClient + CustomDomainsClient *cdnSdk.CustomDomainsClient + EndpointsClient *cdnSdk.EndpointsClient + ProfilesClient *cdnSdk.ProfilesClient } func NewClient(o *common.ClientOptions) *Client { @@ -40,8 +40,8 @@ func NewClient(o *common.ClientOptions) *Client { frontDoorPolicySecurityPoliciesClient := cdnFrontDoorSdk.NewSecurityPoliciesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&frontDoorPolicySecurityPoliciesClient.Client, o.ResourceManagerAuthorizer) - frontDoorLegacyPoliciesClient := frontdoor.NewPoliciesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) - o.ConfigureClient(&frontDoorLegacyPoliciesClient.Client, o.ResourceManagerAuthorizer) + frontDoorLegacyFirewallPoliciesClient := frontdoor.NewPoliciesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&frontDoorLegacyFirewallPoliciesClient.Client, o.ResourceManagerAuthorizer) frontDoorRoutesClient := cdnFrontDoorSdk.NewRoutesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&frontDoorRoutesClient.Client, o.ResourceManagerAuthorizer) @@ -68,19 +68,19 @@ func NewClient(o *common.ClientOptions) *Client { o.ConfigureClient(&profilesClient.Client, o.ResourceManagerAuthorizer) return &Client{ - FrontDoorEndpointsClient: &frontDoorEndpointsClient, - FrontDoorOriginGroupsClient: &frontDoorOriginGroupsClient, - FrontDoorOriginsClient: &frontDoorOriginsClient, - FrontDoorCustomDomainsClient: &frontDoorCustomDomainsClient, - FrontDoorSecurityPoliciesClient: &frontDoorPolicySecurityPoliciesClient, - FrontDoorRoutesClient: &frontDoorRoutesClient, - FrontDoorRulesClient: &frontDoorRulesClient, - FrontDoorProfileClient: &frontDoorProfilesClient, - FrontDoorSecretsClient: &frontDoorPolicySecretsClient, - FrontDoorRuleSetsClient: &frontDoorRuleSetsClient, - FrontDoorLegacyPoliciesClient: &frontDoorLegacyPoliciesClient, - CustomDomainsClient: &customDomainsClient, - EndpointsClient: &endpointsClient, - ProfilesClient: &profilesClient, + FrontDoorEndpointsClient: &frontDoorEndpointsClient, + FrontDoorOriginGroupsClient: &frontDoorOriginGroupsClient, + FrontDoorOriginsClient: &frontDoorOriginsClient, + FrontDoorCustomDomainsClient: &frontDoorCustomDomainsClient, + FrontDoorSecurityPoliciesClient: &frontDoorPolicySecurityPoliciesClient, + FrontDoorRoutesClient: &frontDoorRoutesClient, + FrontDoorRulesClient: &frontDoorRulesClient, + FrontDoorProfileClient: &frontDoorProfilesClient, + FrontDoorSecretsClient: &frontDoorPolicySecretsClient, + FrontDoorRuleSetsClient: &frontDoorRuleSetsClient, + FrontDoorLegacyFirewallPoliciesClient: &frontDoorLegacyFirewallPoliciesClient, + CustomDomainsClient: &customDomainsClient, + EndpointsClient: &endpointsClient, + ProfilesClient: &profilesClient, } } diff --git a/internal/services/cdn/frontdoorsecurityparams/cdn_frontdoor_security_params.go b/internal/services/cdn/frontdoorsecurityparams/cdn_frontdoor_security_params.go new file mode 100644 index 000000000000..f3daa9df11c2 --- /dev/null +++ b/internal/services/cdn/frontdoorsecurityparams/cdn_frontdoor_security_params.go @@ -0,0 +1,110 @@ +package cdnfrontdoorsecurityparams + +import ( + "fmt" + + "github.com/Azure/azure-sdk-for-go/services/cdn/mgmt/2021-06-01/cdn" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type CdnFrontdoorSecurityParameters struct { + TypeName cdn.Type + ConfigName string +} + +type CdnFrontdoorSecurityMappings struct { + Firewall CdnFrontdoorSecurityParameters +} + +func ExpandCdnFrontdoorFirewallPolicyParameters(input []interface{}, isStandardSku bool) (*cdn.SecurityPolicyWebApplicationFirewallParameters, error) { + results := cdn.SecurityPolicyWebApplicationFirewallParameters{} + if len(input) == 0 { + return &results, nil + } + + associations := make([]cdn.SecurityPolicyWebApplicationFirewallAssociation, 0) + + // pull off only the firewall policy from the security_policies list + policyType := input[0].(map[string]interface{}) + firewallPolicy := policyType["firewall"].([]interface{}) + v := firewallPolicy[0].(map[string]interface{}) + + if id := v["cdn_frontdoor_firewall_policy_id"].(string); id != "" { + results.WafPolicy = &cdn.ResourceReference{ + ID: utils.String(id), + } + } + + configAssociations := v["association"].([]interface{}) + + for _, item := range configAssociations { + v := item.(map[string]interface{}) + domains := expandSecurityPoliciesActivatedResourceReference(v["domain"].([]interface{})) + + if isStandardSku { + if len(*domains) > 100 { + return &results, fmt.Errorf("the %q sku is only allowed to have 100 or less domains associated with the firewall policy, got %d", cdn.SkuNameStandardAzureFrontDoor, len(*domains)) + } + } else { + if len(*domains) > 500 { + return &results, fmt.Errorf("the %q sku is only allowed to have 500 or less domains associated with the firewall policy, got %d", cdn.SkuNamePremiumAzureFrontDoor, len(*domains)) + } + } + + association := cdn.SecurityPolicyWebApplicationFirewallAssociation{ + Domains: domains, + PatternsToMatch: utils.ExpandStringSlice(v["patterns_to_match"].([]interface{})), + } + + associations = append(associations, association) + } + + results.Associations = &associations + + return &results, nil +} + +func expandSecurityPoliciesActivatedResourceReference(input []interface{}) *[]cdn.ActivatedResourceReference { + results := make([]cdn.ActivatedResourceReference, 0) + if len(input) == 0 { + return &results + } + + for _, item := range input { + v := item.(map[string]interface{}) + + if id := v["cdn_frontdoor_domain_id"].(string); id != "" { + results = append(results, cdn.ActivatedResourceReference{ + ID: utils.String(id), + }) + } + } + + return &results +} + +func FlattenSecurityPoliciesActivatedResourceReference(input *[]cdn.ActivatedResourceReference) []interface{} { + results := make([]interface{}, 0) + if input == nil { + return results + } + + for _, item := range *input { + frontDoorDomainId := "" + if item.ID != nil { + frontDoorDomainId = *item.ID + } + + active := false + if item.IsActive != nil { + active = *item.IsActive + } + + results = append(results, map[string]interface{}{ + "active": active, + "cdn_frontdoor_domain_id": frontDoorDomainId, + }) + } + + return results +} diff --git a/internal/services/cdn/parse/front_door_custom_domain.go b/internal/services/cdn/parse/front_door_custom_domain.go new file mode 100644 index 000000000000..4d13da872b67 --- /dev/null +++ b/internal/services/cdn/parse/front_door_custom_domain.go @@ -0,0 +1,131 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + "strings" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +type FrontDoorCustomDomainId struct { + SubscriptionId string + ResourceGroup string + ProfileName string + CustomDomainName string +} + +func NewFrontDoorCustomDomainID(subscriptionId, resourceGroup, profileName, customDomainName string) FrontDoorCustomDomainId { + return FrontDoorCustomDomainId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + ProfileName: profileName, + CustomDomainName: customDomainName, + } +} + +func (id FrontDoorCustomDomainId) String() string { + segments := []string{ + fmt.Sprintf("Custom Domain Name %q", id.CustomDomainName), + fmt.Sprintf("Profile Name %q", id.ProfileName), + fmt.Sprintf("Resource Group %q", id.ResourceGroup), + } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "Front Door Custom Domain", segmentsStr) +} + +func (id FrontDoorCustomDomainId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Cdn/profiles/%s/customDomains/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.ProfileName, id.CustomDomainName) +} + +// FrontDoorCustomDomainID parses a FrontDoorCustomDomain ID into an FrontDoorCustomDomainId struct +func FrontDoorCustomDomainID(input string) (*FrontDoorCustomDomainId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := FrontDoorCustomDomainId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + if resourceId.ProfileName, err = id.PopSegment("profiles"); err != nil { + return nil, err + } + if resourceId.CustomDomainName, err = id.PopSegment("customDomains"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} + +// FrontDoorCustomDomainIDInsensitively parses an FrontDoorCustomDomain ID into an FrontDoorCustomDomainId struct, insensitively +// This should only be used to parse an ID for rewriting, the FrontDoorCustomDomainID +// method should be used instead for validation etc. +// +// Whilst this may seem strange, this enables Terraform have consistent casing +// which works around issues in Core, whilst handling broken API responses. +func FrontDoorCustomDomainIDInsensitively(input string) (*FrontDoorCustomDomainId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := FrontDoorCustomDomainId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + // find the correct casing for the 'profiles' segment + profilesKey := "profiles" + for key := range id.Path { + if strings.EqualFold(key, profilesKey) { + profilesKey = key + break + } + } + if resourceId.ProfileName, err = id.PopSegment(profilesKey); err != nil { + return nil, err + } + + // find the correct casing for the 'customDomains' segment + customDomainsKey := "customDomains" + for key := range id.Path { + if strings.EqualFold(key, customDomainsKey) { + customDomainsKey = key + break + } + } + if resourceId.CustomDomainName, err = id.PopSegment(customDomainsKey); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} diff --git a/internal/services/cdn/parse/front_door_custom_domain_test.go b/internal/services/cdn/parse/front_door_custom_domain_test.go new file mode 100644 index 000000000000..a6380ae021a4 --- /dev/null +++ b/internal/services/cdn/parse/front_door_custom_domain_test.go @@ -0,0 +1,264 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "testing" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +var _ resourceids.Id = FrontDoorCustomDomainId{} + +func TestFrontDoorCustomDomainIDFormatter(t *testing.T) { + actual := NewFrontDoorCustomDomainID("12345678-1234-9876-4563-123456789012", "resGroup1", "profile1", "customDomain1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/customDomain1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestFrontDoorCustomDomainID(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *FrontDoorCustomDomainId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing ProfileName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/", + Error: true, + }, + + { + // missing value for ProfileName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/", + Error: true, + }, + + { + // missing CustomDomainName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/", + Error: true, + }, + + { + // missing value for CustomDomainName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/customDomain1", + Expected: &FrontDoorCustomDomainId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ProfileName: "profile1", + CustomDomainName: "customDomain1", + }, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.CDN/PROFILES/PROFILE1/CUSTOMDOMAINS/CUSTOMDOMAIN1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := FrontDoorCustomDomainID(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.ProfileName != v.Expected.ProfileName { + t.Fatalf("Expected %q but got %q for ProfileName", v.Expected.ProfileName, actual.ProfileName) + } + if actual.CustomDomainName != v.Expected.CustomDomainName { + t.Fatalf("Expected %q but got %q for CustomDomainName", v.Expected.CustomDomainName, actual.CustomDomainName) + } + } +} + +func TestFrontDoorCustomDomainIDInsensitively(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *FrontDoorCustomDomainId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing ProfileName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/", + Error: true, + }, + + { + // missing value for ProfileName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/", + Error: true, + }, + + { + // missing CustomDomainName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/", + Error: true, + }, + + { + // missing value for CustomDomainName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/customDomain1", + Expected: &FrontDoorCustomDomainId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ProfileName: "profile1", + CustomDomainName: "customDomain1", + }, + }, + + { + // lower-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customdomains/customDomain1", + Expected: &FrontDoorCustomDomainId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ProfileName: "profile1", + CustomDomainName: "customDomain1", + }, + }, + + { + // upper-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/PROFILES/profile1/CUSTOMDOMAINS/customDomain1", + Expected: &FrontDoorCustomDomainId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ProfileName: "profile1", + CustomDomainName: "customDomain1", + }, + }, + + { + // mixed-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/PrOfIlEs/profile1/CuStOmDoMaInS/customDomain1", + Expected: &FrontDoorCustomDomainId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ProfileName: "profile1", + CustomDomainName: "customDomain1", + }, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := FrontDoorCustomDomainIDInsensitively(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.ProfileName != v.Expected.ProfileName { + t.Fatalf("Expected %q but got %q for ProfileName", v.Expected.ProfileName, actual.ProfileName) + } + if actual.CustomDomainName != v.Expected.CustomDomainName { + t.Fatalf("Expected %q but got %q for CustomDomainName", v.Expected.CustomDomainName, actual.CustomDomainName) + } + } +} diff --git a/internal/services/cdn/parse/front_door_endpoint_test.go b/internal/services/cdn/parse/front_door_endpoint_test.go index 488adfeefeae..485c2acc7841 100644 --- a/internal/services/cdn/parse/front_door_endpoint_test.go +++ b/internal/services/cdn/parse/front_door_endpoint_test.go @@ -11,8 +11,8 @@ import ( var _ resourceids.Id = FrontDoorEndpointId{} func TestFrontDoorEndpointIDFormatter(t *testing.T) { - actual := NewFrontDoorEndpointID("12345678-1234-9876-4563-123456789012", "resourceGroup1", "profile1", "endpoint1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/afdEndpoints/endpoint1" + actual := NewFrontDoorEndpointID("12345678-1234-9876-4563-123456789012", "resGroup1", "profile1", "endpoint1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/afdEndpoints/endpoint1" if actual != expected { t.Fatalf("Expected %q but got %q", expected, actual) } @@ -57,34 +57,34 @@ func TestFrontDoorEndpointID(t *testing.T) { { // missing ProfileName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/", Error: true, }, { // missing value for ProfileName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/", Error: true, }, { // missing AfdEndpointName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/", Error: true, }, { // missing value for AfdEndpointName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/afdEndpoints/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/afdEndpoints/", Error: true, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/afdEndpoints/endpoint1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/afdEndpoints/endpoint1", Expected: &FrontDoorEndpointId{ SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resourceGroup1", + ResourceGroup: "resGroup1", ProfileName: "profile1", AfdEndpointName: "endpoint1", }, @@ -92,7 +92,7 @@ func TestFrontDoorEndpointID(t *testing.T) { { // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESOURCEGROUP1/PROVIDERS/MICROSOFT.CDN/PROFILES/PROFILE1/AFDENDPOINTS/ENDPOINT1", + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.CDN/PROFILES/PROFILE1/AFDENDPOINTS/ENDPOINT1", Error: true, }, } @@ -166,34 +166,34 @@ func TestFrontDoorEndpointIDInsensitively(t *testing.T) { { // missing ProfileName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/", Error: true, }, { // missing value for ProfileName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/", Error: true, }, { // missing AfdEndpointName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/", Error: true, }, { // missing value for AfdEndpointName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/afdEndpoints/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/afdEndpoints/", Error: true, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/afdEndpoints/endpoint1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/afdEndpoints/endpoint1", Expected: &FrontDoorEndpointId{ SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resourceGroup1", + ResourceGroup: "resGroup1", ProfileName: "profile1", AfdEndpointName: "endpoint1", }, @@ -201,10 +201,10 @@ func TestFrontDoorEndpointIDInsensitively(t *testing.T) { { // lower-cased segment names - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/afdendpoints/endpoint1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/afdendpoints/endpoint1", Expected: &FrontDoorEndpointId{ SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resourceGroup1", + ResourceGroup: "resGroup1", ProfileName: "profile1", AfdEndpointName: "endpoint1", }, @@ -212,10 +212,10 @@ func TestFrontDoorEndpointIDInsensitively(t *testing.T) { { // upper-cased segment names - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/PROFILES/profile1/AFDENDPOINTS/endpoint1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/PROFILES/profile1/AFDENDPOINTS/endpoint1", Expected: &FrontDoorEndpointId{ SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resourceGroup1", + ResourceGroup: "resGroup1", ProfileName: "profile1", AfdEndpointName: "endpoint1", }, @@ -223,10 +223,10 @@ func TestFrontDoorEndpointIDInsensitively(t *testing.T) { { // mixed-cased segment names - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/PrOfIlEs/profile1/AfDeNdPoInTs/endpoint1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/PrOfIlEs/profile1/AfDeNdPoInTs/endpoint1", Expected: &FrontDoorEndpointId{ SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resourceGroup1", + ResourceGroup: "resGroup1", ProfileName: "profile1", AfdEndpointName: "endpoint1", }, diff --git a/internal/services/cdn/parse/front_door_firewall_policy.go b/internal/services/cdn/parse/front_door_firewall_policy.go new file mode 100644 index 000000000000..89aed188c84e --- /dev/null +++ b/internal/services/cdn/parse/front_door_firewall_policy.go @@ -0,0 +1,113 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + "strings" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +type FrontDoorFirewallPolicyId struct { + SubscriptionId string + ResourceGroup string + FrontDoorWebApplicationFirewallPolicyName string +} + +func NewFrontDoorFirewallPolicyID(subscriptionId, resourceGroup, frontDoorWebApplicationFirewallPolicyName string) FrontDoorFirewallPolicyId { + return FrontDoorFirewallPolicyId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + FrontDoorWebApplicationFirewallPolicyName: frontDoorWebApplicationFirewallPolicyName, + } +} + +func (id FrontDoorFirewallPolicyId) String() string { + segments := []string{ + fmt.Sprintf("Front Door Web Application Firewall Policy Name %q", id.FrontDoorWebApplicationFirewallPolicyName), + fmt.Sprintf("Resource Group %q", id.ResourceGroup), + } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "Front Door Firewall Policy", segmentsStr) +} + +func (id FrontDoorFirewallPolicyId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/frontDoorWebApplicationFirewallPolicies/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.FrontDoorWebApplicationFirewallPolicyName) +} + +// FrontDoorFirewallPolicyID parses a FrontDoorFirewallPolicy ID into an FrontDoorFirewallPolicyId struct +func FrontDoorFirewallPolicyID(input string) (*FrontDoorFirewallPolicyId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := FrontDoorFirewallPolicyId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + if resourceId.FrontDoorWebApplicationFirewallPolicyName, err = id.PopSegment("frontDoorWebApplicationFirewallPolicies"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} + +// FrontDoorFirewallPolicyIDInsensitively parses an FrontDoorFirewallPolicy ID into an FrontDoorFirewallPolicyId struct, insensitively +// This should only be used to parse an ID for rewriting, the FrontDoorFirewallPolicyID +// method should be used instead for validation etc. +// +// Whilst this may seem strange, this enables Terraform have consistent casing +// which works around issues in Core, whilst handling broken API responses. +func FrontDoorFirewallPolicyIDInsensitively(input string) (*FrontDoorFirewallPolicyId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := FrontDoorFirewallPolicyId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + // find the correct casing for the 'frontDoorWebApplicationFirewallPolicies' segment + frontDoorWebApplicationFirewallPoliciesKey := "frontDoorWebApplicationFirewallPolicies" + for key := range id.Path { + if strings.EqualFold(key, frontDoorWebApplicationFirewallPoliciesKey) { + frontDoorWebApplicationFirewallPoliciesKey = key + break + } + } + if resourceId.FrontDoorWebApplicationFirewallPolicyName, err = id.PopSegment(frontDoorWebApplicationFirewallPoliciesKey); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} diff --git a/internal/services/cdn/parse/front_door_firewall_policy_test.go b/internal/services/cdn/parse/front_door_firewall_policy_test.go new file mode 100644 index 000000000000..df69d0c756ef --- /dev/null +++ b/internal/services/cdn/parse/front_door_firewall_policy_test.go @@ -0,0 +1,229 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "testing" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +var _ resourceids.Id = FrontDoorFirewallPolicyId{} + +func TestFrontDoorFirewallPolicyIDFormatter(t *testing.T) { + actual := NewFrontDoorFirewallPolicyID("12345678-1234-9876-4563-123456789012", "resGroup1", "policy1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/frontDoorWebApplicationFirewallPolicies/policy1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestFrontDoorFirewallPolicyID(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *FrontDoorFirewallPolicyId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing FrontDoorWebApplicationFirewallPolicyName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/", + Error: true, + }, + + { + // missing value for FrontDoorWebApplicationFirewallPolicyName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/frontDoorWebApplicationFirewallPolicies/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/frontDoorWebApplicationFirewallPolicies/policy1", + Expected: &FrontDoorFirewallPolicyId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + FrontDoorWebApplicationFirewallPolicyName: "policy1", + }, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.NETWORK/FRONTDOORWEBAPPLICATIONFIREWALLPOLICIES/POLICY1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := FrontDoorFirewallPolicyID(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.FrontDoorWebApplicationFirewallPolicyName != v.Expected.FrontDoorWebApplicationFirewallPolicyName { + t.Fatalf("Expected %q but got %q for FrontDoorWebApplicationFirewallPolicyName", v.Expected.FrontDoorWebApplicationFirewallPolicyName, actual.FrontDoorWebApplicationFirewallPolicyName) + } + } +} + +func TestFrontDoorFirewallPolicyIDInsensitively(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *FrontDoorFirewallPolicyId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing FrontDoorWebApplicationFirewallPolicyName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/", + Error: true, + }, + + { + // missing value for FrontDoorWebApplicationFirewallPolicyName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/frontDoorWebApplicationFirewallPolicies/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/frontDoorWebApplicationFirewallPolicies/policy1", + Expected: &FrontDoorFirewallPolicyId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + FrontDoorWebApplicationFirewallPolicyName: "policy1", + }, + }, + + { + // lower-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/frontdoorwebapplicationfirewallpolicies/policy1", + Expected: &FrontDoorFirewallPolicyId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + FrontDoorWebApplicationFirewallPolicyName: "policy1", + }, + }, + + { + // upper-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/FRONTDOORWEBAPPLICATIONFIREWALLPOLICIES/policy1", + Expected: &FrontDoorFirewallPolicyId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + FrontDoorWebApplicationFirewallPolicyName: "policy1", + }, + }, + + { + // mixed-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/FrOnTdOoRwEbApPlIcAtIoNfIrEwAlLpOlIcIeS/policy1", + Expected: &FrontDoorFirewallPolicyId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + FrontDoorWebApplicationFirewallPolicyName: "policy1", + }, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := FrontDoorFirewallPolicyIDInsensitively(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.FrontDoorWebApplicationFirewallPolicyName != v.Expected.FrontDoorWebApplicationFirewallPolicyName { + t.Fatalf("Expected %q but got %q for FrontDoorWebApplicationFirewallPolicyName", v.Expected.FrontDoorWebApplicationFirewallPolicyName, actual.FrontDoorWebApplicationFirewallPolicyName) + } + } +} diff --git a/internal/services/cdn/parse/front_door_origin.go b/internal/services/cdn/parse/front_door_origin.go new file mode 100644 index 000000000000..ac7a74449423 --- /dev/null +++ b/internal/services/cdn/parse/front_door_origin.go @@ -0,0 +1,149 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + "strings" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +type FrontDoorOriginId struct { + SubscriptionId string + ResourceGroup string + ProfileName string + OriginGroupName string + OriginName string +} + +func NewFrontDoorOriginID(subscriptionId, resourceGroup, profileName, originGroupName, originName string) FrontDoorOriginId { + return FrontDoorOriginId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + ProfileName: profileName, + OriginGroupName: originGroupName, + OriginName: originName, + } +} + +func (id FrontDoorOriginId) String() string { + segments := []string{ + fmt.Sprintf("Origin Name %q", id.OriginName), + fmt.Sprintf("Origin Group Name %q", id.OriginGroupName), + fmt.Sprintf("Profile Name %q", id.ProfileName), + fmt.Sprintf("Resource Group %q", id.ResourceGroup), + } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "Front Door Origin", segmentsStr) +} + +func (id FrontDoorOriginId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Cdn/profiles/%s/originGroups/%s/origins/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.ProfileName, id.OriginGroupName, id.OriginName) +} + +// FrontDoorOriginID parses a FrontDoorOrigin ID into an FrontDoorOriginId struct +func FrontDoorOriginID(input string) (*FrontDoorOriginId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := FrontDoorOriginId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + if resourceId.ProfileName, err = id.PopSegment("profiles"); err != nil { + return nil, err + } + if resourceId.OriginGroupName, err = id.PopSegment("originGroups"); err != nil { + return nil, err + } + if resourceId.OriginName, err = id.PopSegment("origins"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} + +// FrontDoorOriginIDInsensitively parses an FrontDoorOrigin ID into an FrontDoorOriginId struct, insensitively +// This should only be used to parse an ID for rewriting, the FrontDoorOriginID +// method should be used instead for validation etc. +// +// Whilst this may seem strange, this enables Terraform have consistent casing +// which works around issues in Core, whilst handling broken API responses. +func FrontDoorOriginIDInsensitively(input string) (*FrontDoorOriginId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := FrontDoorOriginId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + // find the correct casing for the 'profiles' segment + profilesKey := "profiles" + for key := range id.Path { + if strings.EqualFold(key, profilesKey) { + profilesKey = key + break + } + } + if resourceId.ProfileName, err = id.PopSegment(profilesKey); err != nil { + return nil, err + } + + // find the correct casing for the 'originGroups' segment + originGroupsKey := "originGroups" + for key := range id.Path { + if strings.EqualFold(key, originGroupsKey) { + originGroupsKey = key + break + } + } + if resourceId.OriginGroupName, err = id.PopSegment(originGroupsKey); err != nil { + return nil, err + } + + // find the correct casing for the 'origins' segment + originsKey := "origins" + for key := range id.Path { + if strings.EqualFold(key, originsKey) { + originsKey = key + break + } + } + if resourceId.OriginName, err = id.PopSegment(originsKey); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} diff --git a/internal/services/cdn/parse/front_door_origin_group.go b/internal/services/cdn/parse/front_door_origin_group.go new file mode 100644 index 000000000000..fe1739596e74 --- /dev/null +++ b/internal/services/cdn/parse/front_door_origin_group.go @@ -0,0 +1,131 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + "strings" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +type FrontDoorOriginGroupId struct { + SubscriptionId string + ResourceGroup string + ProfileName string + OriginGroupName string +} + +func NewFrontDoorOriginGroupID(subscriptionId, resourceGroup, profileName, originGroupName string) FrontDoorOriginGroupId { + return FrontDoorOriginGroupId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + ProfileName: profileName, + OriginGroupName: originGroupName, + } +} + +func (id FrontDoorOriginGroupId) String() string { + segments := []string{ + fmt.Sprintf("Origin Group Name %q", id.OriginGroupName), + fmt.Sprintf("Profile Name %q", id.ProfileName), + fmt.Sprintf("Resource Group %q", id.ResourceGroup), + } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "Front Door Origin Group", segmentsStr) +} + +func (id FrontDoorOriginGroupId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Cdn/profiles/%s/originGroups/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.ProfileName, id.OriginGroupName) +} + +// FrontDoorOriginGroupID parses a FrontDoorOriginGroup ID into an FrontDoorOriginGroupId struct +func FrontDoorOriginGroupID(input string) (*FrontDoorOriginGroupId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := FrontDoorOriginGroupId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + if resourceId.ProfileName, err = id.PopSegment("profiles"); err != nil { + return nil, err + } + if resourceId.OriginGroupName, err = id.PopSegment("originGroups"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} + +// FrontDoorOriginGroupIDInsensitively parses an FrontDoorOriginGroup ID into an FrontDoorOriginGroupId struct, insensitively +// This should only be used to parse an ID for rewriting, the FrontDoorOriginGroupID +// method should be used instead for validation etc. +// +// Whilst this may seem strange, this enables Terraform have consistent casing +// which works around issues in Core, whilst handling broken API responses. +func FrontDoorOriginGroupIDInsensitively(input string) (*FrontDoorOriginGroupId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := FrontDoorOriginGroupId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + // find the correct casing for the 'profiles' segment + profilesKey := "profiles" + for key := range id.Path { + if strings.EqualFold(key, profilesKey) { + profilesKey = key + break + } + } + if resourceId.ProfileName, err = id.PopSegment(profilesKey); err != nil { + return nil, err + } + + // find the correct casing for the 'originGroups' segment + originGroupsKey := "originGroups" + for key := range id.Path { + if strings.EqualFold(key, originGroupsKey) { + originGroupsKey = key + break + } + } + if resourceId.OriginGroupName, err = id.PopSegment(originGroupsKey); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} diff --git a/internal/services/cdn/parse/front_door_origin_group_test.go b/internal/services/cdn/parse/front_door_origin_group_test.go new file mode 100644 index 000000000000..0ac837741463 --- /dev/null +++ b/internal/services/cdn/parse/front_door_origin_group_test.go @@ -0,0 +1,264 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "testing" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +var _ resourceids.Id = FrontDoorOriginGroupId{} + +func TestFrontDoorOriginGroupIDFormatter(t *testing.T) { + actual := NewFrontDoorOriginGroupID("12345678-1234-9876-4563-123456789012", "resGroup1", "profile1", "originGroup1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/originGroups/originGroup1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestFrontDoorOriginGroupID(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *FrontDoorOriginGroupId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing ProfileName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/", + Error: true, + }, + + { + // missing value for ProfileName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/", + Error: true, + }, + + { + // missing OriginGroupName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/", + Error: true, + }, + + { + // missing value for OriginGroupName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/originGroups/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/originGroups/originGroup1", + Expected: &FrontDoorOriginGroupId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ProfileName: "profile1", + OriginGroupName: "originGroup1", + }, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.CDN/PROFILES/PROFILE1/ORIGINGROUPS/ORIGINGROUP1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := FrontDoorOriginGroupID(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.ProfileName != v.Expected.ProfileName { + t.Fatalf("Expected %q but got %q for ProfileName", v.Expected.ProfileName, actual.ProfileName) + } + if actual.OriginGroupName != v.Expected.OriginGroupName { + t.Fatalf("Expected %q but got %q for OriginGroupName", v.Expected.OriginGroupName, actual.OriginGroupName) + } + } +} + +func TestFrontDoorOriginGroupIDInsensitively(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *FrontDoorOriginGroupId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing ProfileName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/", + Error: true, + }, + + { + // missing value for ProfileName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/", + Error: true, + }, + + { + // missing OriginGroupName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/", + Error: true, + }, + + { + // missing value for OriginGroupName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/originGroups/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/originGroups/originGroup1", + Expected: &FrontDoorOriginGroupId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ProfileName: "profile1", + OriginGroupName: "originGroup1", + }, + }, + + { + // lower-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/origingroups/originGroup1", + Expected: &FrontDoorOriginGroupId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ProfileName: "profile1", + OriginGroupName: "originGroup1", + }, + }, + + { + // upper-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/PROFILES/profile1/ORIGINGROUPS/originGroup1", + Expected: &FrontDoorOriginGroupId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ProfileName: "profile1", + OriginGroupName: "originGroup1", + }, + }, + + { + // mixed-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/PrOfIlEs/profile1/OrIgInGrOuPs/originGroup1", + Expected: &FrontDoorOriginGroupId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ProfileName: "profile1", + OriginGroupName: "originGroup1", + }, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := FrontDoorOriginGroupIDInsensitively(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.ProfileName != v.Expected.ProfileName { + t.Fatalf("Expected %q but got %q for ProfileName", v.Expected.ProfileName, actual.ProfileName) + } + if actual.OriginGroupName != v.Expected.OriginGroupName { + t.Fatalf("Expected %q but got %q for OriginGroupName", v.Expected.OriginGroupName, actual.OriginGroupName) + } + } +} diff --git a/internal/services/cdn/parse/front_door_origin_test.go b/internal/services/cdn/parse/front_door_origin_test.go new file mode 100644 index 000000000000..4de2e782d988 --- /dev/null +++ b/internal/services/cdn/parse/front_door_origin_test.go @@ -0,0 +1,299 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "testing" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +var _ resourceids.Id = FrontDoorOriginId{} + +func TestFrontDoorOriginIDFormatter(t *testing.T) { + actual := NewFrontDoorOriginID("12345678-1234-9876-4563-123456789012", "resGroup1", "profile1", "originGroup1", "origin1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/originGroups/originGroup1/origins/origin1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestFrontDoorOriginID(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *FrontDoorOriginId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing ProfileName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/", + Error: true, + }, + + { + // missing value for ProfileName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/", + Error: true, + }, + + { + // missing OriginGroupName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/", + Error: true, + }, + + { + // missing value for OriginGroupName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/originGroups/", + Error: true, + }, + + { + // missing OriginName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/originGroups/originGroup1/", + Error: true, + }, + + { + // missing value for OriginName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/originGroups/originGroup1/origins/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/originGroups/originGroup1/origins/origin1", + Expected: &FrontDoorOriginId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ProfileName: "profile1", + OriginGroupName: "originGroup1", + OriginName: "origin1", + }, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.CDN/PROFILES/PROFILE1/ORIGINGROUPS/ORIGINGROUP1/ORIGINS/ORIGIN1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := FrontDoorOriginID(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.ProfileName != v.Expected.ProfileName { + t.Fatalf("Expected %q but got %q for ProfileName", v.Expected.ProfileName, actual.ProfileName) + } + if actual.OriginGroupName != v.Expected.OriginGroupName { + t.Fatalf("Expected %q but got %q for OriginGroupName", v.Expected.OriginGroupName, actual.OriginGroupName) + } + if actual.OriginName != v.Expected.OriginName { + t.Fatalf("Expected %q but got %q for OriginName", v.Expected.OriginName, actual.OriginName) + } + } +} + +func TestFrontDoorOriginIDInsensitively(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *FrontDoorOriginId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing ProfileName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/", + Error: true, + }, + + { + // missing value for ProfileName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/", + Error: true, + }, + + { + // missing OriginGroupName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/", + Error: true, + }, + + { + // missing value for OriginGroupName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/originGroups/", + Error: true, + }, + + { + // missing OriginName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/originGroups/originGroup1/", + Error: true, + }, + + { + // missing value for OriginName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/originGroups/originGroup1/origins/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/originGroups/originGroup1/origins/origin1", + Expected: &FrontDoorOriginId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ProfileName: "profile1", + OriginGroupName: "originGroup1", + OriginName: "origin1", + }, + }, + + { + // lower-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/origingroups/originGroup1/origins/origin1", + Expected: &FrontDoorOriginId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ProfileName: "profile1", + OriginGroupName: "originGroup1", + OriginName: "origin1", + }, + }, + + { + // upper-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/PROFILES/profile1/ORIGINGROUPS/originGroup1/ORIGINS/origin1", + Expected: &FrontDoorOriginId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ProfileName: "profile1", + OriginGroupName: "originGroup1", + OriginName: "origin1", + }, + }, + + { + // mixed-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/PrOfIlEs/profile1/OrIgInGrOuPs/originGroup1/OrIgInS/origin1", + Expected: &FrontDoorOriginId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ProfileName: "profile1", + OriginGroupName: "originGroup1", + OriginName: "origin1", + }, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := FrontDoorOriginIDInsensitively(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.ProfileName != v.Expected.ProfileName { + t.Fatalf("Expected %q but got %q for ProfileName", v.Expected.ProfileName, actual.ProfileName) + } + if actual.OriginGroupName != v.Expected.OriginGroupName { + t.Fatalf("Expected %q but got %q for OriginGroupName", v.Expected.OriginGroupName, actual.OriginGroupName) + } + if actual.OriginName != v.Expected.OriginName { + t.Fatalf("Expected %q but got %q for OriginName", v.Expected.OriginName, actual.OriginName) + } + } +} diff --git a/internal/services/cdn/parse/front_door_profile_test.go b/internal/services/cdn/parse/front_door_profile_test.go index a05a36dac453..e55e4112de1d 100644 --- a/internal/services/cdn/parse/front_door_profile_test.go +++ b/internal/services/cdn/parse/front_door_profile_test.go @@ -11,8 +11,8 @@ import ( var _ resourceids.Id = FrontDoorProfileId{} func TestFrontDoorProfileIDFormatter(t *testing.T) { - actual := NewFrontDoorProfileID("12345678-1234-9876-4563-123456789012", "resourceGroup1", "profile1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1" + actual := NewFrontDoorProfileID("12345678-1234-9876-4563-123456789012", "resGroup1", "profile1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1" if actual != expected { t.Fatalf("Expected %q but got %q", expected, actual) } @@ -57,29 +57,29 @@ func TestFrontDoorProfileID(t *testing.T) { { // missing ProfileName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/", Error: true, }, { // missing value for ProfileName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/", Error: true, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1", Expected: &FrontDoorProfileId{ SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resourceGroup1", + ResourceGroup: "resGroup1", ProfileName: "profile1", }, }, { // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESOURCEGROUP1/PROVIDERS/MICROSOFT.CDN/PROFILES/PROFILE1", + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.CDN/PROFILES/PROFILE1", Error: true, }, } @@ -150,52 +150,52 @@ func TestFrontDoorProfileIDInsensitively(t *testing.T) { { // missing ProfileName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/", Error: true, }, { // missing value for ProfileName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/", Error: true, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1", Expected: &FrontDoorProfileId{ SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resourceGroup1", + ResourceGroup: "resGroup1", ProfileName: "profile1", }, }, { // lower-cased segment names - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1", Expected: &FrontDoorProfileId{ SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resourceGroup1", + ResourceGroup: "resGroup1", ProfileName: "profile1", }, }, { // upper-cased segment names - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/PROFILES/profile1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/PROFILES/profile1", Expected: &FrontDoorProfileId{ SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resourceGroup1", + ResourceGroup: "resGroup1", ProfileName: "profile1", }, }, { // mixed-cased segment names - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/PrOfIlEs/profile1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/PrOfIlEs/profile1", Expected: &FrontDoorProfileId{ SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resourceGroup1", + ResourceGroup: "resGroup1", ProfileName: "profile1", }, }, diff --git a/internal/services/cdn/parse/front_door_rule_set_test.go b/internal/services/cdn/parse/front_door_rule_set_test.go index 45e91d416cf7..736d442839c6 100644 --- a/internal/services/cdn/parse/front_door_rule_set_test.go +++ b/internal/services/cdn/parse/front_door_rule_set_test.go @@ -11,8 +11,8 @@ import ( var _ resourceids.Id = FrontDoorRuleSetId{} func TestFrontDoorRuleSetIDFormatter(t *testing.T) { - actual := NewFrontDoorRuleSetID("12345678-1234-9876-4563-123456789012", "resourceGroup1", "profile1", "ruleSet1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/ruleSet1" + actual := NewFrontDoorRuleSetID("12345678-1234-9876-4563-123456789012", "resGroup1", "profile1", "ruleSet1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/ruleSet1" if actual != expected { t.Fatalf("Expected %q but got %q", expected, actual) } @@ -57,34 +57,34 @@ func TestFrontDoorRuleSetID(t *testing.T) { { // missing ProfileName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/", Error: true, }, { // missing value for ProfileName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/", Error: true, }, { // missing RuleSetName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/", Error: true, }, { // missing value for RuleSetName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/", Error: true, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/ruleSet1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/ruleSet1", Expected: &FrontDoorRuleSetId{ SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resourceGroup1", + ResourceGroup: "resGroup1", ProfileName: "profile1", RuleSetName: "ruleSet1", }, @@ -92,7 +92,7 @@ func TestFrontDoorRuleSetID(t *testing.T) { { // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESOURCEGROUP1/PROVIDERS/MICROSOFT.CDN/PROFILES/PROFILE1/RULESETS/RULESET1", + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.CDN/PROFILES/PROFILE1/RULESETS/RULESET1", Error: true, }, } @@ -166,34 +166,34 @@ func TestFrontDoorRuleSetIDInsensitively(t *testing.T) { { // missing ProfileName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/", Error: true, }, { // missing value for ProfileName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/", Error: true, }, { // missing RuleSetName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/", Error: true, }, { // missing value for RuleSetName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/", Error: true, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/ruleSet1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/ruleSet1", Expected: &FrontDoorRuleSetId{ SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resourceGroup1", + ResourceGroup: "resGroup1", ProfileName: "profile1", RuleSetName: "ruleSet1", }, @@ -201,10 +201,10 @@ func TestFrontDoorRuleSetIDInsensitively(t *testing.T) { { // lower-cased segment names - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/rulesets/ruleSet1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/rulesets/ruleSet1", Expected: &FrontDoorRuleSetId{ SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resourceGroup1", + ResourceGroup: "resGroup1", ProfileName: "profile1", RuleSetName: "ruleSet1", }, @@ -212,10 +212,10 @@ func TestFrontDoorRuleSetIDInsensitively(t *testing.T) { { // upper-cased segment names - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/PROFILES/profile1/RULESETS/ruleSet1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/PROFILES/profile1/RULESETS/ruleSet1", Expected: &FrontDoorRuleSetId{ SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resourceGroup1", + ResourceGroup: "resGroup1", ProfileName: "profile1", RuleSetName: "ruleSet1", }, @@ -223,10 +223,10 @@ func TestFrontDoorRuleSetIDInsensitively(t *testing.T) { { // mixed-cased segment names - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/PrOfIlEs/profile1/RuLeSeTs/ruleSet1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/PrOfIlEs/profile1/RuLeSeTs/ruleSet1", Expected: &FrontDoorRuleSetId{ SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resourceGroup1", + ResourceGroup: "resGroup1", ProfileName: "profile1", RuleSetName: "ruleSet1", }, diff --git a/internal/services/cdn/parse/front_door_rule_test.go b/internal/services/cdn/parse/front_door_rule_test.go index 84e83c640e65..eb75b42bdab3 100644 --- a/internal/services/cdn/parse/front_door_rule_test.go +++ b/internal/services/cdn/parse/front_door_rule_test.go @@ -11,8 +11,8 @@ import ( var _ resourceids.Id = FrontDoorRuleId{} func TestFrontDoorRuleIDFormatter(t *testing.T) { - actual := NewFrontDoorRuleID("12345678-1234-9876-4563-123456789012", "resourceGroup1", "profile1", "ruleSet1", "rule1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/ruleSet1/rules/rule1" + actual := NewFrontDoorRuleID("12345678-1234-9876-4563-123456789012", "resGroup1", "profile1", "ruleSet1", "rule1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/ruleSet1/rules/rule1" if actual != expected { t.Fatalf("Expected %q but got %q", expected, actual) } @@ -57,46 +57,46 @@ func TestFrontDoorRuleID(t *testing.T) { { // missing ProfileName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/", Error: true, }, { // missing value for ProfileName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/", Error: true, }, { // missing RuleSetName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/", Error: true, }, { // missing value for RuleSetName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/", Error: true, }, { // missing RuleName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/ruleSet1/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/ruleSet1/", Error: true, }, { // missing value for RuleName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/ruleSet1/rules/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/ruleSet1/rules/", Error: true, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/ruleSet1/rules/rule1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/ruleSet1/rules/rule1", Expected: &FrontDoorRuleId{ SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resourceGroup1", + ResourceGroup: "resGroup1", ProfileName: "profile1", RuleSetName: "ruleSet1", RuleName: "rule1", @@ -105,7 +105,7 @@ func TestFrontDoorRuleID(t *testing.T) { { // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESOURCEGROUP1/PROVIDERS/MICROSOFT.CDN/PROFILES/PROFILE1/RULESETS/RULESET1/RULES/RULE1", + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.CDN/PROFILES/PROFILE1/RULESETS/RULESET1/RULES/RULE1", Error: true, }, } @@ -182,46 +182,46 @@ func TestFrontDoorRuleIDInsensitively(t *testing.T) { { // missing ProfileName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/", Error: true, }, { // missing value for ProfileName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/", Error: true, }, { // missing RuleSetName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/", Error: true, }, { // missing value for RuleSetName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/", Error: true, }, { // missing RuleName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/ruleSet1/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/ruleSet1/", Error: true, }, { // missing value for RuleName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/ruleSet1/rules/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/ruleSet1/rules/", Error: true, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/ruleSet1/rules/rule1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/ruleSet1/rules/rule1", Expected: &FrontDoorRuleId{ SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resourceGroup1", + ResourceGroup: "resGroup1", ProfileName: "profile1", RuleSetName: "ruleSet1", RuleName: "rule1", @@ -230,10 +230,10 @@ func TestFrontDoorRuleIDInsensitively(t *testing.T) { { // lower-cased segment names - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/rulesets/ruleSet1/rules/rule1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/rulesets/ruleSet1/rules/rule1", Expected: &FrontDoorRuleId{ SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resourceGroup1", + ResourceGroup: "resGroup1", ProfileName: "profile1", RuleSetName: "ruleSet1", RuleName: "rule1", @@ -242,10 +242,10 @@ func TestFrontDoorRuleIDInsensitively(t *testing.T) { { // upper-cased segment names - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/PROFILES/profile1/RULESETS/ruleSet1/RULES/rule1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/PROFILES/profile1/RULESETS/ruleSet1/RULES/rule1", Expected: &FrontDoorRuleId{ SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resourceGroup1", + ResourceGroup: "resGroup1", ProfileName: "profile1", RuleSetName: "ruleSet1", RuleName: "rule1", @@ -254,10 +254,10 @@ func TestFrontDoorRuleIDInsensitively(t *testing.T) { { // mixed-cased segment names - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/PrOfIlEs/profile1/RuLeSeTs/ruleSet1/RuLeS/rule1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/PrOfIlEs/profile1/RuLeSeTs/ruleSet1/RuLeS/rule1", Expected: &FrontDoorRuleId{ SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resourceGroup1", + ResourceGroup: "resGroup1", ProfileName: "profile1", RuleSetName: "ruleSet1", RuleName: "rule1", diff --git a/internal/services/cdn/parse/front_door_security_policy.go b/internal/services/cdn/parse/front_door_security_policy.go new file mode 100644 index 000000000000..fa64a9954c49 --- /dev/null +++ b/internal/services/cdn/parse/front_door_security_policy.go @@ -0,0 +1,131 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + "strings" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +type FrontDoorSecurityPolicyId struct { + SubscriptionId string + ResourceGroup string + ProfileName string + SecurityPolicyName string +} + +func NewFrontDoorSecurityPolicyID(subscriptionId, resourceGroup, profileName, securityPolicyName string) FrontDoorSecurityPolicyId { + return FrontDoorSecurityPolicyId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + ProfileName: profileName, + SecurityPolicyName: securityPolicyName, + } +} + +func (id FrontDoorSecurityPolicyId) String() string { + segments := []string{ + fmt.Sprintf("Security Policy Name %q", id.SecurityPolicyName), + fmt.Sprintf("Profile Name %q", id.ProfileName), + fmt.Sprintf("Resource Group %q", id.ResourceGroup), + } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "Front Door Security Policy", segmentsStr) +} + +func (id FrontDoorSecurityPolicyId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Cdn/profiles/%s/securityPolicies/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.ProfileName, id.SecurityPolicyName) +} + +// FrontDoorSecurityPolicyID parses a FrontDoorSecurityPolicy ID into an FrontDoorSecurityPolicyId struct +func FrontDoorSecurityPolicyID(input string) (*FrontDoorSecurityPolicyId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := FrontDoorSecurityPolicyId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + if resourceId.ProfileName, err = id.PopSegment("profiles"); err != nil { + return nil, err + } + if resourceId.SecurityPolicyName, err = id.PopSegment("securityPolicies"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} + +// FrontDoorSecurityPolicyIDInsensitively parses an FrontDoorSecurityPolicy ID into an FrontDoorSecurityPolicyId struct, insensitively +// This should only be used to parse an ID for rewriting, the FrontDoorSecurityPolicyID +// method should be used instead for validation etc. +// +// Whilst this may seem strange, this enables Terraform have consistent casing +// which works around issues in Core, whilst handling broken API responses. +func FrontDoorSecurityPolicyIDInsensitively(input string) (*FrontDoorSecurityPolicyId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := FrontDoorSecurityPolicyId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + // find the correct casing for the 'profiles' segment + profilesKey := "profiles" + for key := range id.Path { + if strings.EqualFold(key, profilesKey) { + profilesKey = key + break + } + } + if resourceId.ProfileName, err = id.PopSegment(profilesKey); err != nil { + return nil, err + } + + // find the correct casing for the 'securityPolicies' segment + securityPoliciesKey := "securityPolicies" + for key := range id.Path { + if strings.EqualFold(key, securityPoliciesKey) { + securityPoliciesKey = key + break + } + } + if resourceId.SecurityPolicyName, err = id.PopSegment(securityPoliciesKey); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} diff --git a/internal/services/cdn/parse/front_door_security_policy_test.go b/internal/services/cdn/parse/front_door_security_policy_test.go new file mode 100644 index 000000000000..e84ab01eb1b7 --- /dev/null +++ b/internal/services/cdn/parse/front_door_security_policy_test.go @@ -0,0 +1,264 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "testing" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +var _ resourceids.Id = FrontDoorSecurityPolicyId{} + +func TestFrontDoorSecurityPolicyIDFormatter(t *testing.T) { + actual := NewFrontDoorSecurityPolicyID("12345678-1234-9876-4563-123456789012", "resGroup1", "profile1", "securityPolicy1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/securityPolicies/securityPolicy1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestFrontDoorSecurityPolicyID(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *FrontDoorSecurityPolicyId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing ProfileName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/", + Error: true, + }, + + { + // missing value for ProfileName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/", + Error: true, + }, + + { + // missing SecurityPolicyName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/", + Error: true, + }, + + { + // missing value for SecurityPolicyName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/securityPolicies/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/securityPolicies/securityPolicy1", + Expected: &FrontDoorSecurityPolicyId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ProfileName: "profile1", + SecurityPolicyName: "securityPolicy1", + }, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.CDN/PROFILES/PROFILE1/SECURITYPOLICIES/SECURITYPOLICY1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := FrontDoorSecurityPolicyID(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.ProfileName != v.Expected.ProfileName { + t.Fatalf("Expected %q but got %q for ProfileName", v.Expected.ProfileName, actual.ProfileName) + } + if actual.SecurityPolicyName != v.Expected.SecurityPolicyName { + t.Fatalf("Expected %q but got %q for SecurityPolicyName", v.Expected.SecurityPolicyName, actual.SecurityPolicyName) + } + } +} + +func TestFrontDoorSecurityPolicyIDInsensitively(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *FrontDoorSecurityPolicyId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing ProfileName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/", + Error: true, + }, + + { + // missing value for ProfileName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/", + Error: true, + }, + + { + // missing SecurityPolicyName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/", + Error: true, + }, + + { + // missing value for SecurityPolicyName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/securityPolicies/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/securityPolicies/securityPolicy1", + Expected: &FrontDoorSecurityPolicyId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ProfileName: "profile1", + SecurityPolicyName: "securityPolicy1", + }, + }, + + { + // lower-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/securitypolicies/securityPolicy1", + Expected: &FrontDoorSecurityPolicyId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ProfileName: "profile1", + SecurityPolicyName: "securityPolicy1", + }, + }, + + { + // upper-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/PROFILES/profile1/SECURITYPOLICIES/securityPolicy1", + Expected: &FrontDoorSecurityPolicyId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ProfileName: "profile1", + SecurityPolicyName: "securityPolicy1", + }, + }, + + { + // mixed-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/PrOfIlEs/profile1/SeCuRiTyPoLiCiEs/securityPolicy1", + Expected: &FrontDoorSecurityPolicyId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ProfileName: "profile1", + SecurityPolicyName: "securityPolicy1", + }, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := FrontDoorSecurityPolicyIDInsensitively(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.ProfileName != v.Expected.ProfileName { + t.Fatalf("Expected %q but got %q for ProfileName", v.Expected.ProfileName, actual.ProfileName) + } + if actual.SecurityPolicyName != v.Expected.SecurityPolicyName { + t.Fatalf("Expected %q but got %q for SecurityPolicyName", v.Expected.SecurityPolicyName, actual.SecurityPolicyName) + } + } +} diff --git a/internal/services/cdn/parse/frontdoor_custom_domain.go b/internal/services/cdn/parse/frontdoor_custom_domain.go new file mode 100644 index 000000000000..3e7576e45d0b --- /dev/null +++ b/internal/services/cdn/parse/frontdoor_custom_domain.go @@ -0,0 +1,131 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + "strings" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +type FrontdoorCustomDomainId struct { + SubscriptionId string + ResourceGroup string + ProfileName string + CustomDomainName string +} + +func NewFrontdoorCustomDomainID(subscriptionId, resourceGroup, profileName, customDomainName string) FrontdoorCustomDomainId { + return FrontdoorCustomDomainId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + ProfileName: profileName, + CustomDomainName: customDomainName, + } +} + +func (id FrontdoorCustomDomainId) String() string { + segments := []string{ + fmt.Sprintf("Custom Domain Name %q", id.CustomDomainName), + fmt.Sprintf("Profile Name %q", id.ProfileName), + fmt.Sprintf("Resource Group %q", id.ResourceGroup), + } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "Frontdoor Custom Domain", segmentsStr) +} + +func (id FrontdoorCustomDomainId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Cdn/profiles/%s/customDomains/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.ProfileName, id.CustomDomainName) +} + +// FrontdoorCustomDomainID parses a FrontdoorCustomDomain ID into an FrontdoorCustomDomainId struct +func FrontdoorCustomDomainID(input string) (*FrontdoorCustomDomainId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := FrontdoorCustomDomainId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + if resourceId.ProfileName, err = id.PopSegment("profiles"); err != nil { + return nil, err + } + if resourceId.CustomDomainName, err = id.PopSegment("customDomains"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} + +// FrontdoorCustomDomainIDInsensitively parses an FrontdoorCustomDomain ID into an FrontdoorCustomDomainId struct, insensitively +// This should only be used to parse an ID for rewriting, the FrontdoorCustomDomainID +// method should be used instead for validation etc. +// +// Whilst this may seem strange, this enables Terraform have consistent casing +// which works around issues in Core, whilst handling broken API responses. +func FrontdoorCustomDomainIDInsensitively(input string) (*FrontdoorCustomDomainId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := FrontdoorCustomDomainId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + // find the correct casing for the 'profiles' segment + profilesKey := "profiles" + for key := range id.Path { + if strings.EqualFold(key, profilesKey) { + profilesKey = key + break + } + } + if resourceId.ProfileName, err = id.PopSegment(profilesKey); err != nil { + return nil, err + } + + // find the correct casing for the 'customDomains' segment + customDomainsKey := "customDomains" + for key := range id.Path { + if strings.EqualFold(key, customDomainsKey) { + customDomainsKey = key + break + } + } + if resourceId.CustomDomainName, err = id.PopSegment(customDomainsKey); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} diff --git a/internal/services/cdn/parse/frontdoor_custom_domain_test.go b/internal/services/cdn/parse/frontdoor_custom_domain_test.go new file mode 100644 index 000000000000..7373d1bdfa7d --- /dev/null +++ b/internal/services/cdn/parse/frontdoor_custom_domain_test.go @@ -0,0 +1,264 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "testing" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +var _ resourceids.Id = FrontdoorCustomDomainId{} + +func TestFrontdoorCustomDomainIDFormatter(t *testing.T) { + actual := NewFrontdoorCustomDomainID("12345678-1234-9876-4563-123456789012", "resourceGroup1", "profile1", "customDomain1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/customDomain1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestFrontdoorCustomDomainID(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *FrontdoorCustomDomainId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing ProfileName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/", + Error: true, + }, + + { + // missing value for ProfileName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/", + Error: true, + }, + + { + // missing CustomDomainName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/", + Error: true, + }, + + { + // missing value for CustomDomainName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/customDomain1", + Expected: &FrontdoorCustomDomainId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resourceGroup1", + ProfileName: "profile1", + CustomDomainName: "customDomain1", + }, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESOURCEGROUP1/PROVIDERS/MICROSOFT.CDN/PROFILES/PROFILE1/CUSTOMDOMAINS/CUSTOMDOMAIN1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := FrontdoorCustomDomainID(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.ProfileName != v.Expected.ProfileName { + t.Fatalf("Expected %q but got %q for ProfileName", v.Expected.ProfileName, actual.ProfileName) + } + if actual.CustomDomainName != v.Expected.CustomDomainName { + t.Fatalf("Expected %q but got %q for CustomDomainName", v.Expected.CustomDomainName, actual.CustomDomainName) + } + } +} + +func TestFrontdoorCustomDomainIDInsensitively(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *FrontdoorCustomDomainId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing ProfileName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/", + Error: true, + }, + + { + // missing value for ProfileName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/", + Error: true, + }, + + { + // missing CustomDomainName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/", + Error: true, + }, + + { + // missing value for CustomDomainName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/customDomain1", + Expected: &FrontdoorCustomDomainId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resourceGroup1", + ProfileName: "profile1", + CustomDomainName: "customDomain1", + }, + }, + + { + // lower-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/customdomains/customDomain1", + Expected: &FrontdoorCustomDomainId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resourceGroup1", + ProfileName: "profile1", + CustomDomainName: "customDomain1", + }, + }, + + { + // upper-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/PROFILES/profile1/CUSTOMDOMAINS/customDomain1", + Expected: &FrontdoorCustomDomainId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resourceGroup1", + ProfileName: "profile1", + CustomDomainName: "customDomain1", + }, + }, + + { + // mixed-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/PrOfIlEs/profile1/CuStOmDoMaInS/customDomain1", + Expected: &FrontdoorCustomDomainId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resourceGroup1", + ProfileName: "profile1", + CustomDomainName: "customDomain1", + }, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := FrontdoorCustomDomainIDInsensitively(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.ProfileName != v.Expected.ProfileName { + t.Fatalf("Expected %q but got %q for ProfileName", v.Expected.ProfileName, actual.ProfileName) + } + if actual.CustomDomainName != v.Expected.CustomDomainName { + t.Fatalf("Expected %q but got %q for CustomDomainName", v.Expected.CustomDomainName, actual.CustomDomainName) + } + } +} diff --git a/internal/services/cdn/registration.go b/internal/services/cdn/registration.go index daa1eff667fe..84356b8e519e 100644 --- a/internal/services/cdn/registration.go +++ b/internal/services/cdn/registration.go @@ -32,9 +32,10 @@ func (r Registration) SupportedDataSources() map[string]*pluginsdk.Resource { "azurerm_cdn_profile": dataSourceCdnProfile(), // FrontDoor - "azurerm_cdn_frontdoor_endpoint": dataSourceCdnFrontDoorEndpoint(), - "azurerm_cdn_frontdoor_profile": dataSourceCdnFrontDoorProfile(), - "azurerm_cdn_frontdoor_rule_set": dataSourceCdnFrontDoorRuleSet(), + "azurerm_cdn_frontdoor_endpoint": dataSourceCdnFrontDoorEndpoint(), + "azurerm_cdn_frontdoor_origin_group": dataSourceCdnFrontDoorOriginGroup(), + "azurerm_cdn_frontdoor_profile": dataSourceCdnFrontDoorProfile(), + "azurerm_cdn_frontdoor_rule_set": dataSourceCdnFrontDoorRuleSet(), } } @@ -47,8 +48,12 @@ func (r Registration) SupportedResources() map[string]*pluginsdk.Resource { "azurerm_cdn_profile": resourceCdnProfile(), // FrontDoor - "azurerm_cdn_frontdoor_endpoint": resourceCdnFrontDoorEndpoint(), - "azurerm_cdn_frontdoor_profile": resourceCdnFrontDoorProfile(), - "azurerm_cdn_frontdoor_rule_set": resourceCdnFrontDoorRuleSet(), + "azurerm_cdn_frontdoor_endpoint": resourceCdnFrontDoorEndpoint(), + "azurerm_cdn_frontdoor_firewall_policy": resourceCdnFrontDoorFirewallPolicy(), + "azurerm_cdn_frontdoor_origin": resourceCdnFrontDoorOrigin(), + "azurerm_cdn_frontdoor_origin_group": resourceCdnFrontDoorOriginGroup(), + "azurerm_cdn_frontdoor_profile": resourceCdnFrontDoorProfile(), + "azurerm_cdn_frontdoor_rule_set": resourceCdnFrontDoorRuleSet(), + "azurerm_cdn_frontdoor_security_policy": resourceCdnFrontDoorSecurityPolicy(), } } diff --git a/internal/services/cdn/resourceids.go b/internal/services/cdn/resourceids.go index 8c08a9e353f7..fe6e58d9c0ca 100644 --- a/internal/services/cdn/resourceids.go +++ b/internal/services/cdn/resourceids.go @@ -6,7 +6,12 @@ package cdn //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=CustomDomain -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/endpoints/endpoint1/customDomains/domain1 // CDN FrontDoor -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=FrontDoorEndpoint -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/afdEndpoints/endpoint1 -rewrite=true -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=FrontDoorProfile -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1 -rewrite=true -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=FrontDoorRuleSet -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/ruleSet1 -rewrite=true -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=FrontDoorRule -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/ruleSet1/rules/rule1 -rewrite=true +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=FrontDoorCustomDomain -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/customDomain1 -rewrite=true +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=FrontDoorEndpoint -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/afdEndpoints/endpoint1 -rewrite=true +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=FrontDoorFirewallPolicy -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/frontDoorWebApplicationFirewallPolicies/policy1 -rewrite=true +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=FrontDoorOrigin -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/originGroups/originGroup1/origins/origin1 -rewrite=true +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=FrontDoorOriginGroup -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/originGroups/originGroup1 -rewrite=true +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=FrontDoorProfile -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1 -rewrite=true +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=FrontDoorRuleSet -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/ruleSet1 -rewrite=true +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=FrontDoorRule -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/ruleSet1/rules/rule1 -rewrite=true +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=FrontDoorSecurityPolicy -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/securityPolicies/securityPolicy1 -rewrite=true diff --git a/internal/services/cdn/validate/cdn.go b/internal/services/cdn/validate/cdn.go index 54034e4a9e9b..daf4c329b8e2 100644 --- a/internal/services/cdn/validate/cdn.go +++ b/internal/services/cdn/validate/cdn.go @@ -12,21 +12,21 @@ import ( func EndpointDeliveryRuleName() pluginsdk.SchemaValidateFunc { return validation.StringMatch( regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9]*$"), - "The Delivery Rule Name must start with a letter any may only contain letters and numbers.", + "the Delivery Rule Name must start with a letter any may only contain letters and numbers", ) } func RuleActionCacheExpirationDuration() pluginsdk.SchemaValidateFunc { return validation.StringMatch( regexp.MustCompile(`^(\d+\.)?([0-1][0-9]|[2][0-3]):[0-5][0-9]:[0-5][0-9]$`), - "The Cache duration must be in this format [d.]hh:mm:ss.", + "the Cache duration must be in this format [d.]hh:mm:ss", ) } func RuleActionUrlRedirectPath() pluginsdk.SchemaValidateFunc { return validation.StringMatch( regexp.MustCompile("^(/.*)?$"), - "The Url Redirect Path must start with a slash.", + "the Url Redirect Path must start with a slash", ) } @@ -35,19 +35,19 @@ func RuleActionUrlRedirectQueryString() pluginsdk.SchemaValidateFunc { querystring := i.(string) if len(querystring) > 100 { - return nil, []error{fmt.Errorf("The Url Query String's max length is 100.")} + return nil, []error{fmt.Errorf("the Url Query String's max length is 100")} } re := regexp.MustCompile("^[?&]") if re.MatchString(querystring) { - return nil, []error{fmt.Errorf("The Url Query String must not start with a question mark or ampersand.")} + return nil, []error{fmt.Errorf("the Url Query String must not start with a question mark or ampersand")} } kvre := regexp.MustCompile("^[^?&]+=[^?&]+$") kvs := strings.Split(querystring, "&") for _, kv := range kvs { if len(kv) > 0 && !kvre.MatchString(kv) { - return nil, []error{fmt.Errorf("The Url Query String must be in = format and separated by an ampersand.")} + return nil, []error{fmt.Errorf("the Url Query String must be in = format and separated by an ampersand")} } } @@ -58,20 +58,20 @@ func RuleActionUrlRedirectQueryString() pluginsdk.SchemaValidateFunc { func RuleActionUrlRedirectFragment() pluginsdk.SchemaValidateFunc { return validation.StringMatch( regexp.MustCompile("^([^#].*)?$"), - "The Url Fragment must not start with a hash.", + "the Url Fragment must not start with a hash.", ) } func RuleActionUrlRewriteSourcePattern() pluginsdk.SchemaValidateFunc { return validation.StringMatch( regexp.MustCompile("^/[^\n]{0,259}$"), - "The Url Rewrite Source Pattern must start with a slash and can not have more than 260 characters.", + "the Url Rewrite Source Pattern must start with a slash and can not have more than 260 characters", ) } func RuleActionUrlRewriteDestination() pluginsdk.SchemaValidateFunc { return validation.StringMatch( regexp.MustCompile("^/[^\n]{0,259}$"), - "The Url Rewrite Destination must start with a slash and can not have more than 260 characters.", + "the Url Rewrite Destination must start with a slash and can not have more than 260 characters", ) } diff --git a/internal/services/cdn/validate/front_door_custom_domain_id.go b/internal/services/cdn/validate/front_door_custom_domain_id.go new file mode 100644 index 000000000000..e549b2f41206 --- /dev/null +++ b/internal/services/cdn/validate/front_door_custom_domain_id.go @@ -0,0 +1,23 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + + "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/parse" +) + +func FrontDoorCustomDomainID(input interface{}, key string) (warnings []string, errors []error) { + v, ok := input.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected %q to be a string", key)) + return + } + + if _, err := parse.FrontDoorCustomDomainID(v); err != nil { + errors = append(errors, err) + } + + return +} diff --git a/internal/services/cdn/validate/front_door_custom_domain_id_test.go b/internal/services/cdn/validate/front_door_custom_domain_id_test.go new file mode 100644 index 000000000000..1027698c1dcb --- /dev/null +++ b/internal/services/cdn/validate/front_door_custom_domain_id_test.go @@ -0,0 +1,88 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import "testing" + +func TestFrontDoorCustomDomainID(t *testing.T) { + cases := []struct { + Input string + Valid bool + }{ + + { + // empty + Input: "", + Valid: false, + }, + + { + // missing SubscriptionId + Input: "/", + Valid: false, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Valid: false, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Valid: false, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Valid: false, + }, + + { + // missing ProfileName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/", + Valid: false, + }, + + { + // missing value for ProfileName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/", + Valid: false, + }, + + { + // missing CustomDomainName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/", + Valid: false, + }, + + { + // missing value for CustomDomainName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/", + Valid: false, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/customDomains/customDomain1", + Valid: true, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.CDN/PROFILES/PROFILE1/CUSTOMDOMAINS/CUSTOMDOMAIN1", + Valid: false, + }, + } + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.Input) + _, errors := FrontDoorCustomDomainID(tc.Input, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} diff --git a/internal/services/cdn/validate/front_door_endpoint_id_test.go b/internal/services/cdn/validate/front_door_endpoint_id_test.go index 4ed43c1f45e4..e02091f71804 100644 --- a/internal/services/cdn/validate/front_door_endpoint_id_test.go +++ b/internal/services/cdn/validate/front_door_endpoint_id_test.go @@ -42,37 +42,37 @@ func TestFrontDoorEndpointID(t *testing.T) { { // missing ProfileName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/", Valid: false, }, { // missing value for ProfileName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/", Valid: false, }, { // missing AfdEndpointName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/", Valid: false, }, { // missing value for AfdEndpointName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/afdEndpoints/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/afdEndpoints/", Valid: false, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/afdEndpoints/endpoint1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/afdEndpoints/endpoint1", Valid: true, }, { // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESOURCEGROUP1/PROVIDERS/MICROSOFT.CDN/PROFILES/PROFILE1/AFDENDPOINTS/ENDPOINT1", + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.CDN/PROFILES/PROFILE1/AFDENDPOINTS/ENDPOINT1", Valid: false, }, } diff --git a/internal/services/cdn/validate/front_door_firewall_policy_id.go b/internal/services/cdn/validate/front_door_firewall_policy_id.go new file mode 100644 index 000000000000..8835e3e0baaf --- /dev/null +++ b/internal/services/cdn/validate/front_door_firewall_policy_id.go @@ -0,0 +1,23 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + + "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/parse" +) + +func FrontDoorFirewallPolicyID(input interface{}, key string) (warnings []string, errors []error) { + v, ok := input.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected %q to be a string", key)) + return + } + + if _, err := parse.FrontDoorFirewallPolicyID(v); err != nil { + errors = append(errors, err) + } + + return +} diff --git a/internal/services/cdn/validate/front_door_firewall_policy_id_test.go b/internal/services/cdn/validate/front_door_firewall_policy_id_test.go new file mode 100644 index 000000000000..a650a7f76edc --- /dev/null +++ b/internal/services/cdn/validate/front_door_firewall_policy_id_test.go @@ -0,0 +1,76 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import "testing" + +func TestFrontDoorFirewallPolicyID(t *testing.T) { + cases := []struct { + Input string + Valid bool + }{ + + { + // empty + Input: "", + Valid: false, + }, + + { + // missing SubscriptionId + Input: "/", + Valid: false, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Valid: false, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Valid: false, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Valid: false, + }, + + { + // missing FrontDoorWebApplicationFirewallPolicyName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/", + Valid: false, + }, + + { + // missing value for FrontDoorWebApplicationFirewallPolicyName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/frontDoorWebApplicationFirewallPolicies/", + Valid: false, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/frontDoorWebApplicationFirewallPolicies/policy1", + Valid: true, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.NETWORK/FRONTDOORWEBAPPLICATIONFIREWALLPOLICIES/POLICY1", + Valid: false, + }, + } + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.Input) + _, errors := FrontDoorFirewallPolicyID(tc.Input, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} diff --git a/internal/services/cdn/validate/front_door_firewall_policy_name.go b/internal/services/cdn/validate/front_door_firewall_policy_name.go new file mode 100644 index 000000000000..5ceb879a49a2 --- /dev/null +++ b/internal/services/cdn/validate/front_door_firewall_policy_name.go @@ -0,0 +1,15 @@ +package validate + +import ( + "fmt" + + "github.com/hashicorp/terraform-provider-azurerm/helpers/validate" +) + +func FrontDoorFirewallPolicyName(i interface{}, k string) (_ []string, errors []error) { + if m, regexErrs := validate.RegExHelper(i, k, `(^[a-zA-Z])([\da-zA-Z]{0,127})$`); !m { + return nil, append(regexErrs, fmt.Errorf(`%q must be between 1 and 128 characters in length, must begin with a letter and may only contain letters and numbers`, k)) + } + + return nil, nil +} diff --git a/internal/services/cdn/validate/front_door_firewall_policy_name_test.go b/internal/services/cdn/validate/front_door_firewall_policy_name_test.go new file mode 100644 index 000000000000..e93199d08388 --- /dev/null +++ b/internal/services/cdn/validate/front_door_firewall_policy_name_test.go @@ -0,0 +1,86 @@ +package validate + +import "testing" + +func TestFrontDoorFirewallPolicyName(t *testing.T) { + cases := []struct { + Input string + Valid bool + }{ + { + // Empty + Input: "", + Valid: false, + }, + + { + // Min Len + Input: "A", + Valid: true, + }, + + { + // Max Len + Input: "AAAAAAAAAAAAAHHHHHHHHHHHHHHHHIIIIIIIIIIIIIIIIIEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", + Valid: true, + }, + + { + // Too Long + Input: "AAAAAAAAAAAAAHHHHHHHHHHHHHHHHIIIIIIIIIIIIIIIIIEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", + Valid: false, + }, + + { + // Invalid Character + Input: "1%A", + Valid: false, + }, + + { + // Start With Hyphen + Input: "-1", + Valid: false, + }, + + { + // End With Hyphen + Input: "1-", + Valid: false, + }, + + { + // Start With Letter, End With Letter + Input: "AA", + Valid: true, + }, + + { + // Start With Number, End With Number + Input: "11", + Valid: false, + }, + + { + // Start With Letter, End With Number + Input: "A1", + Valid: true, + }, + + { + // Start With Letter, End With Letter and Hyphen Separator + Input: "A-A", + Valid: false, + }, + } + + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.Input) + _, errors := FrontDoorFirewallPolicyName(tc.Input, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Testing value %q, Expected %t but got %t", tc.Input, tc.Valid, valid) + } + } +} diff --git a/internal/services/cdn/validate/front_door_origin_group_id.go b/internal/services/cdn/validate/front_door_origin_group_id.go new file mode 100644 index 000000000000..9ea19a01282e --- /dev/null +++ b/internal/services/cdn/validate/front_door_origin_group_id.go @@ -0,0 +1,23 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + + "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/parse" +) + +func FrontDoorOriginGroupID(input interface{}, key string) (warnings []string, errors []error) { + v, ok := input.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected %q to be a string", key)) + return + } + + if _, err := parse.FrontDoorOriginGroupID(v); err != nil { + errors = append(errors, err) + } + + return +} diff --git a/internal/services/cdn/validate/front_door_origin_group_id_test.go b/internal/services/cdn/validate/front_door_origin_group_id_test.go new file mode 100644 index 000000000000..4709f450956b --- /dev/null +++ b/internal/services/cdn/validate/front_door_origin_group_id_test.go @@ -0,0 +1,88 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import "testing" + +func TestFrontDoorOriginGroupID(t *testing.T) { + cases := []struct { + Input string + Valid bool + }{ + + { + // empty + Input: "", + Valid: false, + }, + + { + // missing SubscriptionId + Input: "/", + Valid: false, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Valid: false, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Valid: false, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Valid: false, + }, + + { + // missing ProfileName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/", + Valid: false, + }, + + { + // missing value for ProfileName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/", + Valid: false, + }, + + { + // missing OriginGroupName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/", + Valid: false, + }, + + { + // missing value for OriginGroupName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/originGroups/", + Valid: false, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/originGroups/originGroup1", + Valid: true, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.CDN/PROFILES/PROFILE1/ORIGINGROUPS/ORIGINGROUP1", + Valid: false, + }, + } + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.Input) + _, errors := FrontDoorOriginGroupID(tc.Input, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} diff --git a/internal/services/cdn/validate/front_door_origin_group_name.go b/internal/services/cdn/validate/front_door_origin_group_name.go new file mode 100644 index 000000000000..85c209b935f5 --- /dev/null +++ b/internal/services/cdn/validate/front_door_origin_group_name.go @@ -0,0 +1,15 @@ +package validate + +import ( + "fmt" + + "github.com/hashicorp/terraform-provider-azurerm/helpers/validate" +) + +func FrontDoorOriginGroupName(i interface{}, k string) (_ []string, errors []error) { + if m, regexErrs := validate.RegExHelper(i, k, `^[\da-zA-Z][-\da-zA-Z]{0,88}[\da-zA-Z]$`); !m { + return nil, append(regexErrs, fmt.Errorf(`%q must be between 2 and 90 characters in length, begin with a letter or number, end with a letter or number and may contain only letters, numbers and hyphens, got %q`, k, i)) + } + + return nil, nil +} diff --git a/internal/services/cdn/validate/front_door_origin_group_name_test.go b/internal/services/cdn/validate/front_door_origin_group_name_test.go new file mode 100644 index 000000000000..e068979dc740 --- /dev/null +++ b/internal/services/cdn/validate/front_door_origin_group_name_test.go @@ -0,0 +1,110 @@ +package validate + +import "testing" + +func TestFrontDoorOriginGroupName(t *testing.T) { + cases := []struct { + Input string + Valid bool + }{ + { + // Empty + Input: "", + Valid: false, + }, + + { + // Max Len + Input: "AAAAAAAAAAAAAHHHHHHHHHHHHHHHHIIIIIIIIIIIIIIIIIEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", + Valid: true, + }, + + { + // Too Long + Input: "AAAAAAAAAAAAAHHHHHHHHHHHHHHHHIIIIIIIIIIIIIIIIIEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", + Valid: false, + }, + + { + // Invalid Character + Input: "1%A", + Valid: false, + }, + + { + // Start With Hyphen + Input: "-1", + Valid: false, + }, + + { + // End With Hyphen + Input: "1-", + Valid: false, + }, + + { + // Too Short + Input: "1", + Valid: false, + }, + + { + // Start With Letter, End With Letter + Input: "AA", + Valid: true, + }, + + { + // Start With Number, End With Number + Input: "11", + Valid: true, + }, + + { + // Start With Letter, End With Number + Input: "A1", + Valid: true, + }, + + { + // Start With Number, End With Letter + Input: "1A", + Valid: true, + }, + + { + // Start With Letter, End With Letter and Hyphen Separator + Input: "A-A", + Valid: true, + }, + + { + // Start With Number, End With Number and Hyphen Separator + Input: "1-1", + Valid: true, + }, + + { + // Start With Letter, End With Number and Hyphen Separator + Input: "A-1", + Valid: true, + }, + + { + // Start With Number, End With Letter and Hyphen Separator + Input: "1-A", + Valid: true, + }, + } + + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.Input) + _, errors := FrontDoorOriginGroupName(tc.Input, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} diff --git a/internal/services/cdn/validate/front_door_origin_id.go b/internal/services/cdn/validate/front_door_origin_id.go new file mode 100644 index 000000000000..f20ff81b846f --- /dev/null +++ b/internal/services/cdn/validate/front_door_origin_id.go @@ -0,0 +1,23 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + + "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/parse" +) + +func FrontDoorOriginID(input interface{}, key string) (warnings []string, errors []error) { + v, ok := input.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected %q to be a string", key)) + return + } + + if _, err := parse.FrontDoorOriginID(v); err != nil { + errors = append(errors, err) + } + + return +} diff --git a/internal/services/cdn/validate/front_door_origin_id_test.go b/internal/services/cdn/validate/front_door_origin_id_test.go new file mode 100644 index 000000000000..b904162867b0 --- /dev/null +++ b/internal/services/cdn/validate/front_door_origin_id_test.go @@ -0,0 +1,100 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import "testing" + +func TestFrontDoorOriginID(t *testing.T) { + cases := []struct { + Input string + Valid bool + }{ + + { + // empty + Input: "", + Valid: false, + }, + + { + // missing SubscriptionId + Input: "/", + Valid: false, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Valid: false, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Valid: false, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Valid: false, + }, + + { + // missing ProfileName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/", + Valid: false, + }, + + { + // missing value for ProfileName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/", + Valid: false, + }, + + { + // missing OriginGroupName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/", + Valid: false, + }, + + { + // missing value for OriginGroupName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/originGroups/", + Valid: false, + }, + + { + // missing OriginName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/originGroups/originGroup1/", + Valid: false, + }, + + { + // missing value for OriginName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/originGroups/originGroup1/origins/", + Valid: false, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/originGroups/originGroup1/origins/origin1", + Valid: true, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.CDN/PROFILES/PROFILE1/ORIGINGROUPS/ORIGINGROUP1/ORIGINS/ORIGIN1", + Valid: false, + }, + } + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.Input) + _, errors := FrontDoorOriginID(tc.Input, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} diff --git a/internal/services/cdn/validate/front_door_origin_name.go b/internal/services/cdn/validate/front_door_origin_name.go new file mode 100644 index 000000000000..4fd1a1c8648c --- /dev/null +++ b/internal/services/cdn/validate/front_door_origin_name.go @@ -0,0 +1,15 @@ +package validate + +import ( + "fmt" + + "github.com/hashicorp/terraform-provider-azurerm/helpers/validate" +) + +func FrontDoorOriginName(i interface{}, k string) (_ []string, errors []error) { + if m, regexErrs := validate.RegExHelper(i, k, `^[\da-zA-Z][-\da-zA-Z]{0,88}[\da-zA-Z]$`); !m { + return nil, append(regexErrs, fmt.Errorf(`%q must be between 2 and 90 characters in length, begin with a letter or number, end with a letter or number and may contain only letters, numbers and hyphens, got %q`, k, i)) + } + + return nil, nil +} diff --git a/internal/services/cdn/validate/front_door_origin_name_test.go b/internal/services/cdn/validate/front_door_origin_name_test.go new file mode 100644 index 000000000000..5126b552cd86 --- /dev/null +++ b/internal/services/cdn/validate/front_door_origin_name_test.go @@ -0,0 +1,110 @@ +package validate + +import "testing" + +func TestFrontDoorOriginName(t *testing.T) { + cases := []struct { + Input string + Valid bool + }{ + { + // Empty + Input: "", + Valid: false, + }, + + { + // Max Len + Input: "AAAAAAAAAAAAAHHHHHHHHHHHHHHHHIIIIIIIIIIIIIIIIIEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", + Valid: true, + }, + + { + // Too Long + Input: "AAAAAAAAAAAAAHHHHHHHHHHHHHHHHIIIIIIIIIIIIIIIIIEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", + Valid: false, + }, + + { + // Invalid Character + Input: "1%A", + Valid: false, + }, + + { + // Start With Hyphen + Input: "-1", + Valid: false, + }, + + { + // End With Hyphen + Input: "1-", + Valid: false, + }, + + { + // Too Short + Input: "1", + Valid: false, + }, + + { + // Start With Letter, End With Letter + Input: "AA", + Valid: true, + }, + + { + // Start With Number, End With Number + Input: "11", + Valid: true, + }, + + { + // Start With Letter, End With Number + Input: "A1", + Valid: true, + }, + + { + // Start With Number, End With Letter + Input: "1A", + Valid: true, + }, + + { + // Start With Letter, End With Letter and Hyphen Separator + Input: "A-A", + Valid: true, + }, + + { + // Start With Number, End With Number and Hyphen Separator + Input: "1-1", + Valid: true, + }, + + { + // Start With Letter, End With Number and Hyphen Separator + Input: "A-1", + Valid: true, + }, + + { + // Start With Number, End With Letter and Hyphen Separator + Input: "1-A", + Valid: true, + }, + } + + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.Input) + _, errors := FrontDoorOriginName(tc.Input, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} diff --git a/internal/services/cdn/validate/front_door_profile_id_test.go b/internal/services/cdn/validate/front_door_profile_id_test.go index a4aa17075a03..97fc6fb42849 100644 --- a/internal/services/cdn/validate/front_door_profile_id_test.go +++ b/internal/services/cdn/validate/front_door_profile_id_test.go @@ -42,25 +42,25 @@ func TestFrontDoorProfileID(t *testing.T) { { // missing ProfileName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/", Valid: false, }, { // missing value for ProfileName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/", Valid: false, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1", Valid: true, }, { // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESOURCEGROUP1/PROVIDERS/MICROSOFT.CDN/PROFILES/PROFILE1", + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.CDN/PROFILES/PROFILE1", Valid: false, }, } diff --git a/internal/services/cdn/validate/front_door_rule_id_test.go b/internal/services/cdn/validate/front_door_rule_id_test.go index 436e9526689d..2bf029c0cc6f 100644 --- a/internal/services/cdn/validate/front_door_rule_id_test.go +++ b/internal/services/cdn/validate/front_door_rule_id_test.go @@ -42,49 +42,49 @@ func TestFrontDoorRuleID(t *testing.T) { { // missing ProfileName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/", Valid: false, }, { // missing value for ProfileName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/", Valid: false, }, { // missing RuleSetName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/", Valid: false, }, { // missing value for RuleSetName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/", Valid: false, }, { // missing RuleName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/ruleSet1/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/ruleSet1/", Valid: false, }, { // missing value for RuleName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/ruleSet1/rules/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/ruleSet1/rules/", Valid: false, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/ruleSet1/rules/rule1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/ruleSet1/rules/rule1", Valid: true, }, { // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESOURCEGROUP1/PROVIDERS/MICROSOFT.CDN/PROFILES/PROFILE1/RULESETS/RULESET1/RULES/RULE1", + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.CDN/PROFILES/PROFILE1/RULESETS/RULESET1/RULES/RULE1", Valid: false, }, } diff --git a/internal/services/cdn/validate/front_door_rule_set_id_test.go b/internal/services/cdn/validate/front_door_rule_set_id_test.go index d08969e748a5..8b282a6ef80c 100644 --- a/internal/services/cdn/validate/front_door_rule_set_id_test.go +++ b/internal/services/cdn/validate/front_door_rule_set_id_test.go @@ -42,37 +42,37 @@ func TestFrontDoorRuleSetID(t *testing.T) { { // missing ProfileName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/", Valid: false, }, { // missing value for ProfileName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/", Valid: false, }, { // missing RuleSetName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/", Valid: false, }, { // missing value for RuleSetName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/", Valid: false, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/ruleSet1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/ruleSets/ruleSet1", Valid: true, }, { // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESOURCEGROUP1/PROVIDERS/MICROSOFT.CDN/PROFILES/PROFILE1/RULESETS/RULESET1", + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.CDN/PROFILES/PROFILE1/RULESETS/RULESET1", Valid: false, }, } diff --git a/internal/services/cdn/validate/front_door_security_policy_domain_id.go b/internal/services/cdn/validate/front_door_security_policy_domain_id.go new file mode 100644 index 000000000000..a3e140750102 --- /dev/null +++ b/internal/services/cdn/validate/front_door_security_policy_domain_id.go @@ -0,0 +1,24 @@ +package validate + +import ( + "fmt" +) + +func FrontDoorSecurityPolicyDomainID(i interface{}, k string) (_ []string, errors []error) { + _, ok := i.(string) + if !ok { + return nil, []error{fmt.Errorf("%q is invalid: expected type of %q to be string", "domain", k)} + } + + var err []error + + if _, err = FrontDoorCustomDomainID(i, k); err == nil { + return nil, nil + } + + if _, err = FrontDoorEndpointID(i, k); err == nil { + return nil, nil + } + + return nil, []error{fmt.Errorf("%q is invalid: the %q needs to be a valid Frontdoor Custom Domain ID or a Frontdoor Endpoint ID: %+v", "domain", k, err)} +} diff --git a/internal/services/cdn/validate/front_door_security_policy_id.go b/internal/services/cdn/validate/front_door_security_policy_id.go new file mode 100644 index 000000000000..1dab539a2080 --- /dev/null +++ b/internal/services/cdn/validate/front_door_security_policy_id.go @@ -0,0 +1,23 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + + "github.com/hashicorp/terraform-provider-azurerm/internal/services/cdn/parse" +) + +func FrontDoorSecurityPolicyID(input interface{}, key string) (warnings []string, errors []error) { + v, ok := input.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected %q to be a string", key)) + return + } + + if _, err := parse.FrontDoorSecurityPolicyID(v); err != nil { + errors = append(errors, err) + } + + return +} diff --git a/internal/services/cdn/validate/front_door_security_policy_id_test.go b/internal/services/cdn/validate/front_door_security_policy_id_test.go new file mode 100644 index 000000000000..1e4f2c2f4971 --- /dev/null +++ b/internal/services/cdn/validate/front_door_security_policy_id_test.go @@ -0,0 +1,88 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import "testing" + +func TestFrontDoorSecurityPolicyID(t *testing.T) { + cases := []struct { + Input string + Valid bool + }{ + + { + // empty + Input: "", + Valid: false, + }, + + { + // missing SubscriptionId + Input: "/", + Valid: false, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Valid: false, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Valid: false, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Valid: false, + }, + + { + // missing ProfileName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/", + Valid: false, + }, + + { + // missing value for ProfileName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/", + Valid: false, + }, + + { + // missing SecurityPolicyName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/", + Valid: false, + }, + + { + // missing value for SecurityPolicyName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/securityPolicies/", + Valid: false, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Cdn/profiles/profile1/securityPolicies/securityPolicy1", + Valid: true, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.CDN/PROFILES/PROFILE1/SECURITYPOLICIES/SECURITYPOLICY1", + Valid: false, + }, + } + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.Input) + _, errors := FrontDoorSecurityPolicyID(tc.Input, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} diff --git a/internal/services/cdn/validate/front_door_validation_helpers.go b/internal/services/cdn/validate/front_door_validation_helpers.go new file mode 100644 index 000000000000..f7bf10195464 --- /dev/null +++ b/internal/services/cdn/validate/front_door_validation_helpers.go @@ -0,0 +1,163 @@ +package validate + +import ( + "fmt" + "strings" + + "github.com/Azure/azure-sdk-for-go/services/cdn/mgmt/2021-06-01/cdn" + "github.com/hashicorp/terraform-provider-azurerm/helpers/validate" +) + +func CdnFrontDoorRouteName(i interface{}, k string) (_ []string, errors []error) { + if m, regexErrs := validate.RegExHelper(i, k, `^[\da-zA-Z][-\da-zA-Z]{0,88}[\da-zA-Z]$`); !m { + return nil, append(regexErrs, fmt.Errorf(`%q must be between 2 and 90 characters begin with a letter or number, end with a letter or number and may contain only letters, numbers or hyphens, got %q`, k, i)) + } + + return nil, nil +} + +func CdnFrontDoorCacheDuration(i interface{}, k string) (_ []string, errors []error) { + v, ok := i.(string) + if !ok { + return nil, []error{fmt.Errorf("expected type of %q to be string", k)} + } + + if strings.HasPrefix(v, "0.") { + return nil, []error{fmt.Errorf(`%q must not begin with %q if the duration is less than 1 day. If the %q is less than 1 day it should be in the HH:MM:SS format, got %q`, k, "0.", k, v)} + } + + if m, _ := validate.RegExHelper(i, k, `^([1-9]|([1-9][0-9])|([1-3][0-6][0-5])).((?:[01]\d|2[0123]):(?:[012345]\d):(?:[012345]\d))$|^((?:[01]\d|2[0123]):(?:[012345]\d):(?:[012345]\d))$`); !m { + return nil, []error{fmt.Errorf(`%q must be between in the d.HH:MM:SS or HH:MM:SS format and must be equal to or lower than %q, got %q`, k, "365.23:59:59", v)} + } + + if v == "00:00:00" { + return nil, []error{fmt.Errorf(`%q must be longer than zero seconds, got %q`, k, v)} + } + + return nil, nil +} + +func CdnFrontDoorUrlPathConditionMatchValue(i interface{}, k string) (_ []string, errors []error) { + v, ok := i.(string) + if !ok { + return nil, []error{fmt.Errorf("expected type of %q to be string", k)} + } + + if strings.HasPrefix(v, "/") { + return nil, []error{fmt.Errorf(`%q must not begin with the URLs leading slash(e.g. /), got %q`, k, v)} + } + + return nil, nil +} + +func CdnFrontDoorCustomDomainName(i interface{}, k string) (_ []string, errors []error) { + v, ok := i.(string) + if !ok { + return nil, []error{fmt.Errorf("expected type of %q to be string", k)} + } + + if m, _ := validate.RegExHelper(i, k, `^[a-zA-Z0-9][a-zA-Z0-9-]{0,258}[a-zA-Z0-9]$`); !m { + return nil, []error{fmt.Errorf(`%q must be between 2 and 260 characters in length, must begin with a letter or number, end with a letter or number and contain only letters, numbers and hyphens, got %q`, k, v)} + } + + return nil, nil +} + +func CdnFrontDoorSecretName(i interface{}, k string) (_ []string, errors []error) { + v, ok := i.(string) + if !ok { + return nil, []error{fmt.Errorf("expected type of %q to be string", k)} + } + + if m, _ := validate.RegExHelper(i, k, `^[a-zA-Z0-9][a-zA-Z0-9-]{0,258}[a-zA-Z0-9]$`); !m { + return nil, []error{fmt.Errorf(`%q must be between 2 and 260 characters in length, must begin with a letter or number, end with a letter or number and contain only letters, numbers and hyphens, got %q`, k, v)} + } + + return nil, nil +} + +func CdnFrontDoorActionsBlock(actions []cdn.BasicDeliveryRuleAction) error { + routeConfigurationOverride := false + responseHeader := false + requestHeader := false + urlRewrite := false + urlRedirect := false + + for _, rule := range actions { + if !routeConfigurationOverride { + _, routeConfigurationOverride = rule.AsDeliveryRuleRouteConfigurationOverrideAction() + } + + if !responseHeader { + _, responseHeader = rule.AsDeliveryRuleResponseHeaderAction() + } + + if !requestHeader { + _, requestHeader = rule.AsDeliveryRuleRequestHeaderAction() + } + + if !urlRewrite { + _, urlRewrite = rule.AsURLRewriteAction() + } + + if !urlRedirect { + _, urlRedirect = rule.AsURLRedirectAction() + } + } + + if urlRedirect && urlRewrite { + return fmt.Errorf("the %q and the %q are both present in the %q match block", "url_redirect_action", "url_rewrite_action", "actions") + } + + return nil +} + +func CdnFrontDoorRuleName(i interface{}, k string) (_ []string, errors []error) { + v, ok := i.(string) + if !ok { + return nil, []error{fmt.Errorf("expected type of %q to be string", k)} + } + + if m, _ := validate.RegExHelper(i, k, `^[a-zA-Z][\da-zA-Z]{0,259}$`); !m { + return nil, []error{fmt.Errorf(`%q must be between 1 and 260 characters in length, begin with a letter and may contain only letters and numbers, got %q`, k, v)} + } + + return nil, nil +} + +func CdnFrontDoorUrlRedirectActionQueryString(i interface{}, k string) (_ []string, errors []error) { + v, ok := i.(string) + if !ok { + return nil, []error{fmt.Errorf("%q is invalid: expected type of %q to be string", "url_redirect_action", k)} + } + + // Query string must be in = format. ? and & will be added automatically so do not include them. + if v != "" { + if strings.ContainsAny(v, "?&") { + return nil, []error{fmt.Errorf("%q is invalid: %q must not include the %q or the %q characters in the %q field. They will be automatically added by Frontdoor, got %q", "url_redirect_action", k, "?", "&", "query_string", v)} + } + + if m, _ := validate.RegExHelper(i, k, `^(\b[\da-zA-Z\-\._~]*)(={1})((\b[\da-zA-Z\-\._~]*)|(\{{1}\b(socket_ip|client_ip|client_port|hostname|geo_country|http_method|http_version|query_string|request_scheme|request_uri|ssl_protocol|server_port|url_path){1}\}){1})$`); !m { + return nil, []error{fmt.Errorf("%q is invalid: %q must be in the = or ={action_server_variable} format, got %q", "url_redirect_action", k, v)} + } + } else { + return nil, []error{fmt.Errorf("%q is invalid: %q must not be empty, got %q", "url_redirect_action", k, v)} + } + + return nil, nil +} + +func CdnFrontDoorUrlRedirectActionDestinationPath(i interface{}, k string) (_ []string, errors []error) { + v, ok := i.(string) + if !ok { + return nil, []error{fmt.Errorf("%q is invalid: expected type of %q to be string", "url_redirect_action", k)} + } + + if v != "" { + if !strings.HasPrefix(v, "/") { + return nil, []error{fmt.Errorf("%q is invalid: %q must begin with a %q, got %q. If you are trying to preserve the incoming path leave the %q value empty", "url_redirect_action", k, "/", v, "destination_path")} + } + } + + return nil, nil +} diff --git a/internal/services/cognitive/cognitive_account_resource.go b/internal/services/cognitive/cognitive_account_resource.go index 5a12af8a1029..ad3ae85214c9 100644 --- a/internal/services/cognitive/cognitive_account_resource.go +++ b/internal/services/cognitive/cognitive_account_resource.go @@ -89,6 +89,7 @@ func resourceCognitiveAccount() *pluginsdk.Resource { "LUIS", "LUIS.Authoring", "MetricsAdvisor", + "OpenAI", "Personalizer", "QnAMaker", "Recommendations", @@ -236,6 +237,12 @@ func resourceCognitiveAccount() *pluginsdk.Resource { ValidateFunc: search.ValidateSearchServiceID, }, + "custom_question_answering_search_service_key": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + "storage": { Type: pluginsdk.TypeList, Optional: true, @@ -636,10 +643,10 @@ func expandCognitiveAccountNetworkAcls(d *pluginsdk.ResourceData) (*cognitiveser defaultAction := cognitiveservicesaccounts.NetworkRuleAction(v["default_action"].(string)) ipRulesRaw := v["ip_rules"].(*pluginsdk.Set) - ipRules := make([]cognitiveservicesaccounts.IpRule, 0) + ipRules := make([]cognitiveservicesaccounts.IPRule, 0) for _, v := range ipRulesRaw.List() { - rule := cognitiveservicesaccounts.IpRule{ + rule := cognitiveservicesaccounts.IPRule{ Value: v.(string), } ipRules = append(ipRules, rule) @@ -660,7 +667,7 @@ func expandCognitiveAccountNetworkAcls(d *pluginsdk.ResourceData) (*cognitiveser ruleSet := cognitiveservicesaccounts.NetworkRuleSet{ DefaultAction: &defaultAction, - IpRules: &ipRules, + IPRules: &ipRules, VirtualNetworkRules: &networkRules, } return &ruleSet, subnetIds @@ -698,6 +705,13 @@ func expandCognitiveAccountAPIProperties(d *pluginsdk.ResourceData) (*cognitives return nil, fmt.Errorf("the Search Service ID `custom_question_answering_search_service_id` can only be set when kind is set to `TextAnalytics`") } } + if v, ok := d.GetOk("custom_question_answering_search_service_key"); ok { + if kind == "TextAnalytics" { + props.QnaAzureSearchEndpointKey = utils.String(v.(string)) + } else { + return nil, fmt.Errorf("the Search Service Key `custom_question_answering_search_service_key` can only be set when kind is set to `TextAnalytics`") + } + } if v, ok := d.GetOk("metrics_advisor_aad_client_id"); ok { if kind == "MetricsAdvisor" { props.AadClientId = utils.String(v.(string)) @@ -735,8 +749,8 @@ func flattenCognitiveAccountNetworkAcls(input *cognitiveservicesaccounts.Network } ipRules := make([]interface{}, 0) - if input.IpRules != nil { - for _, v := range *input.IpRules { + if input.IPRules != nil { + for _, v := range *input.IPRules { ipRules = append(ipRules, v.Value) } } diff --git a/internal/services/cognitive/cognitive_account_resource_test.go b/internal/services/cognitive/cognitive_account_resource_test.go index c91b3424c38e..9554d235cf48 100644 --- a/internal/services/cognitive/cognitive_account_resource_test.go +++ b/internal/services/cognitive/cognitive_account_resource_test.go @@ -193,21 +193,21 @@ func TestAccCognitiveAccount_customQuestionAnsweringSearchServiceId(t *testing.T check.That(data.ResourceName).ExistsInAzure(r), ), }, - data.ImportStep(), + data.ImportStep("custom_question_answering_search_service_key"), { Config: r.customQuestionAnsweringSearchServiceIdUpdated(data), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), ), }, - data.ImportStep(), + data.ImportStep("custom_question_answering_search_service_key"), { Config: r.customQuestionAnsweringSearchServiceIdRemoved(data), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), ), }, - data.ImportStep(), + data.ImportStep("custom_question_answering_search_service_key"), }) } @@ -639,14 +639,15 @@ resource "azurerm_search_service" "test" { } resource "azurerm_cognitive_account" "test" { - name = "acctestcogacc-%[1]d" - location = azurerm_resource_group.test.location - resource_group_name = azurerm_resource_group.test.name - kind = "TextAnalytics" - sku_name = "F0" - custom_question_answering_search_service_id = azurerm_search_service.test.id + name = "acctestcogacc-%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + kind = "TextAnalytics" + sku_name = "F0" + custom_question_answering_search_service_id = azurerm_search_service.test.id + custom_question_answering_search_service_key = azurerm_search_service.test.primary_key } -`, data.RandomInteger, data.Locations.Primary) +`, data.RandomInteger, "West US") } func (CognitiveAccountResource) customQuestionAnsweringSearchServiceIdUpdated(data acceptance.TestData) string { @@ -675,14 +676,15 @@ resource "azurerm_search_service" "test2" { } resource "azurerm_cognitive_account" "test" { - name = "acctestcogacc-%[1]d" - location = azurerm_resource_group.test.location - resource_group_name = azurerm_resource_group.test.name - kind = "TextAnalytics" - sku_name = "F0" - custom_question_answering_search_service_id = azurerm_search_service.test2.id + name = "acctestcogacc-%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + kind = "TextAnalytics" + sku_name = "F0" + custom_question_answering_search_service_id = azurerm_search_service.test2.id + custom_question_answering_search_service_key = azurerm_search_service.test2.primary_key } -`, data.RandomInteger, data.Locations.Primary) +`, data.RandomInteger, "West US") } func (CognitiveAccountResource) customQuestionAnsweringSearchServiceIdRemoved(data acceptance.TestData) string { @@ -717,7 +719,7 @@ resource "azurerm_cognitive_account" "test" { kind = "TextAnalytics" sku_name = "F0" } -`, data.RandomInteger, data.Locations.Primary) +`, data.RandomInteger, "West US") } func (CognitiveAccountResource) cognitiveServices(data acceptance.TestData) string { diff --git a/internal/services/compute/client/client.go b/internal/services/compute/client/client.go index ce3fe7323043..d3cf4358d2d0 100644 --- a/internal/services/compute/client/client.go +++ b/internal/services/compute/client/client.go @@ -4,6 +4,9 @@ import ( "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2021-11-01/compute" "github.com/Azure/azure-sdk-for-go/services/marketplaceordering/mgmt/2015-06-01/marketplaceordering" "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/availabilitysets" + "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhostgroups" + "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhosts" + "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/proximityplacementgroups" "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/sshpublickeys" "github.com/hashicorp/terraform-provider-azurerm/internal/common" ) @@ -12,8 +15,8 @@ type Client struct { AvailabilitySetsClient *availabilitysets.AvailabilitySetsClient CapacityReservationsClient *compute.CapacityReservationsClient CapacityReservationGroupsClient *compute.CapacityReservationGroupsClient - DedicatedHostsClient *compute.DedicatedHostsClient - DedicatedHostGroupsClient *compute.DedicatedHostGroupsClient + DedicatedHostsClient *dedicatedhosts.DedicatedHostsClient + DedicatedHostGroupsClient *dedicatedhostgroups.DedicatedHostGroupsClient DisksClient *compute.DisksClient DiskAccessClient *compute.DiskAccessesClient DiskEncryptionSetsClient *compute.DiskEncryptionSetsClient @@ -24,7 +27,7 @@ type Client struct { GalleryImageVersionsClient *compute.GalleryImageVersionsClient ImagesClient *compute.ImagesClient MarketplaceAgreementsClient *marketplaceordering.MarketplaceAgreementsClient - ProximityPlacementGroupsClient *compute.ProximityPlacementGroupsClient + ProximityPlacementGroupsClient *proximityplacementgroups.ProximityPlacementGroupsClient SSHPublicKeysClient *sshpublickeys.SshPublicKeysClient SnapshotsClient *compute.SnapshotsClient UsageClient *compute.UsageClient @@ -48,10 +51,10 @@ func NewClient(o *common.ClientOptions) *Client { capacityReservationGroupsClient := compute.NewCapacityReservationGroupsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&capacityReservationGroupsClient.Client, o.ResourceManagerAuthorizer) - dedicatedHostsClient := compute.NewDedicatedHostsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + dedicatedHostsClient := dedicatedhosts.NewDedicatedHostsClientWithBaseURI(o.ResourceManagerEndpoint) o.ConfigureClient(&dedicatedHostsClient.Client, o.ResourceManagerAuthorizer) - dedicatedHostGroupsClient := compute.NewDedicatedHostGroupsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + dedicatedHostGroupsClient := dedicatedhostgroups.NewDedicatedHostGroupsClientWithBaseURI(o.ResourceManagerEndpoint) o.ConfigureClient(&dedicatedHostGroupsClient.Client, o.ResourceManagerAuthorizer) disksClient := compute.NewDisksClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) @@ -84,7 +87,7 @@ func NewClient(o *common.ClientOptions) *Client { marketplaceAgreementsClient := marketplaceordering.NewMarketplaceAgreementsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&marketplaceAgreementsClient.Client, o.ResourceManagerAuthorizer) - proximityPlacementGroupsClient := compute.NewProximityPlacementGroupsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + proximityPlacementGroupsClient := proximityplacementgroups.NewProximityPlacementGroupsClientWithBaseURI(o.ResourceManagerEndpoint) o.ConfigureClient(&proximityPlacementGroupsClient.Client, o.ResourceManagerAuthorizer) snapshotsClient := compute.NewSnapshotsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) diff --git a/internal/services/compute/dedicated_host_data_source.go b/internal/services/compute/dedicated_host_data_source.go index 6b2f2ff5c865..04b8ec950f04 100644 --- a/internal/services/compute/dedicated_host_data_source.go +++ b/internal/services/compute/dedicated_host_data_source.go @@ -4,15 +4,15 @@ import ( "fmt" "time" + "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhosts" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/compute/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/compute/validate" - "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" - "github.com/hashicorp/terraform-provider-azurerm/utils" ) func dataSourceDedicatedHost() *pluginsdk.Resource { @@ -40,7 +40,7 @@ func dataSourceDedicatedHost() *pluginsdk.Resource { "location": commonschema.LocationComputed(), - "tags": tags.SchemaDataSource(), + "tags": commonschema.TagsDataSource(), }, } } @@ -51,22 +51,29 @@ func dataSourceDedicatedHostRead(d *pluginsdk.ResourceData, meta interface{}) er ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id := parse.NewDedicatedHostID(subscriptionId, d.Get("resource_group_name").(string), d.Get("dedicated_host_group_name").(string), d.Get("name").(string)) + id := dedicatedhosts.NewHostID(subscriptionId, d.Get("resource_group_name").(string), d.Get("dedicated_host_group_name").(string), d.Get("name").(string)) - resp, err := client.Get(ctx, id.ResourceGroup, id.HostGroupName, id.HostName, "") + resp, err := client.Get(ctx, id, dedicatedhosts.DefaultGetOperationOptions()) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { return fmt.Errorf("%s was not found", id) } + return fmt.Errorf("reading %s: %+v", id, err) } d.SetId(id.ID()) d.Set("name", id.HostName) - d.Set("resource_group_name", id.ResourceGroup) + d.Set("resource_group_name", id.ResourceGroupName) d.Set("dedicated_host_group_name", id.HostGroupName) - d.Set("location", location.NormalizeNilable(resp.Location)) + if model := resp.Model; model != nil { + d.Set("location", location.Normalize(model.Location)) + + if err := tags.FlattenAndSet(d, model.Tags); err != nil { + return err + } + } - return tags.FlattenAndSet(d, resp.Tags) + return nil } diff --git a/internal/services/compute/dedicated_host_group_data_source.go b/internal/services/compute/dedicated_host_group_data_source.go index 322429c23bf0..0446ea8c1a9f 100644 --- a/internal/services/compute/dedicated_host_group_data_source.go +++ b/internal/services/compute/dedicated_host_group_data_source.go @@ -5,16 +5,16 @@ import ( "regexp" "time" + "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" "github.com/hashicorp/go-azure-helpers/resourcemanager/zones" + "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhostgroups" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/compute/parse" - "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" - "github.com/hashicorp/terraform-provider-azurerm/utils" ) func dataSourceDedicatedHostGroup() *pluginsdk.Resource { @@ -59,10 +59,10 @@ func dataSourceDedicatedHostGroupRead(d *pluginsdk.ResourceData, meta interface{ ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id := parse.NewDedicatedHostGroupID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) - resp, err := client.Get(ctx, id.ResourceGroup, id.HostGroupName, "") + id := dedicatedhostgroups.NewHostGroupID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) + resp, err := client.Get(ctx, id, dedicatedhostgroups.DefaultGetOperationOptions()) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { return fmt.Errorf("%s was not found", id) } return fmt.Errorf("reading %s: %+v", id, err) @@ -71,20 +71,21 @@ func dataSourceDedicatedHostGroupRead(d *pluginsdk.ResourceData, meta interface{ d.SetId(id.ID()) d.Set("name", id.HostGroupName) - d.Set("resource_group_name", id.ResourceGroup) + d.Set("resource_group_name", id.ResourceGroupName) - d.Set("location", location.NormalizeNilable(resp.Location)) - d.Set("zones", zones.Flatten(resp.Zones)) + if model := resp.Model; model != nil { + d.Set("location", location.Normalize(model.Location)) + d.Set("zones", zones.Flatten(model.Zones)) - if props := resp.DedicatedHostGroupProperties; props != nil { - d.Set("automatic_placement_enabled", props.SupportAutomaticPlacement) + if props := model.Properties; props != nil { + d.Set("automatic_placement_enabled", props.SupportAutomaticPlacement) + d.Set("platform_fault_domain_count", props.PlatformFaultDomainCount) + } - platformFaultDomainCount := 0 - if props.PlatformFaultDomainCount != nil { - platformFaultDomainCount = int(*props.PlatformFaultDomainCount) + if err := tags.FlattenAndSet(d, model.Tags); err != nil { + return err } - d.Set("platform_fault_domain_count", platformFaultDomainCount) } - return tags.FlattenAndSet(d, resp.Tags) + return nil } diff --git a/internal/services/compute/dedicated_host_group_resource.go b/internal/services/compute/dedicated_host_group_resource.go index 06de97bed5f0..f8eba877674f 100644 --- a/internal/services/compute/dedicated_host_group_resource.go +++ b/internal/services/compute/dedicated_host_group_resource.go @@ -5,15 +5,14 @@ import ( "log" "time" - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2021-11-01/compute" + "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" - "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhostgroups" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/compute/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/compute/validate" - "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" @@ -28,7 +27,7 @@ func resourceDedicatedHostGroup() *pluginsdk.Resource { Delete: resourceDedicatedHostGroupDelete, Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - _, err := parse.HostGroupID(id) + _, err := dedicatedhostgroups.ParseHostGroupID(id) return err }), @@ -47,11 +46,9 @@ func resourceDedicatedHostGroup() *pluginsdk.Resource { ValidateFunc: validate.DedicatedHostGroupName(), }, - "location": azure.SchemaLocation(), + "resource_group_name": commonschema.ResourceGroupName(), - // There's a bug in the Azure API where this is returned in upper-case - // BUG: https://github.com/Azure/azure-rest-api-specs/issues/8068 - "resource_group_name": azure.SchemaResourceGroupNameDiffSuppress(), + "location": commonschema.Location(), "platform_fault_domain_count": { Type: pluginsdk.TypeInt, @@ -68,7 +65,7 @@ func resourceDedicatedHostGroup() *pluginsdk.Resource { }, "zone": commonschema.ZoneSingleOptionalForceNew(), - "tags": tags.Schema(), + "tags": commonschema.Tags(), }, } } @@ -79,48 +76,45 @@ func resourceDedicatedHostGroupCreate(d *pluginsdk.ResourceData, meta interface{ ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) defer cancel() - id := parse.NewHostGroupID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) - + id := dedicatedhostgroups.NewHostGroupID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) if d.IsNewResource() { - existing, err := client.Get(ctx, id.ResourceGroup, id.Name, "") + existing, err := client.Get(ctx, id, dedicatedhostgroups.DefaultGetOperationOptions()) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return fmt.Errorf("checking for presence of %s: %+v", id, err) } } - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return tf.ImportAsExistsError("azurerm_dedicated_host_group", id.ID()) } } - location := azure.NormalizeLocation(d.Get("location").(string)) platformFaultDomainCount := d.Get("platform_fault_domain_count").(int) t := d.Get("tags").(map[string]interface{}) - parameters := compute.DedicatedHostGroup{ - Location: utils.String(location), - DedicatedHostGroupProperties: &compute.DedicatedHostGroupProperties{ - PlatformFaultDomainCount: utils.Int32(int32(platformFaultDomainCount)), + payload := dedicatedhostgroups.DedicatedHostGroup{ + Location: location.Normalize(d.Get("location").(string)), + Properties: &dedicatedhostgroups.DedicatedHostGroupProperties{ + PlatformFaultDomainCount: int64(platformFaultDomainCount), }, Tags: tags.Expand(t), } if zone, ok := d.GetOk("zone"); ok { - parameters.Zones = &[]string{ + payload.Zones = &[]string{ zone.(string), } } if v, ok := d.GetOk("automatic_placement_enabled"); ok { - parameters.DedicatedHostGroupProperties.SupportAutomaticPlacement = utils.Bool(v.(bool)) + payload.Properties.SupportAutomaticPlacement = utils.Bool(v.(bool)) } - if _, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.Name, parameters); err != nil { + if _, err := client.CreateOrUpdate(ctx, id, payload); err != nil { return fmt.Errorf("creating %s: %+v", id, err) } d.SetId(id.ID()) - return resourceDedicatedHostGroupRead(d, meta) } @@ -129,44 +123,45 @@ func resourceDedicatedHostGroupRead(d *pluginsdk.ResourceData, meta interface{}) ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.HostGroupID(d.Id()) + id, err := dedicatedhostgroups.ParseHostGroupID(d.Id()) if err != nil { return err } - resp, err := client.Get(ctx, id.ResourceGroup, id.Name, "") + resp, err := client.Get(ctx, *id, dedicatedhostgroups.DefaultGetOperationOptions()) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { - log.Printf("[INFO] Dedicated Host Group %q does not exist - removing from state", d.Id()) + if response.WasNotFound(resp.HttpResponse) { + log.Printf("[INFO] %q was not found - removing from state", *id) d.SetId("") return nil } - return fmt.Errorf("reading Dedicated Host Group %q (: %+v", id.String(), err) + return fmt.Errorf("retrieving %s: %+v", *id, err) } - d.Set("name", id.Name) - d.Set("resource_group_name", id.ResourceGroup) + d.Set("name", id.HostGroupName) + d.Set("resource_group_name", id.ResourceGroupName) - d.Set("location", location.NormalizeNilable(resp.Location)) + if model := resp.Model; model != nil { + d.Set("location", location.Normalize(model.Location)) - zone := "" - if resp.Zones != nil && len(*resp.Zones) > 0 { - z := *resp.Zones - zone = z[0] - } - d.Set("zone", zone) + zone := "" + if model.Zones != nil && len(*model.Zones) > 0 { + z := *model.Zones + zone = z[0] + } + d.Set("zone", zone) - if props := resp.DedicatedHostGroupProperties; props != nil { - platformFaultDomainCount := 0 - if props.PlatformFaultDomainCount != nil { - platformFaultDomainCount = int(*props.PlatformFaultDomainCount) + if props := model.Properties; props != nil { + d.Set("platform_fault_domain_count", props.PlatformFaultDomainCount) + d.Set("automatic_placement_enabled", props.SupportAutomaticPlacement) } - d.Set("platform_fault_domain_count", platformFaultDomainCount) - d.Set("automatic_placement_enabled", props.SupportAutomaticPlacement) + if err := tags.FlattenAndSet(d, model.Tags); err != nil { + return err + } } - return tags.FlattenAndSet(d, resp.Tags) + return nil } func resourceDedicatedHostGroupUpdate(d *pluginsdk.ResourceData, meta interface{}) error { @@ -174,16 +169,17 @@ func resourceDedicatedHostGroupUpdate(d *pluginsdk.ResourceData, meta interface{ ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - name := d.Get("name").(string) - resourceGroupName := d.Get("resource_group_name").(string) - t := d.Get("tags").(map[string]interface{}) + id, err := dedicatedhostgroups.ParseHostGroupID(d.Id()) + if err != nil { + return err + } - parameters := compute.DedicatedHostGroupUpdate{ - Tags: tags.Expand(t), + payload := dedicatedhostgroups.DedicatedHostGroupUpdate{ + Tags: tags.Expand(d.Get("tags").(map[string]interface{})), } - if _, err := client.Update(ctx, resourceGroupName, name, parameters); err != nil { - return fmt.Errorf("updating Dedicated Host Group %q (Resource Group %q): %+v", name, resourceGroupName, err) + if _, err := client.Update(ctx, *id, payload); err != nil { + return fmt.Errorf("updating %s: %+v", *id, err) } return resourceDedicatedHostGroupRead(d, meta) @@ -194,13 +190,13 @@ func resourceDedicatedHostGroupDelete(d *pluginsdk.ResourceData, meta interface{ ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.HostGroupID(d.Id()) + id, err := dedicatedhostgroups.ParseHostGroupID(d.Id()) if err != nil { return err } - if _, err := client.Delete(ctx, id.ResourceGroup, id.Name); err != nil { - return fmt.Errorf("deleting Dedicated Host Group %q : %+v", id.String(), err) + if _, err := client.Delete(ctx, *id); err != nil { + return fmt.Errorf("deleting %s: %+v", *id, err) } return nil diff --git a/internal/services/compute/dedicated_host_group_resource_test.go b/internal/services/compute/dedicated_host_group_resource_test.go index 1abe0a0aac07..0fac0d29f4ed 100644 --- a/internal/services/compute/dedicated_host_group_resource_test.go +++ b/internal/services/compute/dedicated_host_group_resource_test.go @@ -5,10 +5,11 @@ import ( "fmt" "testing" + "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhostgroups" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/compute/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -78,17 +79,17 @@ func TestAccDedicatedHostGroup_complete(t *testing.T) { } func (r DedicatedHostGroupResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.HostGroupID(state.ID) + id, err := dedicatedhostgroups.ParseHostGroupID(state.ID) if err != nil { return nil, err } - resp, err := clients.Compute.DedicatedHostGroupsClient.Get(ctx, id.ResourceGroup, id.Name, "") + resp, err := clients.Compute.DedicatedHostGroupsClient.Get(ctx, *id, dedicatedhostgroups.DefaultGetOperationOptions()) if err != nil { return nil, fmt.Errorf("retrieving Compute Dedicated Host Group %q", id) } - return utils.Bool(resp.ID != nil), nil + return utils.Bool(resp.Model != nil), nil } func (DedicatedHostGroupResource) basic(data acceptance.TestData) string { diff --git a/internal/services/compute/dedicated_host_resource.go b/internal/services/compute/dedicated_host_resource.go index 41dc03fec72a..2dc6307bf4d9 100644 --- a/internal/services/compute/dedicated_host_resource.go +++ b/internal/services/compute/dedicated_host_resource.go @@ -6,14 +6,15 @@ import ( "log" "time" - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2021-11-01/compute" "github.com/hashicorp/go-azure-helpers/lang/response" - "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhostgroups" + "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhosts" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/compute/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/compute/validate" - "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" @@ -28,7 +29,7 @@ func resourceDedicatedHost() *pluginsdk.Resource { Delete: resourceDedicatedHostDelete, Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - _, err := parse.DedicatedHostID(id) + _, err := dedicatedhosts.ParseHostID(id) return err }), @@ -47,15 +48,15 @@ func resourceDedicatedHost() *pluginsdk.Resource { ValidateFunc: validate.DedicatedHostName(), }, - "location": azure.SchemaLocation(), - "dedicated_host_group_id": { Type: pluginsdk.TypeString, Required: true, ForceNew: true, - ValidateFunc: validate.DedicatedHostGroupID, + ValidateFunc: dedicatedhostgroups.ValidateHostGroupID, }, + "location": commonschema.Location(), + "sku_name": { Type: pluginsdk.TypeString, ForceNew: true, @@ -124,14 +125,15 @@ func resourceDedicatedHost() *pluginsdk.Resource { Type: pluginsdk.TypeString, Optional: true, ValidateFunc: validation.StringInSlice([]string{ - string(compute.DedicatedHostLicenseTypesNone), - string(compute.DedicatedHostLicenseTypesWindowsServerHybrid), - string(compute.DedicatedHostLicenseTypesWindowsServerPerpetual), + // TODO: remove `None` in 4.0 in favour of this field being set to an empty string (since it's optional) + string(dedicatedhosts.DedicatedHostLicenseTypesNone), + string(dedicatedhosts.DedicatedHostLicenseTypesWindowsServerHybrid), + string(dedicatedhosts.DedicatedHostLicenseTypesWindowsServerPerpetual), }, false), - Default: string(compute.DedicatedHostLicenseTypesNone), + Default: string(dedicatedhosts.DedicatedHostLicenseTypesNone), }, - "tags": tags.Schema(), + "tags": commonschema.Tags(), }, } } @@ -141,102 +143,90 @@ func resourceDedicatedHostCreate(d *pluginsdk.ResourceData, meta interface{}) er ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) defer cancel() - hostGroupId, err := parse.DedicatedHostGroupID(d.Get("dedicated_host_group_id").(string)) + hostGroupId, err := dedicatedhostgroups.ParseHostGroupID(d.Get("dedicated_host_group_id").(string)) if err != nil { return err } - id := parse.NewDedicatedHostID(hostGroupId.SubscriptionId, hostGroupId.ResourceGroup, hostGroupId.HostGroupName, d.Get("name").(string)) + id := dedicatedhosts.NewHostID(hostGroupId.SubscriptionId, hostGroupId.ResourceGroupName, hostGroupId.HostGroupName, d.Get("name").(string)) if d.IsNewResource() { - existing, err := client.Get(ctx, id.ResourceGroup, id.HostGroupName, id.HostName, "") + existing, err := client.Get(ctx, id, dedicatedhosts.DefaultGetOperationOptions()) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return fmt.Errorf("checking for presence of existing %s: %+v", id, err) } } - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return tf.ImportAsExistsError("azurerm_dedicated_host", id.ID()) } } - parameters := compute.DedicatedHost{ - Location: utils.String(azure.NormalizeLocation(d.Get("location").(string))), - DedicatedHostProperties: &compute.DedicatedHostProperties{ + licenseType := dedicatedhosts.DedicatedHostLicenseTypes(d.Get("license_type").(string)) + payload := dedicatedhosts.DedicatedHost{ + Location: location.Normalize(d.Get("location").(string)), + Properties: &dedicatedhosts.DedicatedHostProperties{ AutoReplaceOnFailure: utils.Bool(d.Get("auto_replace_on_failure").(bool)), - LicenseType: compute.DedicatedHostLicenseTypes(d.Get("license_type").(string)), - PlatformFaultDomain: utils.Int32(int32(d.Get("platform_fault_domain").(int))), + LicenseType: &licenseType, + PlatformFaultDomain: utils.Int64(int64(d.Get("platform_fault_domain").(int))), }, - Sku: &compute.Sku{ + Sku: dedicatedhosts.Sku{ Name: utils.String(d.Get("sku_name").(string)), }, Tags: tags.Expand(d.Get("tags").(map[string]interface{})), } - future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.HostGroupName, id.HostName, parameters) - if err != nil { + if err := client.CreateOrUpdateThenPoll(ctx, id, payload); err != nil { return fmt.Errorf("creating %s: %+v", id, err) } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for creation of %s: %+v", id, err) - } d.SetId(id.ID()) return resourceDedicatedHostRead(d, meta) } func resourceDedicatedHostRead(d *pluginsdk.ResourceData, meta interface{}) error { - groupsClient := meta.(*clients.Client).Compute.DedicatedHostGroupsClient hostsClient := meta.(*clients.Client).Compute.DedicatedHostsClient ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.DedicatedHostID(d.Id()) + id, err := dedicatedhosts.ParseHostID(d.Id()) if err != nil { return err } - hostGroupId := parse.NewDedicatedHostGroupID(id.SubscriptionId, id.ResourceGroup, id.HostGroupName) - group, err := groupsClient.Get(ctx, hostGroupId.ResourceGroup, hostGroupId.HostGroupName, "") + resp, err := hostsClient.Get(ctx, *id, dedicatedhosts.DefaultGetOperationOptions()) if err != nil { - if utils.ResponseWasNotFound(group.Response) { - log.Printf("[INFO] Parent %s does not exist - removing from state", hostGroupId) + if response.WasNotFound(resp.HttpResponse) { + log.Printf("[INFO] %s was not found - removing from state", *id) d.SetId("") return nil } - return fmt.Errorf("retrieving %s: %+v", hostGroupId, err) - } - - resp, err := hostsClient.Get(ctx, id.ResourceGroup, id.HostGroupName, id.HostName, "") - if err != nil { - if utils.ResponseWasNotFound(resp.Response) { - log.Printf("[INFO] Dedicated Host %q does not exist - removing from state", d.Id()) - d.SetId("") - return nil - } - - return fmt.Errorf("retrieving Dedicated Host %q (Host Group Name %q / Resource Group %q): %+v", id.HostName, id.HostGroupName, id.ResourceGroup, err) + return fmt.Errorf("retrieving %s: %+v", *id, err) } d.Set("name", id.HostName) - d.Set("dedicated_host_group_id", hostGroupId.ID()) + d.Set("dedicated_host_group_id", dedicatedhostgroups.NewHostGroupID(id.SubscriptionId, id.ResourceGroupName, id.HostGroupName).ID()) + + if model := resp.Model; model != nil { + d.Set("location", location.Normalize(model.Location)) + d.Set("sku_name", model.Sku.Name) + if props := model.Properties; props != nil { + d.Set("auto_replace_on_failure", props.AutoReplaceOnFailure) + d.Set("license_type", props.LicenseType) + + platformFaultDomain := 0 + if props.PlatformFaultDomain != nil { + platformFaultDomain = int(*props.PlatformFaultDomain) + } + d.Set("platform_fault_domain", platformFaultDomain) + } - if location := resp.Location; location != nil { - d.Set("location", azure.NormalizeLocation(*location)) - } - d.Set("sku_name", resp.Sku.Name) - if props := resp.DedicatedHostProperties; props != nil { - d.Set("auto_replace_on_failure", props.AutoReplaceOnFailure) - d.Set("license_type", props.LicenseType) - - platformFaultDomain := 0 - if props.PlatformFaultDomain != nil { - platformFaultDomain = int(*props.PlatformFaultDomain) + if err := tags.FlattenAndSet(d, model.Tags); err != nil { + return err } - d.Set("platform_fault_domain", platformFaultDomain) } - return tags.FlattenAndSet(d, resp.Tags) + return nil } func resourceDedicatedHostUpdate(d *pluginsdk.ResourceData, meta interface{}) error { @@ -244,25 +234,30 @@ func resourceDedicatedHostUpdate(d *pluginsdk.ResourceData, meta interface{}) er ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.DedicatedHostID(d.Id()) + id, err := dedicatedhosts.ParseHostID(d.Id()) if err != nil { return err } - parameters := compute.DedicatedHostUpdate{ - DedicatedHostProperties: &compute.DedicatedHostProperties{ - AutoReplaceOnFailure: utils.Bool(d.Get("auto_replace_on_failure").(bool)), - LicenseType: compute.DedicatedHostLicenseTypes(d.Get("license_type").(string)), - }, - Tags: tags.Expand(d.Get("tags").(map[string]interface{})), + payload := dedicatedhosts.DedicatedHostUpdate{} + + if d.HasChanges("auto_replace_on_failure", "license_type") { + payload.Properties = &dedicatedhosts.DedicatedHostProperties{} + if d.HasChange("auto_replace_on_failure") { + payload.Properties.AutoReplaceOnFailure = utils.Bool(d.Get("auto_replace_on_failure").(bool)) + } + if d.HasChange("license_type") { + licenseType := dedicatedhosts.DedicatedHostLicenseTypes(d.Get("license_type").(string)) + payload.Properties.LicenseType = &licenseType + } } - future, err := client.Update(ctx, id.ResourceGroup, id.HostGroupName, id.HostName, parameters) - if err != nil { - return fmt.Errorf("updating %s: %+v", *id, err) + if d.HasChange("tags") { + payload.Tags = tags.Expand(d.Get("tags").(map[string]interface{})) } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for update of %s: %+v", *id, err) + + if err := client.UpdateThenPoll(ctx, *id, payload); err != nil { + return fmt.Errorf("updating %s: %+v", *id, err) } return resourceDedicatedHostRead(d, meta) @@ -273,22 +268,15 @@ func resourceDedicatedHostDelete(d *pluginsdk.ResourceData, meta interface{}) er ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.DedicatedHostID(d.Id()) + id, err := dedicatedhosts.ParseHostID(d.Id()) if err != nil { return err } - future, err := client.Delete(ctx, id.ResourceGroup, id.HostGroupName, id.HostName) - if err != nil { + if err := client.DeleteThenPoll(ctx, *id); err != nil { return fmt.Errorf("deleting %s: %+v", *id, err) } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - if !response.WasNotFound(future.Response()) { - return fmt.Errorf("waiting for deletion of %s: %+v", *id, err) - } - } - // API has bug, which appears to be eventually consistent. Tracked by this issue: https://github.com/Azure/azure-rest-api-specs/issues/8137 log.Printf("[DEBUG] Waiting for %s to be fully deleted..", *id) stateConf := &pluginsdk.StateChangeConf{ @@ -307,11 +295,11 @@ func resourceDedicatedHostDelete(d *pluginsdk.ResourceData, meta interface{}) er return nil } -func dedicatedHostDeletedRefreshFunc(ctx context.Context, client *compute.DedicatedHostsClient, id parse.DedicatedHostId) pluginsdk.StateRefreshFunc { +func dedicatedHostDeletedRefreshFunc(ctx context.Context, client *dedicatedhosts.DedicatedHostsClient, id dedicatedhosts.HostId) pluginsdk.StateRefreshFunc { return func() (interface{}, string, error) { - res, err := client.Get(ctx, id.ResourceGroup, id.HostGroupName, id.HostName, "") + res, err := client.Get(ctx, id, dedicatedhosts.DefaultGetOperationOptions()) if err != nil { - if utils.ResponseWasNotFound(res.Response) { + if response.WasNotFound(res.HttpResponse) { return "NotFound", "NotFound", nil } diff --git a/internal/services/compute/dedicated_host_resource_test.go b/internal/services/compute/dedicated_host_resource_test.go index ddc6d6b2f091..09b33e7e0a84 100644 --- a/internal/services/compute/dedicated_host_resource_test.go +++ b/internal/services/compute/dedicated_host_resource_test.go @@ -5,10 +5,11 @@ import ( "fmt" "testing" + "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhosts" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/compute/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -166,17 +167,17 @@ func TestAccDedicatedHost_requiresImport(t *testing.T) { } func (t DedicatedHostResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.DedicatedHostID(state.ID) + id, err := dedicatedhosts.ParseHostID(state.ID) if err != nil { return nil, err } - resp, err := clients.Compute.DedicatedHostsClient.Get(ctx, id.ResourceGroup, id.HostGroupName, id.HostName, "") + resp, err := clients.Compute.DedicatedHostsClient.Get(ctx, *id, dedicatedhosts.DefaultGetOperationOptions()) if err != nil { return nil, fmt.Errorf("retrieving Compute Dedicated Host %q", id.String()) } - return utils.Bool(resp.ID != nil), nil + return utils.Bool(resp.Model != nil), nil } func (r DedicatedHostResource) basic(data acceptance.TestData) string { diff --git a/internal/services/compute/disk_encryption_set_resource.go b/internal/services/compute/disk_encryption_set_resource.go index 8c6adc8be552..588ce5929550 100644 --- a/internal/services/compute/disk_encryption_set_resource.go +++ b/internal/services/compute/disk_encryption_set_resource.go @@ -114,11 +114,14 @@ func resourceDiskEncryptionSetCreate(d *pluginsdk.ResourceData, meta interface{} if err != nil { return fmt.Errorf("validating Key Vault Key %q for Disk Encryption Set: %+v", keyVaultKeyId, err) } - if !keyVaultDetails.softDeleteEnabled { - return fmt.Errorf("validating Key Vault %q (Resource Group %q) for Disk Encryption Set: Soft Delete must be enabled but it isn't!", keyVaultDetails.keyVaultName, keyVaultDetails.resourceGroupName) - } - if !keyVaultDetails.purgeProtectionEnabled { - return fmt.Errorf("validating Key Vault %q (Resource Group %q) for Disk Encryption Set: Purge Protection must be enabled but it isn't!", keyVaultDetails.keyVaultName, keyVaultDetails.resourceGroupName) + + if keyVaultDetails != nil { + if !keyVaultDetails.softDeleteEnabled { + return fmt.Errorf("validating Key Vault %q (Resource Group %q) for Disk Encryption Set: Soft Delete must be enabled but it isn't!", keyVaultDetails.keyVaultName, keyVaultDetails.resourceGroupName) + } + if !keyVaultDetails.purgeProtectionEnabled { + return fmt.Errorf("validating Key Vault %q (Resource Group %q) for Disk Encryption Set: Purge Protection must be enabled but it isn't!", keyVaultDetails.keyVaultName, keyVaultDetails.resourceGroupName) + } } location := azure.NormalizeLocation(d.Get("location").(string)) @@ -136,9 +139,6 @@ func resourceDiskEncryptionSetCreate(d *pluginsdk.ResourceData, meta interface{} EncryptionSetProperties: &compute.EncryptionSetProperties{ ActiveKey: &compute.KeyForDiskEncryptionSet{ KeyURL: utils.String(keyVaultKeyId), - SourceVault: &compute.SourceVault{ - ID: utils.String(keyVaultDetails.keyVaultId), - }, }, RotationToLatestKeyVersionEnabled: utils.Bool(rotationToLatestKeyVersionEnabled), EncryptionType: compute.DiskEncryptionSetType(encryptionType), @@ -147,6 +147,12 @@ func resourceDiskEncryptionSetCreate(d *pluginsdk.ResourceData, meta interface{} Tags: tags.Expand(t), } + if keyVaultDetails != nil { + params.EncryptionSetProperties.ActiveKey.SourceVault = &compute.SourceVault{ + ID: utils.String(keyVaultDetails.keyVaultId), + } + } + future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.Name, params) if err != nil { return fmt.Errorf("creating %s: %+v", id, err) @@ -231,20 +237,27 @@ func resourceDiskEncryptionSetUpdate(d *pluginsdk.ResourceData, meta interface{} if err != nil { return fmt.Errorf("validating Key Vault Key %q for Disk Encryption Set: %+v", keyVaultKeyId, err) } - if !keyVaultDetails.softDeleteEnabled { - return fmt.Errorf("validating Key Vault %q (Resource Group %q) for Disk Encryption Set: Soft Delete must be enabled but it isn't!", keyVaultDetails.keyVaultName, keyVaultDetails.resourceGroupName) - } - if !keyVaultDetails.purgeProtectionEnabled { - return fmt.Errorf("validating Key Vault %q (Resource Group %q) for Disk Encryption Set: Purge Protection must be enabled but it isn't!", keyVaultDetails.keyVaultName, keyVaultDetails.resourceGroupName) + + if keyVaultDetails != nil { + if !keyVaultDetails.softDeleteEnabled { + return fmt.Errorf("validating Key Vault %q (Resource Group %q) for Disk Encryption Set: Soft Delete must be enabled but it isn't!", keyVaultDetails.keyVaultName, keyVaultDetails.resourceGroupName) + } + if !keyVaultDetails.purgeProtectionEnabled { + return fmt.Errorf("validating Key Vault %q (Resource Group %q) for Disk Encryption Set: Purge Protection must be enabled but it isn't!", keyVaultDetails.keyVaultName, keyVaultDetails.resourceGroupName) + } } + update.DiskEncryptionSetUpdateProperties = &compute.DiskEncryptionSetUpdateProperties{ ActiveKey: &compute.KeyForDiskEncryptionSet{ KeyURL: utils.String(keyVaultKeyId), - SourceVault: &compute.SourceVault{ - ID: utils.String(keyVaultDetails.keyVaultId), - }, }, } + + if keyVaultDetails != nil { + update.DiskEncryptionSetUpdateProperties.ActiveKey.SourceVault = &compute.SourceVault{ + ID: utils.String(keyVaultDetails.keyVaultId), + } + } } if d.HasChange("auto_key_rotation_enabled") { @@ -335,7 +348,7 @@ func diskEncryptionSetRetrieveKeyVault(ctx context.Context, keyVaultsClient *cli return nil, fmt.Errorf("retrieving the Resource ID the Key Vault at URL %q: %s", keyVaultKeyId.KeyVaultBaseUrl, err) } if keyVaultID == nil { - return nil, fmt.Errorf("Unable to determine the Resource ID for the Key Vault at URL %q", keyVaultKeyId.KeyVaultBaseUrl) + return nil, nil } parsedKeyVaultID, err := keyVaultParse.VaultID(*keyVaultID) diff --git a/internal/services/compute/images_data_source.go b/internal/services/compute/images_data_source.go index 89c211e6084e..9c3a022519fc 100644 --- a/internal/services/compute/images_data_source.go +++ b/internal/services/compute/images_data_source.go @@ -3,6 +3,7 @@ package compute import ( "context" "fmt" + "sort" "time" "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2021-11-01/compute" @@ -139,7 +140,23 @@ func dataSourceImagesRead(d *pluginsdk.ResourceData, meta interface{}) error { return fmt.Errorf("no images were found that match the specified tags") } - d.SetId(time.Now().UTC().String()) + tagsId := "" + tagKeys := make([]string, 0, len(filterTags)) + for key := range filterTags { + tagKeys = append(tagKeys, key) + } + sort.Strings(tagKeys) + for _, key := range tagKeys { + value := "" + if v, ok := filterTags[key]; ok && v != nil { + value = *v + } + tagsId += fmt.Sprintf("[%s:%s]", key, value) + } + if tagsId == "" { + tagsId = "[]" + } + d.SetId(fmt.Sprintf("resourceGroups/%s/tags/%s/images", resourceGroup, tagsId)) d.Set("resource_group_name", resourceGroup) diff --git a/internal/services/compute/linux_virtual_machine_resource.go b/internal/services/compute/linux_virtual_machine_resource.go index 6a48829f4380..6fb2e691f435 100644 --- a/internal/services/compute/linux_virtual_machine_resource.go +++ b/internal/services/compute/linux_virtual_machine_resource.go @@ -12,6 +12,9 @@ import ( "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/availabilitysets" + "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhostgroups" + "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhosts" + "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/proximityplacementgroups" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" azValidate "github.com/hashicorp/terraform-provider-azurerm/helpers/validate" @@ -150,7 +153,7 @@ func resourceLinuxVirtualMachine() *pluginsdk.Resource { "dedicated_host_id": { Type: pluginsdk.TypeString, Optional: true, - ValidateFunc: computeValidate.DedicatedHostID, + ValidateFunc: dedicatedhosts.ValidateHostID, // the Compute/VM API is broken and returns the Resource Group name in UPPERCASE :shrug: // tracked by https://github.com/Azure/azure-rest-api-specs/issues/19424 DiffSuppressFunc: suppress.CaseDifference, @@ -162,7 +165,7 @@ func resourceLinuxVirtualMachine() *pluginsdk.Resource { "dedicated_host_group_id": { Type: pluginsdk.TypeString, Optional: true, - ValidateFunc: computeValidate.DedicatedHostGroupID, + ValidateFunc: dedicatedhostgroups.ValidateHostGroupID, // the Compute/VM API is broken and returns the Resource Group name in UPPERCASE // tracked by https://github.com/Azure/azure-rest-api-specs/issues/19424 DiffSuppressFunc: suppress.CaseDifference, @@ -191,8 +194,8 @@ func resourceLinuxVirtualMachine() *pluginsdk.Resource { Optional: true, ForceNew: true, ValidateFunc: validation.StringInSlice([]string{ - // NOTE: whilst Delete is an option here, it's only applicable for VMSS string(compute.VirtualMachineEvictionPolicyTypesDeallocate), + string(compute.VirtualMachineEvictionPolicyTypesDelete), }, false), }, @@ -254,7 +257,7 @@ func resourceLinuxVirtualMachine() *pluginsdk.Resource { "proximity_placement_group_id": { Type: pluginsdk.TypeString, Optional: true, - ValidateFunc: computeValidate.ProximityPlacementGroupID, + ValidateFunc: proximityplacementgroups.ValidateProximityPlacementGroupID, // the Compute/VM API is broken and returns the Resource Group name in UPPERCASE :shrug: // tracked by https://github.com/Azure/azure-rest-api-specs/issues/19424 DiffSuppressFunc: suppress.CaseDifference, diff --git a/internal/services/compute/linux_virtual_machine_resource_disk_os_test.go b/internal/services/compute/linux_virtual_machine_resource_disk_os_test.go index 185a41ceffef..ccfbc0940ef5 100644 --- a/internal/services/compute/linux_virtual_machine_resource_disk_os_test.go +++ b/internal/services/compute/linux_virtual_machine_resource_disk_os_test.go @@ -156,6 +156,21 @@ func TestAccLinuxVirtualMachine_diskOSEphemeralDefault(t *testing.T) { }) } +func TestAccLinuxVirtualMachine_diskOSDiskEphemeralSpot(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_linux_virtual_machine", "test") + r := LinuxVirtualMachineResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.diskOSEphemeralSpot(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("admin_password"), + }) +} + func TestAccLinuxVirtualMachine_diskOSEphemeralResourceDisk(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_linux_virtual_machine", "test") r := LinuxVirtualMachineResource{} @@ -738,6 +753,46 @@ resource "azurerm_linux_virtual_machine" "test" { `, r.template(data), data.RandomInteger) } +func (r LinuxVirtualMachineResource) diskOSEphemeralSpot(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_linux_virtual_machine" "test" { + name = "acctestVM-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + size = "Standard_F2s_v2" + admin_username = "adminuser" + priority = "Spot" + eviction_policy = "Delete" + network_interface_ids = [ + azurerm_network_interface.test.id, + ] + + admin_ssh_key { + username = "adminuser" + public_key = local.first_public_key + } + + os_disk { + caching = "ReadOnly" + storage_account_type = "Standard_LRS" + + diff_disk_settings { + option = "Local" + } + } + + source_image_reference { + publisher = "Canonical" + offer = "UbuntuServer" + sku = "16.04-LTS" + version = "latest" + } +} +`, r.template(data), data.RandomInteger) +} + func (r LinuxVirtualMachineResource) diskOSEphemeralResourceDisk(data acceptance.TestData) string { return fmt.Sprintf(` %s diff --git a/internal/services/compute/linux_virtual_machine_scale_set_identity_resource_test.go b/internal/services/compute/linux_virtual_machine_scale_set_identity_resource_test.go index 574773a9148f..e7fa989da250 100644 --- a/internal/services/compute/linux_virtual_machine_scale_set_identity_resource_test.go +++ b/internal/services/compute/linux_virtual_machine_scale_set_identity_resource_test.go @@ -141,6 +141,7 @@ resource "azurerm_linux_virtual_machine_scale_set" "test" { instances = 1 admin_username = "adminuser" admin_password = "P@ssword1234!" + overprovision = false disable_password_authentication = false diff --git a/internal/services/compute/linux_virtual_machine_scale_set_resource.go b/internal/services/compute/linux_virtual_machine_scale_set_resource.go index a276c8473178..34cd02e9d63c 100644 --- a/internal/services/compute/linux_virtual_machine_scale_set_resource.go +++ b/internal/services/compute/linux_virtual_machine_scale_set_resource.go @@ -9,6 +9,7 @@ import ( "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" "github.com/hashicorp/go-azure-helpers/resourcemanager/zones" + "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/proximityplacementgroups" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" @@ -1058,7 +1059,8 @@ func resourceLinuxVirtualMachineScaleSetSchema() map[string]*pluginsdk.Schema { "instances": { Type: pluginsdk.TypeInt, - Required: true, + Optional: true, + Default: 0, ValidateFunc: validation.IntAtLeast(0), }, @@ -1203,7 +1205,7 @@ func resourceLinuxVirtualMachineScaleSetSchema() map[string]*pluginsdk.Schema { Type: pluginsdk.TypeString, Optional: true, ForceNew: true, - ValidateFunc: validate.ProximityPlacementGroupID, + ValidateFunc: proximityplacementgroups.ValidateProximityPlacementGroupID, // the Compute API is broken and returns the Resource Group name in UPPERCASE :shrug:, github issue: https://github.com/Azure/azure-rest-api-specs/issues/10016 DiffSuppressFunc: suppress.CaseDifference, ConflictsWith: []string{ diff --git a/internal/services/compute/linux_virtual_machine_scale_set_scaling_resource_test.go b/internal/services/compute/linux_virtual_machine_scale_set_scaling_resource_test.go index b39157675633..02cd1c5a1abc 100644 --- a/internal/services/compute/linux_virtual_machine_scale_set_scaling_resource_test.go +++ b/internal/services/compute/linux_virtual_machine_scale_set_scaling_resource_test.go @@ -38,6 +38,21 @@ func TestAccLinuxVirtualMachineScaleSet_scalingCapacityReservationGroupId(t *tes }) } +func TestAccLinuxVirtualMachineScaleSet_defaultInstanceCount(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_linux_virtual_machine_scale_set", "test") + r := LinuxVirtualMachineScaleSetResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.defaultInstanceCount(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("admin_password"), + }) +} + func TestAccLinuxVirtualMachineScaleSet_scalingInstanceCount(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_linux_virtual_machine_scale_set", "test") r := LinuxVirtualMachineScaleSetResource{} @@ -436,6 +451,46 @@ resource "azurerm_linux_virtual_machine_scale_set" "test" { `, r.template(data), data.RandomInteger, instanceCount) } +func (r LinuxVirtualMachineScaleSetResource) defaultInstanceCount(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_linux_virtual_machine_scale_set" "test" { + name = "acctestvmss-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + sku = "Standard_F2" + admin_username = "adminuser" + admin_password = "P@ssword1234!" + + disable_password_authentication = false + + source_image_reference { + publisher = "Canonical" + offer = "UbuntuServer" + sku = "16.04-LTS" + version = "latest" + } + + os_disk { + storage_account_type = "Standard_LRS" + caching = "ReadWrite" + } + + network_interface { + name = "example" + primary = true + + ip_configuration { + name = "internal" + primary = true + subnet_id = azurerm_subnet.test.id + } + } +} +`, r.template(data), data.RandomInteger) +} + func (r LinuxVirtualMachineScaleSetResource) scalingInstanceCountIgnoreUpdatedSku(data acceptance.TestData, instanceCount int) string { return fmt.Sprintf(` %s diff --git a/internal/services/compute/managed_disk_data_source.go b/internal/services/compute/managed_disk_data_source.go index b52c98ad9a75..8d0a1dc6c66b 100644 --- a/internal/services/compute/managed_disk_data_source.go +++ b/internal/services/compute/managed_disk_data_source.go @@ -60,6 +60,54 @@ func dataSourceManagedDisk() *pluginsdk.Resource { Computed: true, }, + "encryption_settings": { + Type: pluginsdk.TypeList, + Computed: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "enabled": { + Type: pluginsdk.TypeBool, + Computed: true, + }, + + "disk_encryption_key": { + Type: pluginsdk.TypeList, + Computed: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "secret_url": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "source_vault_id": { + Type: pluginsdk.TypeString, + Computed: true, + }, + }, + }, + }, + "key_encryption_key": { + Type: pluginsdk.TypeList, + Computed: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "key_url": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "source_vault_id": { + Type: pluginsdk.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + "image_reference_id": { Type: pluginsdk.TypeString, Computed: true, @@ -162,6 +210,10 @@ func dataSourceManagedDiskRead(d *pluginsdk.ResourceData, meta interface{}) erro diskEncryptionSetId = *props.Encryption.DiskEncryptionSetID } d.Set("disk_encryption_set_id", diskEncryptionSetId) + + if err := d.Set("encryption_settings", flattenManagedDiskEncryptionSettings(props.EncryptionSettingsCollection)); err != nil { + return fmt.Errorf("setting `encryption_settings`: %+v", err) + } } return tags.FlattenAndSet(d, resp.Tags) diff --git a/internal/services/compute/managed_disk_data_source_test.go b/internal/services/compute/managed_disk_data_source_test.go index 6d027527c39f..6509cae50440 100644 --- a/internal/services/compute/managed_disk_data_source_test.go +++ b/internal/services/compute/managed_disk_data_source_test.go @@ -67,6 +67,27 @@ func TestAccDataSourceManagedDisk_diskAccess(t *testing.T) { }) } +func TestAccDataSourceManagedDisk_encryptionSettings(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_managed_disk", "test") + r := ManagedDiskDataSource{} + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: r.encryptionSettings(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("encryption_settings.#").HasValue("1"), + check.That(data.ResourceName).Key("encryption_settings.0.enabled").HasValue("true"), + check.That(data.ResourceName).Key("encryption_settings.0.disk_encryption_key.#").HasValue("1"), + check.That(data.ResourceName).Key("encryption_settings.0.disk_encryption_key.0.secret_url").Exists(), + check.That(data.ResourceName).Key("encryption_settings.0.disk_encryption_key.0.source_vault_id").Exists(), + check.That(data.ResourceName).Key("encryption_settings.0.key_encryption_key.#").HasValue("1"), + check.That(data.ResourceName).Key("encryption_settings.0.key_encryption_key.0.key_url").Exists(), + check.That(data.ResourceName).Key("encryption_settings.0.key_encryption_key.0.source_vault_id").Exists(), + ), + }, + }) +} + func (ManagedDiskDataSource) basic(data acceptance.TestData, name string, resourceGroupName string) string { return fmt.Sprintf(` provider "azurerm" { @@ -168,3 +189,103 @@ data "azurerm_managed_disk" "test" { } `, data.Locations.Primary, data.RandomInteger) } + +func (ManagedDiskDataSource) encryptionSettings(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features { + key_vault { + recover_soft_deleted_key_vaults = false + purge_soft_delete_on_destroy = false + purge_soft_deleted_keys_on_destroy = false + purge_soft_deleted_secrets_on_destroy = false + } + } +} + +data "azurerm_client_config" "current" {} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_key_vault" "test" { + name = "acctestkv-%s" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + tenant_id = "${data.azurerm_client_config.current.tenant_id}" + sku_name = "standard" + + access_policy { + tenant_id = "${data.azurerm_client_config.current.tenant_id}" + object_id = "${data.azurerm_client_config.current.object_id}" + + key_permissions = [ + "Create", + "Delete", + "Get", + "Purge", + ] + + secret_permissions = [ + "Delete", + "Get", + "Set", + ] + } + + enabled_for_disk_encryption = true + + tags = { + environment = "Production" + } +} + +resource "azurerm_key_vault_secret" "test" { + name = "secret-%s" + value = "szechuan" + key_vault_id = azurerm_key_vault.test.id +} + +resource "azurerm_key_vault_key" "test" { + name = "key-%s" + key_vault_id = azurerm_key_vault.test.id + key_type = "EC" + key_size = 2048 + + key_opts = [ + "sign", + "verify", + ] +} + +resource "azurerm_managed_disk" "test" { + name = "acctestd-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + storage_account_type = "Standard_LRS" + create_option = "Empty" + disk_size_gb = "1" + + encryption_settings { + enabled = true + + disk_encryption_key { + secret_url = "${azurerm_key_vault_secret.test.id}" + source_vault_id = "${azurerm_key_vault.test.id}" + } + + key_encryption_key { + key_url = "${azurerm_key_vault_key.test.id}" + source_vault_id = "${azurerm_key_vault.test.id}" + } + } +} + +data "azurerm_managed_disk" "test" { + name = azurerm_managed_disk.test.name + resource_group_name = azurerm_resource_group.test.name +} +`, data.RandomInteger, data.Locations.Primary, data.RandomString, data.RandomString, data.RandomString, data.RandomInteger) +} diff --git a/internal/services/compute/parse/dedicated_host.go b/internal/services/compute/parse/dedicated_host.go deleted file mode 100644 index f9c7816b810b..000000000000 --- a/internal/services/compute/parse/dedicated_host.go +++ /dev/null @@ -1,75 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - "strings" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -type DedicatedHostId struct { - SubscriptionId string - ResourceGroup string - HostGroupName string - HostName string -} - -func NewDedicatedHostID(subscriptionId, resourceGroup, hostGroupName, hostName string) DedicatedHostId { - return DedicatedHostId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourceGroup, - HostGroupName: hostGroupName, - HostName: hostName, - } -} - -func (id DedicatedHostId) String() string { - segments := []string{ - fmt.Sprintf("Host Name %q", id.HostName), - fmt.Sprintf("Host Group Name %q", id.HostGroupName), - fmt.Sprintf("Resource Group %q", id.ResourceGroup), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Dedicated Host", segmentsStr) -} - -func (id DedicatedHostId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/hostGroups/%s/hosts/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.HostGroupName, id.HostName) -} - -// DedicatedHostID parses a DedicatedHost ID into an DedicatedHostId struct -func DedicatedHostID(input string) (*DedicatedHostId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := DedicatedHostId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - if resourceId.HostGroupName, err = id.PopSegment("hostGroups"); err != nil { - return nil, err - } - if resourceId.HostName, err = id.PopSegment("hosts"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/compute/parse/dedicated_host_group.go b/internal/services/compute/parse/dedicated_host_group.go deleted file mode 100644 index 453a86e5019b..000000000000 --- a/internal/services/compute/parse/dedicated_host_group.go +++ /dev/null @@ -1,69 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - "strings" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -type DedicatedHostGroupId struct { - SubscriptionId string - ResourceGroup string - HostGroupName string -} - -func NewDedicatedHostGroupID(subscriptionId, resourceGroup, hostGroupName string) DedicatedHostGroupId { - return DedicatedHostGroupId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourceGroup, - HostGroupName: hostGroupName, - } -} - -func (id DedicatedHostGroupId) String() string { - segments := []string{ - fmt.Sprintf("Host Group Name %q", id.HostGroupName), - fmt.Sprintf("Resource Group %q", id.ResourceGroup), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Dedicated Host Group", segmentsStr) -} - -func (id DedicatedHostGroupId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/hostGroups/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.HostGroupName) -} - -// DedicatedHostGroupID parses a DedicatedHostGroup ID into an DedicatedHostGroupId struct -func DedicatedHostGroupID(input string) (*DedicatedHostGroupId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := DedicatedHostGroupId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - if resourceId.HostGroupName, err = id.PopSegment("hostGroups"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/compute/parse/dedicated_host_group_test.go b/internal/services/compute/parse/dedicated_host_group_test.go deleted file mode 100644 index 0888e81b0477..000000000000 --- a/internal/services/compute/parse/dedicated_host_group_test.go +++ /dev/null @@ -1,112 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "testing" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -var _ resourceids.Id = DedicatedHostGroupId{} - -func TestDedicatedHostGroupIDFormatter(t *testing.T) { - actual := NewDedicatedHostGroupID("12345678-1234-9876-4563-123456789012", "resGroup1", "hostGroup1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/hostGroups/hostGroup1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestDedicatedHostGroupID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *DedicatedHostGroupId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - - { - // missing HostGroupName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/", - Error: true, - }, - - { - // missing value for HostGroupName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/hostGroups/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/hostGroups/hostGroup1", - Expected: &DedicatedHostGroupId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - HostGroupName: "hostGroup1", - }, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.COMPUTE/HOSTGROUPS/HOSTGROUP1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := DedicatedHostGroupID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - if actual.HostGroupName != v.Expected.HostGroupName { - t.Fatalf("Expected %q but got %q for HostGroupName", v.Expected.HostGroupName, actual.HostGroupName) - } - } -} diff --git a/internal/services/compute/parse/dedicated_host_test.go b/internal/services/compute/parse/dedicated_host_test.go deleted file mode 100644 index 13475856972c..000000000000 --- a/internal/services/compute/parse/dedicated_host_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "testing" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -var _ resourceids.Id = DedicatedHostId{} - -func TestDedicatedHostIDFormatter(t *testing.T) { - actual := NewDedicatedHostID("12345678-1234-9876-4563-123456789012", "resGroup1", "hostGroup1", "host1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/hostGroups/hostGroup1/hosts/host1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestDedicatedHostID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *DedicatedHostId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - - { - // missing HostGroupName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/", - Error: true, - }, - - { - // missing value for HostGroupName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/hostGroups/", - Error: true, - }, - - { - // missing HostName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/hostGroups/hostGroup1/", - Error: true, - }, - - { - // missing value for HostName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/hostGroups/hostGroup1/hosts/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/hostGroups/hostGroup1/hosts/host1", - Expected: &DedicatedHostId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - HostGroupName: "hostGroup1", - HostName: "host1", - }, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.COMPUTE/HOSTGROUPS/HOSTGROUP1/HOSTS/HOST1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := DedicatedHostID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - if actual.HostGroupName != v.Expected.HostGroupName { - t.Fatalf("Expected %q but got %q for HostGroupName", v.Expected.HostGroupName, actual.HostGroupName) - } - if actual.HostName != v.Expected.HostName { - t.Fatalf("Expected %q but got %q for HostName", v.Expected.HostName, actual.HostName) - } - } -} diff --git a/internal/services/compute/parse/proximity_placement_group.go b/internal/services/compute/parse/proximity_placement_group.go deleted file mode 100644 index abb24fffd41c..000000000000 --- a/internal/services/compute/parse/proximity_placement_group.go +++ /dev/null @@ -1,69 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - "strings" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -type ProximityPlacementGroupId struct { - SubscriptionId string - ResourceGroup string - Name string -} - -func NewProximityPlacementGroupID(subscriptionId, resourceGroup, name string) ProximityPlacementGroupId { - return ProximityPlacementGroupId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourceGroup, - Name: name, - } -} - -func (id ProximityPlacementGroupId) String() string { - segments := []string{ - fmt.Sprintf("Name %q", id.Name), - fmt.Sprintf("Resource Group %q", id.ResourceGroup), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Proximity Placement Group", segmentsStr) -} - -func (id ProximityPlacementGroupId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/proximityPlacementGroups/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.Name) -} - -// ProximityPlacementGroupID parses a ProximityPlacementGroup ID into an ProximityPlacementGroupId struct -func ProximityPlacementGroupID(input string) (*ProximityPlacementGroupId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := ProximityPlacementGroupId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - if resourceId.Name, err = id.PopSegment("proximityPlacementGroups"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/compute/parse/proximity_placement_group_test.go b/internal/services/compute/parse/proximity_placement_group_test.go deleted file mode 100644 index a5069aefd4fd..000000000000 --- a/internal/services/compute/parse/proximity_placement_group_test.go +++ /dev/null @@ -1,112 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "testing" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -var _ resourceids.Id = ProximityPlacementGroupId{} - -func TestProximityPlacementGroupIDFormatter(t *testing.T) { - actual := NewProximityPlacementGroupID("12345678-1234-9876-4563-123456789012", "group1", "proximityPlacementGroup1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Compute/proximityPlacementGroups/proximityPlacementGroup1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestProximityPlacementGroupID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *ProximityPlacementGroupId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - - { - // missing Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Compute/", - Error: true, - }, - - { - // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Compute/proximityPlacementGroups/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Compute/proximityPlacementGroups/proximityPlacementGroup1", - Expected: &ProximityPlacementGroupId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "group1", - Name: "proximityPlacementGroup1", - }, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/GROUP1/PROVIDERS/MICROSOFT.COMPUTE/PROXIMITYPLACEMENTGROUPS/PROXIMITYPLACEMENTGROUP1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := ProximityPlacementGroupID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - if actual.Name != v.Expected.Name { - t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name) - } - } -} diff --git a/internal/services/compute/proximity_placement_group_data_source.go b/internal/services/compute/proximity_placement_group_data_source.go index e81b41cf9e24..1827f1522923 100644 --- a/internal/services/compute/proximity_placement_group_data_source.go +++ b/internal/services/compute/proximity_placement_group_data_source.go @@ -4,15 +4,15 @@ import ( "fmt" "time" + "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/proximityplacementgroups" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/compute/parse" - "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" - "github.com/hashicorp/terraform-provider-azurerm/utils" ) func dataSourceProximityPlacementGroup() *pluginsdk.Resource { @@ -34,7 +34,7 @@ func dataSourceProximityPlacementGroup() *pluginsdk.Resource { "location": commonschema.LocationComputed(), - "tags": tags.SchemaDataSource(), + "tags": commonschema.TagsDataSource(), }, } } @@ -45,19 +45,25 @@ func dataSourceProximityPlacementGroupRead(d *pluginsdk.ResourceData, meta inter ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id := parse.NewProximityPlacementGroupID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) + id := proximityplacementgroups.NewProximityPlacementGroupID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) - resp, err := client.Get(ctx, id.ResourceGroup, id.Name, "") + resp, err := client.Get(ctx, id, proximityplacementgroups.DefaultGetOperationOptions()) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { return fmt.Errorf("%s was not found", id) } - return fmt.Errorf("making Read request on %s: %+v", id, err) + return fmt.Errorf("retrieving %s: %+v", id, err) } d.SetId(id.ID()) - d.Set("location", location.NormalizeNilable(resp.Location)) - return tags.FlattenAndSet(d, resp.Tags) + if model := resp.Model; model != nil { + d.Set("location", location.Normalize(model.Location)) + if err := tags.FlattenAndSet(d, model.Tags); err != nil { + return err + } + } + + return nil } diff --git a/internal/services/compute/proximity_placement_group_resource.go b/internal/services/compute/proximity_placement_group_resource.go index 1de0703a126d..01039f9abd69 100644 --- a/internal/services/compute/proximity_placement_group_resource.go +++ b/internal/services/compute/proximity_placement_group_resource.go @@ -2,19 +2,18 @@ package compute import ( "fmt" - "log" "time" - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2021-11-01/compute" - "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/proximityplacementgroups" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/compute/parse" - "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" - "github.com/hashicorp/terraform-provider-azurerm/utils" ) func resourceProximityPlacementGroup() *pluginsdk.Resource { @@ -25,7 +24,7 @@ func resourceProximityPlacementGroup() *pluginsdk.Resource { Delete: resourceProximityPlacementGroupDelete, Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - _, err := parse.ProximityPlacementGroupID(id) + _, err := proximityplacementgroups.ParseProximityPlacementGroupID(id) return err }), @@ -44,11 +43,11 @@ func resourceProximityPlacementGroup() *pluginsdk.Resource { ValidateFunc: validation.StringIsNotEmpty, }, - "resource_group_name": azure.SchemaResourceGroupName(), + "resource_group_name": commonschema.ResourceGroupName(), - "location": azure.SchemaLocation(), + "location": commonschema.Location(), - "tags": tags.Schema(), + "tags": commonschema.Tags(), }, } } @@ -59,32 +58,28 @@ func resourceProximityPlacementGroupCreateUpdate(d *pluginsdk.ResourceData, meta ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - log.Printf("[INFO] preparing arguments for AzureRM Proximity Placement Group creation.") - - id := parse.NewProximityPlacementGroupID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) + id := proximityplacementgroups.NewProximityPlacementGroupID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) if d.IsNewResource() { - existing, err := client.Get(ctx, id.ResourceGroup, id.Name, "") + existing, err := client.Get(ctx, id, proximityplacementgroups.DefaultGetOperationOptions()) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { - return fmt.Errorf("checking for presence of existing %s: %s", id, err) + if !response.WasNotFound(existing.HttpResponse) { + return fmt.Errorf("checking for presence of existing %s: %+v", id, err) } } - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return tf.ImportAsExistsError("azurerm_proximity_placement_group", id.ID()) } } - ppg := compute.ProximityPlacementGroup{ - Name: &id.Name, - Location: utils.String(azure.NormalizeLocation(d.Get("location").(string))), + payload := proximityplacementgroups.ProximityPlacementGroup{ + Location: location.Normalize(d.Get("location").(string)), Tags: tags.Expand(d.Get("tags").(map[string]interface{})), } - _, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.Name, ppg) - if err != nil { - return err + if _, err := client.CreateOrUpdate(ctx, id, payload); err != nil { + return fmt.Errorf("creating/updating %s: %+v", id, err) } d.SetId(id.ID()) @@ -97,27 +92,31 @@ func resourceProximityPlacementGroupRead(d *pluginsdk.ResourceData, meta interfa ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.ProximityPlacementGroupID(d.Id()) + id, err := proximityplacementgroups.ParseProximityPlacementGroupID(d.Id()) if err != nil { return err } - resp, err := client.Get(ctx, id.ResourceGroup, id.Name, "") + resp, err := client.Get(ctx, *id, proximityplacementgroups.DefaultGetOperationOptions()) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { d.SetId("") return nil } - return fmt.Errorf("making Read request on Proximity Placement Group %q : %+v", id.String(), err) + return fmt.Errorf("retrieving %s: %+v", *id, err) } - d.Set("name", id.Name) - d.Set("resource_group_name", id.ResourceGroup) - if location := resp.Location; location != nil { - d.Set("location", azure.NormalizeLocation(*location)) + if model := resp.Model; model != nil { + d.Set("name", id.ProximityPlacementGroupName) + d.Set("resource_group_name", id.ResourceGroupName) + + d.Set("location", location.Normalize(model.Location)) + if err := tags.FlattenAndSet(d, model.Tags); err != nil { + return err + } } - return tags.FlattenAndSet(d, resp.Tags) + return nil } func resourceProximityPlacementGroupDelete(d *pluginsdk.ResourceData, meta interface{}) error { @@ -125,11 +124,14 @@ func resourceProximityPlacementGroupDelete(d *pluginsdk.ResourceData, meta inter ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.ProximityPlacementGroupID(d.Id()) + id, err := proximityplacementgroups.ParseProximityPlacementGroupID(d.Id()) if err != nil { return err } - _, err = client.Delete(ctx, id.ResourceGroup, id.Name) - return err + if _, err = client.Delete(ctx, *id); err != nil { + return fmt.Errorf("deleting %s: %+v", *id, err) + } + + return nil } diff --git a/internal/services/compute/proximity_placement_group_resource_test.go b/internal/services/compute/proximity_placement_group_resource_test.go index d8ffa6053186..b510deb4e1c8 100644 --- a/internal/services/compute/proximity_placement_group_resource_test.go +++ b/internal/services/compute/proximity_placement_group_resource_test.go @@ -5,11 +5,10 @@ import ( "fmt" "testing" - "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/proximityplacementgroups" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/compute/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -88,30 +87,27 @@ func TestAccProximityPlacementGroup_withTags(t *testing.T) { } func (t ProximityPlacementGroupResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.ProximityPlacementGroupID(state.ID) + id, err := proximityplacementgroups.ParseProximityPlacementGroupID(state.ID) if err != nil { return nil, err } - resp, err := clients.Compute.ProximityPlacementGroupsClient.Get(ctx, id.ResourceGroup, id.Name, "") + resp, err := clients.Compute.ProximityPlacementGroupsClient.Get(ctx, *id, proximityplacementgroups.DefaultGetOperationOptions()) if err != nil { - return nil, fmt.Errorf("retrieving Compute Proximity Placement Group %q", id) + return nil, fmt.Errorf("retrieving %s: %+v", *id, err) } - return utils.Bool(resp.ID != nil), nil + return utils.Bool(resp.Model != nil), nil } func (ProximityPlacementGroupResource) Destroy(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.ProximityPlacementGroupID(state.ID) + id, err := proximityplacementgroups.ParseProximityPlacementGroupID(state.ID) if err != nil { return nil, err } - resp, err := client.Compute.ProximityPlacementGroupsClient.Delete(ctx, id.ResourceGroup, id.Name) - if err != nil { - if !response.WasNotFound(resp.Response) { - return nil, fmt.Errorf("deleting Proximity Placement Group %q: %+v", id, err) - } + if _, err := client.Compute.ProximityPlacementGroupsClient.Delete(ctx, *id); err != nil { + return nil, fmt.Errorf("deleting %s: %+v", *id, err) } return utils.Bool(true), nil diff --git a/internal/services/compute/resourceids.go b/internal/services/compute/resourceids.go index 46e1aa7c721f..1ef1ea274ea7 100644 --- a/internal/services/compute/resourceids.go +++ b/internal/services/compute/resourceids.go @@ -2,14 +2,11 @@ package compute //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=CapacityReservationGroup -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/capacityReservationGroups/capacityReservationGroup1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=CapacityReservation -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/capacityReservationGroups/capacityReservationGroup1/capacityReservations/capacityReservation1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=DedicatedHostGroup -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/hostGroups/hostGroup1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=DedicatedHost -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/hostGroups/hostGroup1/hosts/host1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=DiskEncryptionSet -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/diskEncryptionSets/set1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=GalleryApplication -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/galleries/gallery1/applications/galleryApplication1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=GalleryApplicationVersion -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/galleries/gallery1/applications/galleryApplication1/versions/galleryApplicationVersion1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Image -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/images/image1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ManagedDisk -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/disks/disk1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ProximityPlacementGroup -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/proximityPlacementGroups/group1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=SharedImage -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/galleries/gallery1/images/image1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=SharedImageGallery -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/galleries/gallery1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=SharedImageVersion -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/galleries/gallery1/images/image1/versions/version1 @@ -23,5 +20,4 @@ package compute //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=DataDisk -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Compute/virtualMachines/machine1/dataDisks/disk1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Snapshot -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Compute/snapshots/snapshot1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Plan -id=/subscriptions/12345678-1234-9876-4563-123456789012/providers/Microsoft.MarketplaceOrdering/agreements/agreement1/offers/offer1/plans/hourly -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ProximityPlacementGroup -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Compute/proximityPlacementGroups/proximityPlacementGroup1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=HostGroup -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Compute/hostGroups/hostgroup1 diff --git a/internal/services/compute/shared_image_data_source.go b/internal/services/compute/shared_image_data_source.go index 2dbf49fe8201..c211c418f291 100644 --- a/internal/services/compute/shared_image_data_source.go +++ b/internal/services/compute/shared_image_data_source.go @@ -41,6 +41,11 @@ func dataSourceSharedImage() *pluginsdk.Resource { "resource_group_name": commonschema.ResourceGroupNameForDataSource(), + "architecture": { + Type: pluginsdk.TypeString, + Computed: true, + }, + "os_type": { Type: pluginsdk.TypeString, Computed: true, @@ -131,6 +136,7 @@ func dataSourceSharedImageRead(d *pluginsdk.ResourceData, meta interface{}) erro d.Set("description", props.Description) d.Set("eula", props.Eula) d.Set("os_type", string(props.OsType)) + d.Set("architecture", string(props.Architecture)) d.Set("specialized", props.OsState == compute.OperatingSystemStateTypesSpecialized) d.Set("hyper_v_generation", string(props.HyperVGeneration)) d.Set("privacy_statement_uri", props.PrivacyStatementURI) diff --git a/internal/services/compute/shared_image_resource.go b/internal/services/compute/shared_image_resource.go index 8f2372db0361..12211d5cf043 100644 --- a/internal/services/compute/shared_image_resource.go +++ b/internal/services/compute/shared_image_resource.go @@ -60,6 +60,17 @@ func resourceSharedImage() *pluginsdk.Resource { "resource_group_name": azure.SchemaResourceGroupName(), + "architecture": { + Type: pluginsdk.TypeString, + Optional: true, + Default: string(compute.ArchitectureTypesX64), + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{ + string(compute.ArchitectureTypesX64), + string(compute.ArchitectureTypesArm64), + }, false), + }, + "os_type": { Type: pluginsdk.TypeString, Required: true, @@ -107,19 +118,22 @@ func resourceSharedImage() *pluginsdk.Resource { Elem: &pluginsdk.Resource{ Schema: map[string]*pluginsdk.Schema{ "publisher": { - Type: pluginsdk.TypeString, - ForceNew: true, - Required: true, + Type: pluginsdk.TypeString, + ForceNew: true, + Required: true, + ValidateFunc: validate.SharedImageIdentifierAttribute, }, "offer": { - Type: pluginsdk.TypeString, - ForceNew: true, - Required: true, + Type: pluginsdk.TypeString, + ForceNew: true, + Required: true, + ValidateFunc: validate.SharedImageIdentifierAttribute, }, "sku": { - Type: pluginsdk.TypeString, - ForceNew: true, - Required: true, + Type: pluginsdk.TypeString, + ForceNew: true, + Required: true, + ValidateFunc: validate.SharedImageIdentifierAttribute, }, }, }, @@ -277,6 +291,7 @@ func resourceSharedImageCreateUpdate(d *pluginsdk.ResourceData, meta interface{} Identifier: expandGalleryImageIdentifier(d), PrivacyStatementURI: utils.String(d.Get("privacy_statement_uri").(string)), ReleaseNoteURI: utils.String(d.Get("release_note_uri").(string)), + Architecture: compute.Architecture(d.Get("architecture").(string)), OsType: compute.OperatingSystemTypes(d.Get("os_type").(string)), HyperVGeneration: compute.HyperVGeneration(d.Get("hyper_v_generation").(string)), PurchasePlan: expandGalleryImagePurchasePlan(d.Get("purchase_plan").([]interface{})), @@ -392,6 +407,7 @@ func resourceSharedImageRead(d *pluginsdk.ResourceData, meta interface{}) error d.Set("min_recommended_memory_in_gb", minRecommendedMemoryInGB) d.Set("os_type", string(props.OsType)) + d.Set("architecture", string(props.Architecture)) d.Set("specialized", props.OsState == compute.OperatingSystemStateTypesSpecialized) d.Set("hyper_v_generation", string(props.HyperVGeneration)) d.Set("privacy_statement_uri", props.PrivacyStatementURI) diff --git a/internal/services/compute/shared_image_resource_test.go b/internal/services/compute/shared_image_resource_test.go index 02baa96a135f..28c4cc910c11 100644 --- a/internal/services/compute/shared_image_resource_test.go +++ b/internal/services/compute/shared_image_resource_test.go @@ -47,6 +47,22 @@ func TestAccSharedImage_basic_hyperVGeneration_V2(t *testing.T) { }) } +func TestAccSharedImage_basic_Arm(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_shared_image", "test") + r := SharedImageResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basicWithArch(data, "Arm64"), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("description").HasValue(""), + check.That(data.ResourceName).Key("architecture").HasValue("Arm64"), + ), + }, + data.ImportStep(), + }) +} + func TestAccSharedImage_requiresImport(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_shared_image", "test") r := SharedImageResource{} @@ -343,6 +359,45 @@ resource "azurerm_shared_image" "test" { `, hyperVGen, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger) } +func (SharedImageResource) basicWithArch(data acceptance.TestData, arch string) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +variable "architecture" { + default = "%s" +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_shared_image_gallery" "test" { + name = "acctestsig%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location +} + +resource "azurerm_shared_image" "test" { + name = "acctestimg%d" + gallery_name = azurerm_shared_image_gallery.test.name + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + architecture = var.architecture != "" ? var.architecture : null + os_type = "Linux" + hyper_v_generation = "V2" + + identifier { + publisher = "AccTesPublisher%d" + offer = "AccTesOffer%d" + sku = "AccTesSku%d" + } +} +`, arch, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger) +} + func (SharedImageResource) specialized(data acceptance.TestData, hyperVGen string) string { return fmt.Sprintf(` provider "azurerm" { diff --git a/internal/services/compute/shared_image_version_data_source.go b/internal/services/compute/shared_image_version_data_source.go index 38bde5406b64..68cf07227afb 100644 --- a/internal/services/compute/shared_image_version_data_source.go +++ b/internal/services/compute/shared_image_version_data_source.go @@ -168,34 +168,40 @@ func obtainImage(client *compute.GalleryImageVersionsClient, ctx context.Context switch galleryImageVersionName { case "latest": - images, err := client.ListByGalleryImage(ctx, resourceGroup, galleryName, galleryImageName) + imagesIterator, err := client.ListByGalleryImageComplete(ctx, resourceGroup, galleryName, galleryImageName) if err != nil { - if utils.ResponseWasNotFound(images.Response().Response) { + if utils.ResponseWasNotFound(imagesIterator.Response().Response) { return nil, notFoundError } return nil, fmt.Errorf("retrieving Shared Image Versions (Image %q / Gallery %q / Resource Group %q): %+v", galleryImageName, galleryName, resourceGroup, err) } + images := make([]compute.GalleryImageVersion, 0) + for imagesIterator.NotDone() { + images = append(images, imagesIterator.Value()) + if err := imagesIterator.NextWithContext(ctx); err != nil { + return nil, fmt.Errorf("listing Shared Image Versions (Image %q / Gallery %q / Resource Group %q): %+v", galleryImageName, galleryName, resourceGroup, err) + } + } + // the last image in the list is the latest version - if len(images.Values()) > 0 { - values := images.Values() - var errs []error + if len(images) > 0 { if sortBySemVer { - values, errs = sortSharedImageVersions(values) + var errs []error + images, errs = sortSharedImageVersions(images) if len(errs) > 0 { return nil, fmt.Errorf("parsing version(s): %v", errs) } } - image := values[len(values)-1] + image := images[len(images)-1] return &image, nil } - return nil, notFoundError case "recent": - images, err := client.ListByGalleryImage(ctx, resourceGroup, galleryName, galleryImageName) + imagesIterator, err := client.ListByGalleryImageComplete(ctx, resourceGroup, galleryName, galleryImageName) if err != nil { - if utils.ResponseWasNotFound(images.Response().Response) { + if utils.ResponseWasNotFound(imagesIterator.Response().Response) { return nil, notFoundError } return nil, fmt.Errorf("retrieving Shared Image Versions (Image %q / Gallery %q / Resource Group %q): %+v", galleryImageName, galleryName, resourceGroup, err) @@ -203,13 +209,18 @@ func obtainImage(client *compute.GalleryImageVersionsClient, ctx context.Context var image *compute.GalleryImageVersion var recentDate *time.Time // compare dates until we find the image that was updated most recently - for _, currImage := range images.Values() { + for imagesIterator.NotDone() { + currImage := imagesIterator.Value() if profile := currImage.PublishingProfile; profile != nil { if profile.PublishedDate != nil && (recentDate == nil || profile.PublishedDate.Time.After(*recentDate)) { recentDate = &profile.PublishedDate.Time image = &currImage } } + + if err := imagesIterator.NextWithContext(ctx); err != nil { + return nil, fmt.Errorf("listing Shared Image Versions (Image %q / Gallery %q / Resource Group %q): %+v", galleryImageName, galleryName, resourceGroup, err) + } } if image != nil { diff --git a/internal/services/compute/shared_image_version_resource.go b/internal/services/compute/shared_image_version_resource.go index edd06bf961ca..361f6dbbb1fc 100644 --- a/internal/services/compute/shared_image_version_resource.go +++ b/internal/services/compute/shared_image_version_resource.go @@ -14,6 +14,7 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/services/compute/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/compute/validate" + storageValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/storage/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/suppress" @@ -111,6 +112,23 @@ func resourceSharedImageVersion() *pluginsdk.Resource { }, }, + "blob_uri": { + Type: pluginsdk.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.IsURLWithScheme([]string{"http", "https"}), + RequiredWith: []string{"storage_account_id"}, + ExactlyOneOf: []string{"blob_uri", "os_disk_snapshot_id", "managed_image_id"}, + }, + + "storage_account_id": { + Type: pluginsdk.TypeString, + Optional: true, + ForceNew: true, + RequiredWith: []string{"blob_uri"}, + ValidateFunc: storageValidate.StorageAccountID, + }, + "end_of_life_date": { Type: pluginsdk.TypeString, Optional: true, @@ -122,7 +140,7 @@ func resourceSharedImageVersion() *pluginsdk.Resource { Type: pluginsdk.TypeString, Optional: true, ForceNew: true, - ExactlyOneOf: []string{"os_disk_snapshot_id", "managed_image_id"}, + ExactlyOneOf: []string{"blob_uri", "os_disk_snapshot_id", "managed_image_id"}, // TODO -- add a validation function when snapshot has its own validation function }, @@ -134,7 +152,7 @@ func resourceSharedImageVersion() *pluginsdk.Resource { validate.ImageID, validate.VirtualMachineID, ), - ExactlyOneOf: []string{"os_disk_snapshot_id", "managed_image_id"}, + ExactlyOneOf: []string{"blob_uri", "os_disk_snapshot_id", "managed_image_id"}, }, "replication_mode": { @@ -225,6 +243,15 @@ func resourceSharedImageVersionCreateUpdate(d *pluginsdk.ResourceData, meta inte } } + if v, ok := d.GetOk("blob_uri"); ok { + version.GalleryImageVersionProperties.StorageProfile.OsDiskImage = &compute.GalleryOSDiskImage{ + Source: &compute.GalleryArtifactVersionSource{ + ID: utils.String(d.Get("storage_account_id").(string)), + URI: utils.String(v.(string)), + }, + } + } + future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.GalleryName, id.ImageName, id.VersionName, version) if err != nil { return fmt.Errorf("creating %s: %+v", id, err) @@ -292,11 +319,24 @@ func resourceSharedImageVersionRead(d *pluginsdk.ResourceData, meta interface{}) d.Set("managed_image_id", source.ID) } + blobURI := "" + if profile.OsDiskImage != nil && profile.OsDiskImage.Source != nil && profile.OsDiskImage.Source.URI != nil { + blobURI = *profile.OsDiskImage.Source.URI + } + d.Set("blob_uri", blobURI) + osDiskSnapShotID := "" + storageAccountID := "" if profile.OsDiskImage != nil && profile.OsDiskImage.Source != nil && profile.OsDiskImage.Source.ID != nil { - osDiskSnapShotID = *profile.OsDiskImage.Source.ID + sourceID := *profile.OsDiskImage.Source.ID + if blobURI == "" { + osDiskSnapShotID = sourceID + } else { + storageAccountID = sourceID + } } d.Set("os_disk_snapshot_id", osDiskSnapShotID) + d.Set("storage_account_id", storageAccountID) } } diff --git a/internal/services/compute/shared_image_version_resource_test.go b/internal/services/compute/shared_image_version_resource_test.go index d06b1e2a899c..3dab9c7286f1 100644 --- a/internal/services/compute/shared_image_version_resource_test.go +++ b/internal/services/compute/shared_image_version_resource_test.go @@ -102,6 +102,21 @@ func TestAccSharedImageVersion_storageAccountTypeZrs(t *testing.T) { }) } +func TestAccSharedImageVersion_blobURI(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_shared_image_version", "test") + r := SharedImageVersionResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.imageVersionBlobURI(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func TestAccSharedImageVersion_specializedImageVersionBySnapshot(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_shared_image_version", "test") r := SharedImageVersionResource{} @@ -330,6 +345,49 @@ resource "azurerm_shared_image_version" "test" { `, template) } +func (r SharedImageVersionResource) imageVersionBlobURI(data acceptance.TestData) string { + template := r.setup(data) + return fmt.Sprintf(` +%[1]s + +resource "azurerm_shared_image_gallery" "test" { + name = "acctestsig%[2]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location +} + +resource "azurerm_shared_image" "test" { + name = "acctestimg%[2]d" + gallery_name = azurerm_shared_image_gallery.test.name + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + os_type = "Linux" + + identifier { + publisher = "AccTesPublisher%[2]d" + offer = "AccTesOffer%[2]d" + sku = "AccTesSku%[2]d" + } +} + +resource "azurerm_shared_image_version" "test" { + name = "0.0.1" + gallery_name = azurerm_shared_image_gallery.test.name + image_name = azurerm_shared_image.test.name + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + + blob_uri = azurerm_virtual_machine.testsource.storage_os_disk[0].vhd_uri + storage_account_id = azurerm_storage_account.test.id + + target_region { + name = azurerm_resource_group.test.location + regional_replica_count = 1 + } +} +`, template, data.RandomInteger) +} + func (r SharedImageVersionResource) provisionSpecialized(data acceptance.TestData) string { template := ImageResource{}.setupManagedDisks(data) return fmt.Sprintf(` diff --git a/internal/services/compute/validate/compute.go b/internal/services/compute/validate/compute.go index 3b23edd19c41..8889538ad3bb 100644 --- a/internal/services/compute/validate/compute.go +++ b/internal/services/compute/validate/compute.go @@ -3,6 +3,7 @@ package validate import ( "fmt" "regexp" + "strings" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" @@ -40,6 +41,25 @@ func SharedImageName(v interface{}, k string) (warnings []string, errors []error return warnings, errors } +func SharedImageIdentifierAttribute(v interface{}, k string) (warnings []string, errors []error) { + value := v.(string) + + length := len(value) + if length > 128 { + errors = append(errors, fmt.Errorf("%s can be up to 128 characters, currently %d.", k, length)) + } + + if strings.HasSuffix(value, ".") { + errors = append(errors, fmt.Errorf("%q can not end with a '.', got %q", k, value)) + } + + if !regexp.MustCompile(`^[A-Za-z0-9._-]+$`).MatchString(value) { + errors = append(errors, fmt.Errorf("%s can only contain alphanumeric, full stops, dashes and underscores. Got %q.", k, value)) + } + + return warnings, errors +} + func SharedImageVersionName(v interface{}, k string) (warnings []string, errors []error) { value := v.(string) diff --git a/internal/services/compute/validate/compute_test.go b/internal/services/compute/validate/compute_test.go index f7773a8c8221..25774f291b87 100644 --- a/internal/services/compute/validate/compute_test.go +++ b/internal/services/compute/validate/compute_test.go @@ -123,6 +123,69 @@ func TestSharedImageName(t *testing.T) { } } +func TestSharedImageIdentifierAttribute(t *testing.T) { + cases := []struct { + Input string + ShouldError bool + }{ + { + Input: "", + ShouldError: true, + }, + { + Input: "hello", + ShouldError: false, + }, + { + Input: "hello.", + ShouldError: true, + }, + { + Input: "hello123", + ShouldError: false, + }, + { + Input: "hello.123", + ShouldError: false, + }, + { + Input: "hello,123", + ShouldError: true, + }, + { + Input: "hello_123", + ShouldError: false, + }, + { + Input: "hello-123", + ShouldError: false, + }, + { + Input: strings.Repeat("a", 128), + ShouldError: false, + }, + { + Input: strings.Repeat("a", 129), + ShouldError: true, + }, + } + + for _, tc := range cases { + t.Run(tc.Input, func(t *testing.T) { + _, errors := SharedImageIdentifierAttribute(tc.Input, "test") + + hasErrors := len(errors) > 0 + if !hasErrors && tc.ShouldError { + t.Fatalf("Expected an error but didn't get one for %q", tc.Input) + } + + if hasErrors && !tc.ShouldError { + t.Fatalf("Expected to get no errors for %q but got %d", tc.Input, len(errors)) + } + }) + } +} + func TestSharedImageVersionName(t *testing.T) { cases := []struct { Input string diff --git a/internal/services/compute/validate/dedicated_host_group_id.go b/internal/services/compute/validate/dedicated_host_group_id.go deleted file mode 100644 index 94f6c944dcca..000000000000 --- a/internal/services/compute/validate/dedicated_host_group_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/compute/parse" -) - -func DedicatedHostGroupID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.DedicatedHostGroupID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/compute/validate/dedicated_host_group_id_test.go b/internal/services/compute/validate/dedicated_host_group_id_test.go deleted file mode 100644 index 2c2af34a70c0..000000000000 --- a/internal/services/compute/validate/dedicated_host_group_id_test.go +++ /dev/null @@ -1,76 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestDedicatedHostGroupID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - - { - // empty - Input: "", - Valid: false, - }, - - { - // missing SubscriptionId - Input: "/", - Valid: false, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Valid: false, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Valid: false, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Valid: false, - }, - - { - // missing HostGroupName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/", - Valid: false, - }, - - { - // missing value for HostGroupName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/hostGroups/", - Valid: false, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/hostGroups/hostGroup1", - Valid: true, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.COMPUTE/HOSTGROUPS/HOSTGROUP1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := DedicatedHostGroupID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/compute/validate/dedicated_host_id.go b/internal/services/compute/validate/dedicated_host_id.go deleted file mode 100644 index 2aaf7be23fd5..000000000000 --- a/internal/services/compute/validate/dedicated_host_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/compute/parse" -) - -func DedicatedHostID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.DedicatedHostID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/compute/validate/dedicated_host_id_test.go b/internal/services/compute/validate/dedicated_host_id_test.go deleted file mode 100644 index 359fdd9f7cad..000000000000 --- a/internal/services/compute/validate/dedicated_host_id_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestDedicatedHostID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - - { - // empty - Input: "", - Valid: false, - }, - - { - // missing SubscriptionId - Input: "/", - Valid: false, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Valid: false, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Valid: false, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Valid: false, - }, - - { - // missing HostGroupName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/", - Valid: false, - }, - - { - // missing value for HostGroupName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/hostGroups/", - Valid: false, - }, - - { - // missing HostName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/hostGroups/hostGroup1/", - Valid: false, - }, - - { - // missing value for HostName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/hostGroups/hostGroup1/hosts/", - Valid: false, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/hostGroups/hostGroup1/hosts/host1", - Valid: true, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.COMPUTE/HOSTGROUPS/HOSTGROUP1/HOSTS/HOST1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := DedicatedHostID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/compute/validate/proximity_placement_group_id.go b/internal/services/compute/validate/proximity_placement_group_id.go deleted file mode 100644 index 2c48bb9ad7a8..000000000000 --- a/internal/services/compute/validate/proximity_placement_group_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/compute/parse" -) - -func ProximityPlacementGroupID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.ProximityPlacementGroupID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/compute/validate/proximity_placement_group_id_test.go b/internal/services/compute/validate/proximity_placement_group_id_test.go deleted file mode 100644 index 413553dba3ff..000000000000 --- a/internal/services/compute/validate/proximity_placement_group_id_test.go +++ /dev/null @@ -1,76 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestProximityPlacementGroupID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - - { - // empty - Input: "", - Valid: false, - }, - - { - // missing SubscriptionId - Input: "/", - Valid: false, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Valid: false, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Valid: false, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Valid: false, - }, - - { - // missing Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Compute/", - Valid: false, - }, - - { - // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Compute/proximityPlacementGroups/", - Valid: false, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Compute/proximityPlacementGroups/proximityPlacementGroup1", - Valid: true, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/GROUP1/PROVIDERS/MICROSOFT.COMPUTE/PROXIMITYPLACEMENTGROUPS/PROXIMITYPLACEMENTGROUP1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := ProximityPlacementGroupID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/compute/virtual_machine_extension_resource.go b/internal/services/compute/virtual_machine_extension_resource.go index 11300b08bef8..101c02955d6e 100644 --- a/internal/services/compute/virtual_machine_extension_resource.go +++ b/internal/services/compute/virtual_machine_extension_resource.go @@ -40,6 +40,10 @@ func resourceVirtualMachineExtension() *pluginsdk.Resource { Type: pluginsdk.TypeString, Required: true, ForceNew: true, + ValidateFunc: validation.All( + validation.StringIsNotEmpty, + validation.StringDoesNotContainAny("/"), + ), }, "virtual_machine_id": { diff --git a/internal/services/compute/virtual_machine_scale_set_data_source.go b/internal/services/compute/virtual_machine_scale_set_data_source.go index 014d91762794..9c6c88c6c9c8 100644 --- a/internal/services/compute/virtual_machine_scale_set_data_source.go +++ b/internal/services/compute/virtual_machine_scale_set_data_source.go @@ -1,13 +1,17 @@ package compute import ( + "context" "fmt" "time" + "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2021-11-01/compute" + "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2021-08-01/network" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/services/compute/parse" + networkParse "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" @@ -36,12 +40,79 @@ func dataSourceVirtualMachineScaleSet() *pluginsdk.Resource { "network_interface": VirtualMachineScaleSetNetworkInterfaceSchemaForDataSource(), "identity": commonschema.SystemAssignedUserAssignedIdentityComputed(), + + "instances": { + Type: pluginsdk.TypeList, + Computed: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "computer_name": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "instance_id": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "latest_model_applied": { + Type: pluginsdk.TypeBool, + Computed: true, + }, + + "name": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "private_ip_address": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "private_ip_addresses": { + Type: pluginsdk.TypeList, + Computed: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + }, + }, + + "public_ip_address": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "public_ip_addresses": { + Type: pluginsdk.TypeList, + Computed: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + }, + }, + + "virtual_machine_id": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "zone": { + Type: pluginsdk.TypeString, + Computed: true, + }, + }, + }, + }, }, } } func dataSourceVirtualMachineScaleSetRead(d *pluginsdk.ResourceData, meta interface{}) error { client := meta.(*clients.Client).Compute.VMScaleSetClient + instancesClient := meta.(*clients.Client).Compute.VMScaleSetVMsClient + networkInterfacesClient := meta.(*clients.Client).Network.InterfacesClient + publicIPAddressesClient := meta.(*clients.Client).Network.PublicIPsClient subscriptionId := meta.(*clients.Client).Account.SubscriptionId ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() @@ -82,5 +153,130 @@ func dataSourceVirtualMachineScaleSetRead(d *pluginsdk.ResourceData, meta interf return fmt.Errorf("setting `identity`: %+v", err) } + instances := make([]interface{}, 0) + result, err := instancesClient.ListComplete(ctx, id.ResourceGroup, id.Name, "", "", "") + if err != nil { + return fmt.Errorf("listing VM Instances for Virtual Machine Scale Set %q (Resource Group %q): %+v", id.ResourceGroup, id.Name, err) + } + + for result.NotDone() { + instance := result.Value() + if instance.InstanceID != nil { + nics, err := networkInterfacesClient.ListVirtualMachineScaleSetVMNetworkInterfacesComplete(ctx, id.ResourceGroup, id.Name, *instance.InstanceID) + if err != nil { + return fmt.Errorf("listing Network Interfaces for VM Instance %q for Virtual Machine Scale Set %q (Resource Group %q): %+v", *instance.InstanceID, id.ResourceGroup, id.Name, err) + } + + networkInterfaces := make([]network.Interface, 0) + for nics.NotDone() { + networkInterfaces = append(networkInterfaces, nics.Value()) + if err := nics.NextWithContext(ctx); err != nil { + return fmt.Errorf("listing next page of Network Interfaces for VM Instance %q of Virtual Machine Scale Set %q (Resource Group %q): %v", *instance.InstanceID, id.ResourceGroup, id.Name, err) + } + } + + connectionInfo, err := getVirtualMachineScaleSetVMConnectionInfo(ctx, networkInterfaces, id.ResourceGroup, id.Name, *instance.InstanceID, publicIPAddressesClient) + if err != nil { + return err + } + + flattenedInstances := flattenVirtualMachineScaleSetVM(instance, connectionInfo) + instances = append(instances, flattenedInstances) + } + + if err := result.NextWithContext(ctx); err != nil { + return fmt.Errorf("listing next page VM Instances for Virtual Machine Scale Set %q (Resource Group %q): %+v", id.ResourceGroup, id.Name, err) + } + } + if err := d.Set("instances", instances); err != nil { + return fmt.Errorf("setting `instances`: %+v", err) + } + return nil } + +func getVirtualMachineScaleSetVMConnectionInfo(ctx context.Context, networkInterfaces []network.Interface, resourceGroupName string, virtualMachineScaleSetName string, virtualmachineIndex string, publicIPAddressesClient *network.PublicIPAddressesClient) (*connectionInfo, error) { + if len(networkInterfaces) == 0 { + return nil, nil + } + + primaryPublicAddress := "" + primaryPrivateAddress := "" + publicIPAddresses := make([]string, 0) + privateIPAddresses := make([]string, 0) + + for _, nic := range networkInterfaces { + for _, config := range *nic.IPConfigurations { + if props := config.InterfaceIPConfigurationPropertiesFormat; props != nil { + if pip := props.PublicIPAddress; pip != nil { + pipID, err := networkParse.VirtualMachineScaleSetPublicIPAddressID(*pip.ID) + if err != nil { + return nil, err + } + + publicIPAddress, err := publicIPAddressesClient.GetVirtualMachineScaleSetPublicIPAddress(ctx, resourceGroupName, virtualMachineScaleSetName, virtualmachineIndex, pipID.NetworkInterfaceName, pipID.IpConfigurationName, pipID.PublicIPAddressName, "") + if err != nil { + return nil, fmt.Errorf("reading Public IP Address for VM Instance %q for Virtual Machine Scale Set %q (Resource Group %q): %+v", virtualmachineIndex, virtualMachineScaleSetName, resourceGroupName, err) + } + + if *nic.Primary && *props.Primary { + primaryPublicAddress = *publicIPAddress.IPAddress + } + publicIPAddresses = append(publicIPAddresses, *publicIPAddress.IPAddress) + } + + if props.PrivateIPAddress != nil { + if *nic.Primary && *props.Primary { + primaryPrivateAddress = *props.PrivateIPAddress + } + privateIPAddresses = append(privateIPAddresses, *props.PrivateIPAddress) + } + } + } + } + + if primaryPublicAddress == "" && len(publicIPAddresses) > 0 { + primaryPublicAddress = publicIPAddresses[0] + } + + if primaryPrivateAddress == "" && len(privateIPAddresses) > 0 { + primaryPrivateAddress = privateIPAddresses[0] + } + + return &connectionInfo{ + primaryPublicAddress: primaryPublicAddress, + publicAddresses: publicIPAddresses, + primaryPrivateAddress: primaryPrivateAddress, + privateAddresses: privateIPAddresses, + }, nil +} + +func flattenVirtualMachineScaleSetVM(input compute.VirtualMachineScaleSetVM, connectionInfo *connectionInfo) map[string]interface{} { + output := make(map[string]interface{}) + output["name"] = *input.Name + output["instance_id"] = *input.InstanceID + output["latest_model_applied"] = *input.LatestModelApplied + output["virtual_machine_id"] = *input.VMID + + props := *input.VirtualMachineScaleSetVMProperties + if profile := props.OsProfile; profile != nil { + output["computer_name"] = profile.ComputerName + } + + zone := "" + if input.Zones != nil { + if zones := *input.Zones; len(zones) > 0 { + zone = zones[0] + } + } + output["zone"] = zone + + if connectionInfo != nil { + output["private_ip_address"] = connectionInfo.primaryPrivateAddress + output["private_ip_addresses"] = connectionInfo.privateAddresses + output["public_ip_address"] = connectionInfo.primaryPublicAddress + output["public_ip_addresses"] = connectionInfo.publicAddresses + } + + return output +} diff --git a/internal/services/compute/virtual_machine_scale_set_data_source_test.go b/internal/services/compute/virtual_machine_scale_set_data_source_test.go index 385f5d0c66e9..539aaef08dff 100644 --- a/internal/services/compute/virtual_machine_scale_set_data_source_test.go +++ b/internal/services/compute/virtual_machine_scale_set_data_source_test.go @@ -21,6 +21,9 @@ func TestAccDataSourceVirtualMachineScaleSet_basicLinux(t *testing.T) { check.That(data.ResourceName).Key("identity.#").HasValue("1"), check.That(data.ResourceName).Key("identity.0.type").HasValue("SystemAssigned"), check.That(data.ResourceName).Key("identity.0.principal_id").Exists(), + check.That(data.ResourceName).Key("instances.#").HasValue("1"), + check.That(data.ResourceName).Key("instances.0.instance_id").HasValue("0"), + check.That(data.ResourceName).Key("instances.0.private_ip_address").HasValue("10.0.2.4"), ), }, }) diff --git a/internal/services/compute/virtual_machine_scale_set_extension_resource.go b/internal/services/compute/virtual_machine_scale_set_extension_resource.go index 21f653ade4f2..d023c04909d3 100644 --- a/internal/services/compute/virtual_machine_scale_set_extension_resource.go +++ b/internal/services/compute/virtual_machine_scale_set_extension_resource.go @@ -39,10 +39,13 @@ func resourceVirtualMachineScaleSetExtension() *pluginsdk.Resource { Schema: map[string]*pluginsdk.Schema{ "name": { - Type: pluginsdk.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validation.StringIsNotEmpty, + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.All( + validation.StringIsNotEmpty, + validation.StringDoesNotContainAny("/"), + ), }, "virtual_machine_scale_set_id": { diff --git a/internal/services/compute/windows_virtual_machine_resource.go b/internal/services/compute/windows_virtual_machine_resource.go index 0a68f6a74a16..1bdd33e700ee 100644 --- a/internal/services/compute/windows_virtual_machine_resource.go +++ b/internal/services/compute/windows_virtual_machine_resource.go @@ -12,6 +12,9 @@ import ( "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/availabilitysets" + "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhostgroups" + "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhosts" + "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/proximityplacementgroups" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" azValidate "github.com/hashicorp/terraform-provider-azurerm/helpers/validate" @@ -151,7 +154,7 @@ func resourceWindowsVirtualMachine() *pluginsdk.Resource { "dedicated_host_id": { Type: pluginsdk.TypeString, Optional: true, - ValidateFunc: computeValidate.DedicatedHostID, + ValidateFunc: dedicatedhosts.ValidateHostID, // the Compute/VM API is broken and returns the Resource Group name in UPPERCASE :shrug: // tracked by https://github.com/Azure/azure-rest-api-specs/issues/19424 DiffSuppressFunc: suppress.CaseDifference, @@ -163,7 +166,7 @@ func resourceWindowsVirtualMachine() *pluginsdk.Resource { "dedicated_host_group_id": { Type: pluginsdk.TypeString, Optional: true, - ValidateFunc: computeValidate.DedicatedHostGroupID, + ValidateFunc: dedicatedhostgroups.ValidateHostGroupID, // the Compute/VM API is broken and returns the Resource Group name in UPPERCASE // tracked by https://github.com/Azure/azure-rest-api-specs/issues/19424 DiffSuppressFunc: suppress.CaseDifference, @@ -193,8 +196,8 @@ func resourceWindowsVirtualMachine() *pluginsdk.Resource { Optional: true, ForceNew: true, ValidateFunc: validation.StringInSlice([]string{ - // NOTE: whilst Delete is an option here, it's only applicable for VMSS string(compute.VirtualMachineEvictionPolicyTypesDeallocate), + string(compute.VirtualMachineEvictionPolicyTypesDelete), }, false), }, @@ -271,7 +274,7 @@ func resourceWindowsVirtualMachine() *pluginsdk.Resource { "proximity_placement_group_id": { Type: pluginsdk.TypeString, Optional: true, - ValidateFunc: computeValidate.ProximityPlacementGroupID, + ValidateFunc: proximityplacementgroups.ValidateProximityPlacementGroupID, // the Compute/VM API is broken and returns the Resource Group name in UPPERCASE :shrug: // tracked by https://github.com/Azure/azure-rest-api-specs/issues/19424 DiffSuppressFunc: suppress.CaseDifference, diff --git a/internal/services/compute/windows_virtual_machine_resource_disk_os_test.go b/internal/services/compute/windows_virtual_machine_resource_disk_os_test.go index 16261a27a83c..8fa9c294d283 100644 --- a/internal/services/compute/windows_virtual_machine_resource_disk_os_test.go +++ b/internal/services/compute/windows_virtual_machine_resource_disk_os_test.go @@ -156,6 +156,21 @@ func TestAccWindowsVirtualMachine_diskOSEphemeralDefault(t *testing.T) { }) } +func TestAccWindowsVirtualMachine_diskOSEphemeralSpot(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_windows_virtual_machine", "test") + r := WindowsVirtualMachineResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.diskOSEphemeralSpot(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("admin_password"), + }) +} + func TestAccWindowsVirtualMachine_diskOSEphemeralResourceDisk(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_windows_virtual_machine", "test") r := WindowsVirtualMachineResource{} @@ -709,6 +724,43 @@ resource "azurerm_windows_virtual_machine" "test" { `, r.template(data)) } +func (r WindowsVirtualMachineResource) diskOSEphemeralSpot(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_windows_virtual_machine" "test" { + name = local.vm_name + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + # Message="OS disk of Ephemeral VM with size greater than 32 GB is not allowed for VM size Standard_F2s_v2" + size = "Standard_DS3_v2" + admin_username = "adminuser" + admin_password = "P@$$w0rd1234!" + priority = "Spot" + eviction_policy = "Delete" + network_interface_ids = [ + azurerm_network_interface.test.id, + ] + + os_disk { + caching = "ReadOnly" + storage_account_type = "Standard_LRS" + + diff_disk_settings { + option = "Local" + } + } + + source_image_reference { + publisher = "MicrosoftWindowsServer" + offer = "WindowsServer" + sku = "2016-Datacenter" + version = "latest" + } +} +`, r.template(data)) +} + func (r WindowsVirtualMachineResource) diskOSEphemeralResourceDisk(data acceptance.TestData) string { return fmt.Sprintf(` %s diff --git a/internal/services/consumption/client/client.go b/internal/services/consumption/client/client.go index 04040a0d9dd1..e867b6340157 100644 --- a/internal/services/consumption/client/client.go +++ b/internal/services/consumption/client/client.go @@ -1,16 +1,16 @@ package client import ( - "github.com/Azure/azure-sdk-for-go/services/consumption/mgmt/2019-10-01/consumption" + "github.com/hashicorp/go-azure-sdk/resource-manager/consumption/2019-10-01/budgets" "github.com/hashicorp/terraform-provider-azurerm/internal/common" ) type Client struct { - BudgetsClient *consumption.BudgetsClient + BudgetsClient *budgets.BudgetsClient } func NewClient(o *common.ClientOptions) *Client { - budgetsClient := consumption.NewBudgetsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + budgetsClient := budgets.NewBudgetsClientWithBaseURI(o.ResourceManagerEndpoint) o.ConfigureClient(&budgetsClient.Client, o.ResourceManagerAuthorizer) return &Client{ diff --git a/internal/services/consumption/consumption_budget_base.go b/internal/services/consumption/consumption_budget_base.go index 25ac88c1d9c8..72ff97aa075b 100644 --- a/internal/services/consumption/consumption_budget_base.go +++ b/internal/services/consumption/consumption_budget_base.go @@ -5,16 +5,15 @@ import ( "fmt" "time" - "github.com/Azure/azure-sdk-for-go/services/consumption/mgmt/2019-10-01/consumption" "github.com/Azure/go-autorest/autorest/date" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/consumption/2019-10-01/budgets" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/consumption/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/consumption/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/utils" - "github.com/shopspring/decimal" ) type consumptionBudgetBaseResource struct{} @@ -227,10 +226,10 @@ func (br consumptionBudgetBaseResource) arguments(fields map[string]*pluginsdk.S "threshold_type": { Type: pluginsdk.TypeString, Optional: true, - Default: string(consumption.ThresholdTypeActual), + Default: string(budgets.ThresholdTypeActual), ForceNew: true, // TODO: remove this when the above issue is fixed ValidateFunc: validation.StringInSlice([]string{ - string(consumption.ThresholdTypeActual), + string(budgets.ThresholdTypeActual), "Forecasted", }, false), }, @@ -238,9 +237,9 @@ func (br consumptionBudgetBaseResource) arguments(fields map[string]*pluginsdk.S Type: pluginsdk.TypeString, Required: true, ValidateFunc: validation.StringInSlice([]string{ - string(consumption.OperatorTypeEqualTo), - string(consumption.OperatorTypeGreaterThan), - string(consumption.OperatorTypeGreaterThanOrEqualTo), + string(budgets.OperatorTypeEqualTo), + string(budgets.OperatorTypeGreaterThan), + string(budgets.OperatorTypeGreaterThanOrEqualTo), }, false), }, @@ -277,15 +276,15 @@ func (br consumptionBudgetBaseResource) arguments(fields map[string]*pluginsdk.S "time_grain": { Type: pluginsdk.TypeString, Optional: true, - Default: string(consumption.TimeGrainTypeMonthly), + Default: string(budgets.TimeGrainTypeMonthly), ForceNew: true, ValidateFunc: validation.StringInSlice([]string{ - string(consumption.TimeGrainTypeBillingAnnual), - string(consumption.TimeGrainTypeBillingMonth), - string(consumption.TimeGrainTypeBillingQuarter), - string(consumption.TimeGrainTypeAnnually), - string(consumption.TimeGrainTypeMonthly), - string(consumption.TimeGrainTypeQuarterly), + string(budgets.TimeGrainTypeBillingAnnual), + string(budgets.TimeGrainTypeBillingMonth), + string(budgets.TimeGrainTypeBillingQuarter), + string(budgets.TimeGrainTypeAnnually), + string(budgets.TimeGrainTypeMonthly), + string(budgets.TimeGrainTypeQuarterly), }, false), }, @@ -334,16 +333,16 @@ func (br consumptionBudgetBaseResource) createFunc(resourceName, scopeFieldName var err error scope := metadata.ResourceData.Get(scopeFieldName).(string) - id := parse.NewConsumptionBudgetId(scope, metadata.ResourceData.Get("name").(string)) + id := budgets.NewScopedBudgetID(scope, metadata.ResourceData.Get("name").(string)) - existing, err := client.Get(ctx, id.Scope, id.Name) + existing, err := client.Get(ctx, id) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return fmt.Errorf("checking for presence of existing %s: %+v", id, err) } } - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return tf.ImportAsExistsError(resourceName, id.ID()) } @@ -362,38 +361,38 @@ func (br consumptionBudgetBaseResource) readFunc(scopeFieldName string) sdk.Reso Timeout: 5 * time.Minute, Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { client := metadata.Client.Consumption.BudgetsClient - id, err := parse.ConsumptionBudgetID(metadata.ResourceData.Id()) + id, err := budgets.ParseScopedBudgetID(metadata.ResourceData.Id()) if err != nil { return err } - resp, err := client.Get(ctx, id.Scope, id.Name) + resp, err := client.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { return metadata.MarkAsGone(id) } return fmt.Errorf("reading %s, %+v", *id, err) } - metadata.ResourceData.Set("name", id.Name) + metadata.ResourceData.Set("name", id.BudgetName) //lintignore:R001 metadata.ResourceData.Set(scopeFieldName, id.Scope) - amount := 0.0 - if v := resp.Amount; v != nil { - amount, _ = v.Float64() - } - metadata.ResourceData.Set("amount", amount) - - eTag := "" - if v := resp.ETag; v != nil { - eTag = *v + if model := resp.Model; model != nil { + eTag := "" + if v := model.ETag; v != nil { + eTag = *v + } + metadata.ResourceData.Set("etag", eTag) + + if props := model.Properties; props != nil { + metadata.ResourceData.Set("amount", props.Amount) + metadata.ResourceData.Set("time_grain", string(props.TimeGrain)) + metadata.ResourceData.Set("time_period", flattenConsumptionBudgetTimePeriod(&props.TimePeriod)) + metadata.ResourceData.Set("notification", flattenConsumptionBudgetNotifications(props.Notifications, scopeFieldName)) + metadata.ResourceData.Set("filter", flattenConsumptionBudgetFilter(props.Filter)) + } } - metadata.ResourceData.Set("etag", eTag) - metadata.ResourceData.Set("time_grain", string(resp.TimeGrain)) - metadata.ResourceData.Set("time_period", flattenConsumptionBudgetTimePeriod(resp.TimePeriod)) - metadata.ResourceData.Set("notification", flattenConsumptionBudgetNotifications(resp.Notifications, scopeFieldName)) - metadata.ResourceData.Set("filter", flattenConsumptionBudgetFilter(resp.Filter)) return nil }, @@ -405,12 +404,12 @@ func (br consumptionBudgetBaseResource) deleteFunc() sdk.ResourceFunc { Timeout: 30 * time.Minute, Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { client := metadata.Client.Consumption.BudgetsClient - id, err := parse.ConsumptionBudgetID(metadata.ResourceData.Id()) + id, err := budgets.ParseScopedBudgetID(metadata.ResourceData.Id()) if err != nil { return err } - if _, err = client.Delete(ctx, id.Scope, id.Name); err != nil { + if _, err = client.Delete(ctx, *id); err != nil { return fmt.Errorf("deleting %s: %+v", *id, err) } @@ -425,7 +424,7 @@ func (br consumptionBudgetBaseResource) updateFunc() sdk.ResourceFunc { Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { client := metadata.Client.Consumption.BudgetsClient - id, err := parse.ConsumptionBudgetID(metadata.ResourceData.Id()) + id, err := budgets.ParseScopedBudgetID(metadata.ResourceData.Id()) if err != nil { return err } @@ -439,33 +438,18 @@ func (br consumptionBudgetBaseResource) updateFunc() sdk.ResourceFunc { } } -func (br consumptionBudgetBaseResource) importerFunc(expectScope string) sdk.ResourceRunFunc { +func (br consumptionBudgetBaseResource) importerFunc() sdk.ResourceRunFunc { return func(ctx context.Context, metadata sdk.ResourceMetaData) error { - var err error - id, err := parse.ConsumptionBudgetID(metadata.ResourceData.Id()) + _, err := budgets.ParseScopedBudgetID(metadata.ResourceData.Id()) if err != nil { return err } - switch expectScope { - case "subscription": - _, err = parse.ConsumptionBudgetSubscriptionID(metadata.ResourceData.Id()) - case "resource_group": - _, err = parse.ConsumptionBudgetResourceGroupID(metadata.ResourceData.Id()) - case "management_group": - _, err = parse.ConsumptionBudgetManagementGroupID(metadata.ResourceData.Id()) - } - - if err != nil { - return fmt.Errorf("budget has mismatched scope, expected a budget with %s scope, got %s", expectScope, id.Scope) - } - return nil } } -func createOrUpdateConsumptionBudget(ctx context.Context, client *consumption.BudgetsClient, metadata sdk.ResourceMetaData, id parse.ConsumptionBudgetId) error { - amount := decimal.NewFromFloat(metadata.ResourceData.Get("amount").(float64)) +func createOrUpdateConsumptionBudget(ctx context.Context, client *budgets.BudgetsClient, metadata sdk.ResourceMetaData, id budgets.ScopedBudgetId) error { timePeriod, err := expandConsumptionBudgetTimePeriod(metadata.ResourceData.Get("time_period").([]interface{})) if err != nil { return fmt.Errorf("expanding `time_period`: %+v", err) @@ -473,16 +457,16 @@ func createOrUpdateConsumptionBudget(ctx context.Context, client *consumption.Bu // The Consumption Budget API requires the category type field to be set in a budget's properties. // 'Cost' is the only valid Budget type today according to the API spec. - category := "Cost" - parameters := consumption.Budget{ - Name: utils.String(id.Name), - BudgetProperties: &consumption.BudgetProperties{ - Amount: &amount, - Category: &category, + + parameters := budgets.Budget{ + Name: utils.String(id.BudgetName), + Properties: &budgets.BudgetProperties{ + Amount: metadata.ResourceData.Get("amount").(float64), + Category: budgets.CategoryTypeCost, Filter: expandConsumptionBudgetFilter(metadata.ResourceData.Get("filter").([]interface{})), Notifications: expandConsumptionBudgetNotifications(metadata.ResourceData.Get("notification").(*pluginsdk.Set).List()), - TimeGrain: consumption.TimeGrainType(metadata.ResourceData.Get("time_grain").(string)), - TimePeriod: timePeriod, + TimeGrain: budgets.TimeGrainType(metadata.ResourceData.Get("time_grain").(string)), + TimePeriod: *timePeriod, }, } @@ -490,7 +474,7 @@ func createOrUpdateConsumptionBudget(ctx context.Context, client *consumption.Bu parameters.ETag = utils.String(v.(string)) } - _, err = client.CreateOrUpdate(ctx, id.Scope, id.Name, parameters) + _, err = client.CreateOrUpdate(ctx, id, parameters) if err != nil { return err } @@ -498,56 +482,48 @@ func createOrUpdateConsumptionBudget(ctx context.Context, client *consumption.Bu return nil } -func expandConsumptionBudgetTimePeriod(i []interface{}) (*consumption.BudgetTimePeriod, error) { +func expandConsumptionBudgetTimePeriod(i []interface{}) (*budgets.BudgetTimePeriod, error) { if len(i) == 0 || i[0] == nil { return nil, nil } input := i[0].(map[string]interface{}) - timePeriod := consumption.BudgetTimePeriod{} + timePeriod := budgets.BudgetTimePeriod{} if startDateInput, ok := input["start_date"].(string); ok { - startDate, err := date.ParseTime(time.RFC3339, startDateInput) + _, err := date.ParseTime(time.RFC3339, startDateInput) if err != nil { return nil, fmt.Errorf("start_date '%s' was not in the correct format: %+v", startDateInput, err) } - - timePeriod.StartDate = &date.Time{ - Time: startDate, - } + timePeriod.StartDate = input["start_date"].(string) } if endDateInput, ok := input["end_date"].(string); ok { if endDateInput != "" { - endDate, err := date.ParseTime(time.RFC3339, endDateInput) + _, err := date.ParseTime(time.RFC3339, endDateInput) if err != nil { return nil, fmt.Errorf("end_date '%s' was not in the correct format: %+v", endDateInput, err) } - timePeriod.EndDate = &date.Time{ - Time: endDate, - } + timePeriod.EndDate = utils.String(input["end_date"].(string)) } } return &timePeriod, nil } -func flattenConsumptionBudgetTimePeriod(input *consumption.BudgetTimePeriod) []interface{} { +func flattenConsumptionBudgetTimePeriod(input *budgets.BudgetTimePeriod) []interface{} { timePeriod := make([]interface{}, 0) if input == nil { return timePeriod } - startDate := "" - if v := input.StartDate; v != nil { - startDate = v.String() - } + startDate := input.StartDate endDate := "" if v := input.EndDate; v != nil { - endDate = v.String() + endDate = *v } return append(timePeriod, map[string]interface{}{ @@ -556,27 +532,28 @@ func flattenConsumptionBudgetTimePeriod(input *consumption.BudgetTimePeriod) []i }) } -func expandConsumptionBudgetNotifications(input []interface{}) map[string]*consumption.Notification { +func expandConsumptionBudgetNotifications(input []interface{}) *map[string]budgets.Notification { if len(input) == 0 { return nil } - notifications := make(map[string]*consumption.Notification) + notifications := make(map[string]budgets.Notification) for _, v := range input { if v != nil { notificationRaw := v.(map[string]interface{}) - notification := consumption.Notification{} + notification := budgets.Notification{} - notification.Enabled = utils.Bool(notificationRaw["enabled"].(bool)) - notification.Operator = consumption.OperatorType(notificationRaw["operator"].(string)) + notification.Enabled = notificationRaw["enabled"].(bool) + notification.Operator = budgets.OperatorType(notificationRaw["operator"].(string)) - thresholdDecimal := decimal.NewFromInt(int64(notificationRaw["threshold"].(int))) - notification.Threshold = &thresholdDecimal + notification.Threshold = float64(notificationRaw["threshold"].(int)) - notification.ThresholdType = consumption.ThresholdType(notificationRaw["threshold_type"].(string)) + thresholdType := budgets.ThresholdType(notificationRaw["threshold_type"].(string)) + notification.ThresholdType = &thresholdType - notification.ContactEmails = utils.ExpandStringSlice(notificationRaw["contact_emails"].([]interface{})) + contactEmails := utils.ExpandStringSlice(notificationRaw["contact_emails"].([]interface{})) + notification.ContactEmails = *contactEmails // contact_roles cannot be set on consumption budgets for management groups if _, ok := notificationRaw["contact_roles"]; ok { @@ -588,110 +565,98 @@ func expandConsumptionBudgetNotifications(input []interface{}) map[string]*consu notification.ContactGroups = utils.ExpandStringSlice(notificationRaw["contact_groups"].([]interface{})) } - notificationKey := fmt.Sprintf("actual_%s_%s_Percent", string(notification.Operator), notification.Threshold.StringFixed(0)) - notifications[notificationKey] = ¬ification + notificationKey := fmt.Sprintf("actual_%s_%f_Percent", string(notification.Operator), notification.Threshold) + notifications[notificationKey] = notification } } - return notifications + return ¬ifications } -func flattenConsumptionBudgetNotifications(input map[string]*consumption.Notification, scope string) []interface{} { +func flattenConsumptionBudgetNotifications(input *map[string]budgets.Notification, scope string) []interface{} { if input == nil { return []interface{}{} } notifications := make([]interface{}, 0) - for _, n := range input { - if n != nil { - block := make(map[string]interface{}) - - enabled := true - if v := n.Enabled; v != nil && !*v { - enabled = false - } - block["enabled"] = enabled + for _, n := range *input { + block := make(map[string]interface{}) - operator := "" - if v := n.Operator; v != "" { - operator = string(v) - } - block["operator"] = operator + block["enabled"] = n.Enabled - threshold := 0 - if v := n.Threshold; v != nil { - t, _ := v.Float64() - threshold = int(t) - } - block["threshold"] = threshold + operator := "" + if v := n.Operator; v != "" { + operator = string(v) + } + block["operator"] = operator - thresholdType := string(consumption.ThresholdTypeActual) - if v := n.ThresholdType; v != consumption.ThresholdTypeActual { - t := v - thresholdType = string(t) - } - block["threshold_type"] = thresholdType + block["threshold"] = n.Threshold - var emails []interface{} - if v := n.ContactEmails; v != nil { - emails = utils.FlattenStringSlice(v) - } - block["contact_emails"] = emails + thresholdType := string(budgets.ThresholdTypeActual) + if v := n.ThresholdType; v != nil { + thresholdType = string(*v) + } + block["threshold_type"] = thresholdType - if scope != "management_group_id" { - var roles []interface{} - if v := n.ContactRoles; v != nil { - roles = utils.FlattenStringSlice(v) - } - block["contact_roles"] = roles + var emails []interface{} + if v := n.ContactEmails; v != nil { + emails = utils.FlattenStringSlice(&v) + } + block["contact_emails"] = emails - var groups []interface{} - if v := n.ContactGroups; v != nil { - groups = utils.FlattenStringSlice(v) - } - block["contact_groups"] = groups + if scope != "management_group_id" { + var roles []interface{} + if v := n.ContactRoles; v != nil { + roles = utils.FlattenStringSlice(v) } + block["contact_roles"] = roles - notifications = append(notifications, block) + var groups []interface{} + if v := n.ContactGroups; v != nil { + groups = utils.FlattenStringSlice(v) + } + block["contact_groups"] = groups } + + notifications = append(notifications, block) } return notifications } -func expandConsumptionBudgetComparisonExpression(input interface{}) *consumption.BudgetComparisonExpression { +func expandConsumptionBudgetComparisonExpression(input interface{}) *budgets.BudgetComparisonExpression { if input == nil { return nil } v := input.(map[string]interface{}) - return &consumption.BudgetComparisonExpression{ - Name: utils.String(v["name"].(string)), - Operator: utils.String(v["operator"].(string)), - Values: utils.ExpandStringSlice(v["values"].([]interface{})), + return &budgets.BudgetComparisonExpression{ + Name: v["name"].(string), + Operator: budgets.BudgetOperatorType(v["operator"].(string)), + Values: *utils.ExpandStringSlice(v["values"].([]interface{})), } } -func flattenConsumptionBudgetComparisonExpression(input *consumption.BudgetComparisonExpression) *map[string]interface{} { +func flattenConsumptionBudgetComparisonExpression(input *budgets.BudgetComparisonExpression) *map[string]interface{} { consumptionBudgetComparisonExpression := make(map[string]interface{}) consumptionBudgetComparisonExpression["name"] = input.Name consumptionBudgetComparisonExpression["operator"] = input.Operator - consumptionBudgetComparisonExpression["values"] = utils.FlattenStringSlice(input.Values) + consumptionBudgetComparisonExpression["values"] = utils.FlattenStringSlice(&input.Values) return &consumptionBudgetComparisonExpression } -func expandConsumptionBudgetFilterDimensions(input []interface{}) []consumption.BudgetFilterProperties { +func expandConsumptionBudgetFilterDimensions(input []interface{}) []budgets.BudgetFilterProperties { if len(input) == 0 { return nil } - dimensions := make([]consumption.BudgetFilterProperties, 0) + dimensions := make([]budgets.BudgetFilterProperties, 0) for _, v := range input { - dimension := consumption.BudgetFilterProperties{ + dimension := budgets.BudgetFilterProperties{ Dimensions: expandConsumptionBudgetComparisonExpression(v), } dimensions = append(dimensions, dimension) @@ -700,15 +665,15 @@ func expandConsumptionBudgetFilterDimensions(input []interface{}) []consumption. return dimensions } -func expandConsumptionBudgetFilterTag(input []interface{}) []consumption.BudgetFilterProperties { +func expandConsumptionBudgetFilterTag(input []interface{}) []budgets.BudgetFilterProperties { if len(input) == 0 { return nil } - tags := make([]consumption.BudgetFilterProperties, 0) + tags := make([]budgets.BudgetFilterProperties, 0) for _, v := range input { - tag := consumption.BudgetFilterProperties{ + tag := budgets.BudgetFilterProperties{ Tags: expandConsumptionBudgetComparisonExpression(v), } @@ -718,13 +683,13 @@ func expandConsumptionBudgetFilterTag(input []interface{}) []consumption.BudgetF return tags } -func expandConsumptionBudgetFilter(i []interface{}) *consumption.BudgetFilter { +func expandConsumptionBudgetFilter(i []interface{}) *budgets.BudgetFilter { if len(i) == 0 || i[0] == nil { return nil } input := i[0].(map[string]interface{}) - filter := consumption.BudgetFilter{} + filter := budgets.BudgetFilter{} notBlock := input["not"].([]interface{}) if len(notBlock) != 0 && notBlock[0] != nil { @@ -768,7 +733,7 @@ func expandConsumptionBudgetFilter(i []interface{}) *consumption.BudgetFilter { return &filter } -func flattenConsumptionBudgetFilter(input *consumption.BudgetFilter) []interface{} { +func flattenConsumptionBudgetFilter(input *budgets.BudgetFilter) []interface{} { filter := make([]interface{}, 0) if input == nil { diff --git a/internal/services/consumption/consumption_budget_management_group_resource.go b/internal/services/consumption/consumption_budget_management_group_resource.go index 41a8f9e3f0ae..f9a150d4dfc5 100644 --- a/internal/services/consumption/consumption_budget_management_group_resource.go +++ b/internal/services/consumption/consumption_budget_management_group_resource.go @@ -1,9 +1,8 @@ package consumption import ( - "github.com/Azure/azure-sdk-for-go/services/consumption/mgmt/2019-10-01/consumption" + "github.com/hashicorp/go-azure-sdk/resource-manager/consumption/2019-10-01/budgets" "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/consumption/validate" validateManagementGroup "github.com/hashicorp/terraform-provider-azurerm/internal/services/managementgroup/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" @@ -58,10 +57,10 @@ func (r ManagementGroupConsumptionBudget) Arguments() map[string]*pluginsdk.Sche "threshold_type": { Type: pluginsdk.TypeString, Optional: true, - Default: string(consumption.ThresholdTypeActual), + Default: string(budgets.ThresholdTypeActual), ForceNew: true, // TODO: remove this when the above issue is fixed ValidateFunc: validation.StringInSlice([]string{ - string(consumption.ThresholdTypeActual), + string(budgets.ThresholdTypeActual), "Forecasted", }, false), }, @@ -69,9 +68,9 @@ func (r ManagementGroupConsumptionBudget) Arguments() map[string]*pluginsdk.Sche Type: pluginsdk.TypeString, Required: true, ValidateFunc: validation.StringInSlice([]string{ - string(consumption.OperatorTypeEqualTo), - string(consumption.OperatorTypeGreaterThan), - string(consumption.OperatorTypeGreaterThanOrEqualTo), + string(budgets.OperatorTypeEqualTo), + string(budgets.OperatorTypeGreaterThan), + string(budgets.OperatorTypeGreaterThanOrEqualTo), }, false), }, @@ -104,7 +103,7 @@ func (r ManagementGroupConsumptionBudget) ResourceType() string { } func (r ManagementGroupConsumptionBudget) IDValidationFunc() pluginsdk.SchemaValidateFunc { - return validate.ConsumptionBudgetManagementGroupID + return budgets.ValidateScopedBudgetID } func (r ManagementGroupConsumptionBudget) Create() sdk.ResourceFunc { @@ -124,5 +123,5 @@ func (r ManagementGroupConsumptionBudget) Update() sdk.ResourceFunc { } func (r ManagementGroupConsumptionBudget) CustomImporter() sdk.ResourceRunFunc { - return r.base.importerFunc("management_group") + return r.base.importerFunc() } diff --git a/internal/services/consumption/consumption_budget_management_group_resource_test.go b/internal/services/consumption/consumption_budget_management_group_resource_test.go index cd6b1e513d96..db677cc469f2 100644 --- a/internal/services/consumption/consumption_budget_management_group_resource_test.go +++ b/internal/services/consumption/consumption_budget_management_group_resource_test.go @@ -6,10 +6,10 @@ import ( "testing" "time" + "github.com/hashicorp/go-azure-sdk/resource-manager/consumption/2019-10-01/budgets" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/consumption/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -109,17 +109,17 @@ func TestAccConsumptionBudgetManagementGroup_completeUpdate(t *testing.T) { } func (ConsumptionBudgetManagementGroupResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.ConsumptionBudgetID(state.ID) + id, err := budgets.ParseScopedBudgetID(state.ID) if err != nil { return nil, err } - resp, err := clients.Consumption.BudgetsClient.Get(ctx, id.Scope, id.Name) + resp, err := clients.Consumption.BudgetsClient.Get(ctx, *id) if err != nil { return nil, fmt.Errorf("retrieving %s: %v", *id, err) } - return utils.Bool(resp.BudgetProperties != nil), nil + return utils.Bool(resp.Model != nil), nil } func (ConsumptionBudgetManagementGroupResource) basic(data acceptance.TestData) string { diff --git a/internal/services/consumption/consumption_budget_resource_group_data_source.go b/internal/services/consumption/consumption_budget_resource_group_data_source.go index a72de7712429..b01c5f7f3b11 100644 --- a/internal/services/consumption/consumption_budget_resource_group_data_source.go +++ b/internal/services/consumption/consumption_budget_resource_group_data_source.go @@ -4,12 +4,12 @@ import ( "fmt" "time" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/consumption/2019-10-01/budgets" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/consumption/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/consumption/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" - "github.com/hashicorp/terraform-provider-azurerm/utils" ) func resourceArmConsumptionBudgetResourceGroupDataSource() *pluginsdk.Resource { @@ -223,28 +223,28 @@ func resourceArmConsumptionBudgetResourceGroupDataSourceRead(d *pluginsdk.Resour ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - id := parse.NewConsumptionBudgetId(d.Get("resource_group_id").(string), d.Get("name").(string)) + id := budgets.NewScopedBudgetID(d.Get("resource_group_id").(string), d.Get("name").(string)) d.SetId(id.ID()) - resp, err := client.Get(ctx, id.Scope, id.Name) + resp, err := client.Get(ctx, id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { d.SetId("") return nil } return fmt.Errorf("making read request on %s: %+v", id, err) } - d.Set("name", resp.Name) - if resp.Amount != nil { - amount, _ := resp.Amount.Float64() - d.Set("amount", amount) + d.Set("name", id.BudgetName) + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("amount", props.Amount) + d.Set("time_grain", string(props.TimeGrain)) + d.Set("time_period", flattenConsumptionBudgetTimePeriod(&props.TimePeriod)) + d.Set("notification", flattenConsumptionBudgetNotifications(props.Notifications, id.Scope)) + d.Set("filter", flattenConsumptionBudgetFilter(props.Filter)) + } } - d.Set("resource_group_id", id.Scope) - d.Set("time_grain", string(resp.TimeGrain)) - d.Set("time_period", flattenConsumptionBudgetTimePeriod(resp.TimePeriod)) - d.Set("notification", flattenConsumptionBudgetNotifications(resp.Notifications, id.Scope)) - d.Set("filter", flattenConsumptionBudgetFilter(resp.Filter)) return nil } diff --git a/internal/services/consumption/consumption_budget_resource_group_resource.go b/internal/services/consumption/consumption_budget_resource_group_resource.go index af2cf8039740..6f22756a783d 100644 --- a/internal/services/consumption/consumption_budget_resource_group_resource.go +++ b/internal/services/consumption/consumption_budget_resource_group_resource.go @@ -1,8 +1,8 @@ package consumption import ( + "github.com/hashicorp/go-azure-sdk/resource-manager/consumption/2019-10-01/budgets" "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/consumption/validate" validateResourceGroup "github.com/hashicorp/terraform-provider-azurerm/internal/services/resource/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" @@ -48,7 +48,7 @@ func (r ResourceGroupConsumptionBudget) ResourceType() string { } func (r ResourceGroupConsumptionBudget) IDValidationFunc() pluginsdk.SchemaValidateFunc { - return validate.ConsumptionBudgetResourceGroupID + return budgets.ValidateScopedBudgetID } func (r ResourceGroupConsumptionBudget) Create() sdk.ResourceFunc { @@ -68,5 +68,5 @@ func (r ResourceGroupConsumptionBudget) Update() sdk.ResourceFunc { } func (r ResourceGroupConsumptionBudget) CustomImporter() sdk.ResourceRunFunc { - return r.base.importerFunc("resource_group") + return r.base.importerFunc() } diff --git a/internal/services/consumption/consumption_budget_resource_group_resource_test.go b/internal/services/consumption/consumption_budget_resource_group_resource_test.go index 95061df52b20..ce902879d9e9 100644 --- a/internal/services/consumption/consumption_budget_resource_group_resource_test.go +++ b/internal/services/consumption/consumption_budget_resource_group_resource_test.go @@ -6,10 +6,10 @@ import ( "testing" "time" + "github.com/hashicorp/go-azure-sdk/resource-manager/consumption/2019-10-01/budgets" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/consumption/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -121,17 +121,17 @@ func TestAccConsumptionBudgetResourceGroup_disappears(t *testing.T) { } func (ConsumptionBudgetResourceGroupResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.ConsumptionBudgetID(state.ID) + id, err := budgets.ParseScopedBudgetID(state.ID) if err != nil { return nil, err } - resp, err := clients.Consumption.BudgetsClient.Get(ctx, id.Scope, id.Name) + resp, err := clients.Consumption.BudgetsClient.Get(ctx, *id) if err != nil { return nil, fmt.Errorf("retrieving %s: %v", *id, err) } - return utils.Bool(resp.BudgetProperties != nil), nil + return utils.Bool(resp.Model != nil), nil } func (ConsumptionBudgetResourceGroupResource) basic(data acceptance.TestData) string { @@ -458,12 +458,12 @@ resource "azurerm_consumption_budget_resource_group" "test" { } func (t ConsumptionBudgetResourceGroupResource) Destroy(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.ConsumptionBudgetID(state.ID) + id, err := budgets.ParseScopedBudgetID(state.ID) if err != nil { return nil, err } - if _, err = client.Consumption.BudgetsClient.Delete(ctx, id.Scope, id.Name); err != nil { + if _, err = client.Consumption.BudgetsClient.Delete(ctx, *id); err != nil { return nil, fmt.Errorf("deleting %s: %+v", *id, err) } diff --git a/internal/services/consumption/consumption_budget_subscription_data_source.go b/internal/services/consumption/consumption_budget_subscription_data_source.go index 4c4424caa9b8..0ff13b8d753c 100644 --- a/internal/services/consumption/consumption_budget_subscription_data_source.go +++ b/internal/services/consumption/consumption_budget_subscription_data_source.go @@ -4,12 +4,12 @@ import ( "fmt" "time" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/consumption/2019-10-01/budgets" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/consumption/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/consumption/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" - "github.com/hashicorp/terraform-provider-azurerm/utils" ) func resourceArmConsumptionBudgetSubscriptionDataSource() *pluginsdk.Resource { @@ -223,27 +223,27 @@ func resourceArmConsumptionBudgetSubscriptionDataSourceRead(d *pluginsdk.Resourc ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - id := parse.NewConsumptionBudgetId(d.Get("subscription_id").(string), d.Get("name").(string)) + id := budgets.NewScopedBudgetID(d.Get("subscription_id").(string), d.Get("name").(string)) - resp, err := client.Get(ctx, id.Scope, id.Name) + resp, err := client.Get(ctx, id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { return fmt.Errorf("%s was not found", id) } return fmt.Errorf("retrieving %s: %+v", id, err) } d.SetId(id.ID()) - d.Set("name", id.Name) - d.Set("subscription_id", id.Scope) - if resp.Amount != nil { - amount, _ := resp.Amount.Float64() - d.Set("amount", amount) + d.Set("name", id.BudgetName) + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("amount", props.Amount) + d.Set("time_grain", string(props.TimeGrain)) + d.Set("time_period", flattenConsumptionBudgetTimePeriod(&props.TimePeriod)) + d.Set("notification", flattenConsumptionBudgetNotifications(props.Notifications, id.Scope)) + d.Set("filter", flattenConsumptionBudgetFilter(props.Filter)) + } } - d.Set("time_grain", string(resp.TimeGrain)) - d.Set("time_period", flattenConsumptionBudgetTimePeriod(resp.TimePeriod)) - d.Set("notification", flattenConsumptionBudgetNotifications(resp.Notifications, id.Scope)) - d.Set("filter", flattenConsumptionBudgetFilter(resp.Filter)) return nil } diff --git a/internal/services/consumption/consumption_budget_subscription_resource.go b/internal/services/consumption/consumption_budget_subscription_resource.go index 3cd80093a024..ea8b696c6f87 100644 --- a/internal/services/consumption/consumption_budget_subscription_resource.go +++ b/internal/services/consumption/consumption_budget_subscription_resource.go @@ -2,9 +2,9 @@ package consumption import ( "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" + "github.com/hashicorp/go-azure-sdk/resource-manager/consumption/2019-10-01/budgets" "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" "github.com/hashicorp/terraform-provider-azurerm/internal/services/consumption/migration" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/consumption/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" ) @@ -50,7 +50,7 @@ func (r SubscriptionConsumptionBudget) ResourceType() string { } func (r SubscriptionConsumptionBudget) IDValidationFunc() pluginsdk.SchemaValidateFunc { - return validate.ConsumptionBudgetSubscriptionID + return budgets.ValidateScopedBudgetID } func (r SubscriptionConsumptionBudget) Create() sdk.ResourceFunc { @@ -70,7 +70,7 @@ func (r SubscriptionConsumptionBudget) Update() sdk.ResourceFunc { } func (r SubscriptionConsumptionBudget) CustomImporter() sdk.ResourceRunFunc { - return r.base.importerFunc("subscription") + return r.base.importerFunc() } func (r SubscriptionConsumptionBudget) StateUpgraders() sdk.StateUpgradeData { diff --git a/internal/services/consumption/consumption_budget_subscription_resource_test.go b/internal/services/consumption/consumption_budget_subscription_resource_test.go index 7617f005ef1f..2dcb87b63766 100644 --- a/internal/services/consumption/consumption_budget_subscription_resource_test.go +++ b/internal/services/consumption/consumption_budget_subscription_resource_test.go @@ -6,10 +6,10 @@ import ( "testing" "time" + "github.com/hashicorp/go-azure-sdk/resource-manager/consumption/2019-10-01/budgets" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/consumption/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -116,17 +116,17 @@ func TestAccConsumptionBudgetSubscription_completeUpdate(t *testing.T) { } func (ConsumptionBudgetSubscriptionResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.ConsumptionBudgetID(state.ID) + id, err := budgets.ParseScopedBudgetID(state.ID) if err != nil { return nil, err } - resp, err := clients.Consumption.BudgetsClient.Get(ctx, id.Scope, id.Name) + resp, err := clients.Consumption.BudgetsClient.Get(ctx, *id) if err != nil { return nil, fmt.Errorf("retrieving %s: %v", *id, err) } - return utils.Bool(resp.BudgetProperties != nil), nil + return utils.Bool(resp.Model != nil), nil } func (ConsumptionBudgetSubscriptionResource) basic(data acceptance.TestData) string { diff --git a/internal/services/consumption/migration/consumption_budget_subscription.go b/internal/services/consumption/migration/consumption_budget_subscription.go index c663acd5ea2c..93faacfb0b9d 100644 --- a/internal/services/consumption/migration/consumption_budget_subscription.go +++ b/internal/services/consumption/migration/consumption_budget_subscription.go @@ -6,7 +6,7 @@ import ( "log" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/consumption/parse" + "github.com/hashicorp/go-azure-sdk/resource-manager/consumption/2019-10-01/budgets" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" ) @@ -241,13 +241,13 @@ func (SubscriptionConsumptionBudgetV1ToV2) UpgradeFunc() pluginsdk.StateUpgrader // since the `subscription_id` field gets incorrectly mutated in the V0 -> V1 upgrade // we have to parse it from the ID instead to correct this idRaw := rawState["id"].(string) - id, err := parse.ConsumptionBudgetSubscriptionID(idRaw) + id, err := budgets.ParseScopedBudgetID(idRaw) if err != nil { return nil, fmt.Errorf("parsing %q: %+v", idRaw, err) } oldSubscriptionId := rawState["subscription_id"].(commonids.SubscriptionId) - newSubscriptionId := commonids.NewSubscriptionID(id.SubscriptionId).ID() + newSubscriptionId := commonids.NewSubscriptionID(id.Scope).ID() log.Printf("[DEBUG] Updating subscription_id from %q to %q", oldSubscriptionId, newSubscriptionId) rawState["subscription_id"] = newSubscriptionId diff --git a/internal/services/consumption/parse/consumption_budget.go b/internal/services/consumption/parse/consumption_budget.go deleted file mode 100644 index baf347fbb41c..000000000000 --- a/internal/services/consumption/parse/consumption_budget.go +++ /dev/null @@ -1,59 +0,0 @@ -package parse - -import ( - "fmt" - "regexp" - "strings" -) - -type ConsumptionBudgetId struct { - Name string - Scope string -} - -func (id ConsumptionBudgetId) String() string { - segments := []string{ - fmt.Sprintf("Consumption Budget Name %q", id.Name), - fmt.Sprintf("Scope %q", id.Scope), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Consumption Budget ID", segmentsStr) -} - -func (id ConsumptionBudgetId) ID() string { - fmtString := "%s/providers/Microsoft.Consumption/budgets/%s" - return fmt.Sprintf(fmtString, id.Scope, id.Name) -} - -func NewConsumptionBudgetId(scope, name string) ConsumptionBudgetId { - return ConsumptionBudgetId{ - Name: name, - Scope: scope, - } -} - -func ConsumptionBudgetID(input string) (*ConsumptionBudgetId, error) { - // in general, the id of a budget should be: - // {scope}/providers/Microsoft.Consumption/budgets/{name} - regex := regexp.MustCompile(`/providers/Microsoft\.Consumption/budgets/`) - if !regex.MatchString(input) { - return nil, fmt.Errorf("unable to parse Consumption Budget ID %q", input) - } - - segments := regex.Split(input, -1) - - if len(segments) != 2 { - return nil, fmt.Errorf("unable to parse Consumption Budget ID %q: Expected 2 segments after split", input) - } - - scope := segments[0] - name := segments[1] - if name == "" { - return nil, fmt.Errorf("unable to parse Consumption Budget ID %q: budget name is empty", input) - } - - return &ConsumptionBudgetId{ - Name: name, - Scope: scope, - }, nil -} diff --git a/internal/services/consumption/parse/consumption_budget_management_group.go b/internal/services/consumption/parse/consumption_budget_management_group.go deleted file mode 100644 index aec534efaba8..000000000000 --- a/internal/services/consumption/parse/consumption_budget_management_group.go +++ /dev/null @@ -1,58 +0,0 @@ -package parse - -import ( - "fmt" - "strings" - - "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" -) - -type ConsumptionBudgetManagementGroupId struct { - ManagementGroupName string - BudgetName string -} - -func NewConsumptionBudgetManagementGroupID(managementGroupName, budgetName string) ConsumptionBudgetManagementGroupId { - return ConsumptionBudgetManagementGroupId{ - ManagementGroupName: managementGroupName, - BudgetName: budgetName, - } -} - -func (id ConsumptionBudgetManagementGroupId) String() string { - segments := []string{ - fmt.Sprintf("Budget Name %q", id.BudgetName), - fmt.Sprintf("Management Group Name %q", id.ManagementGroupName), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Consumption Budget Management Group", segmentsStr) -} - -func (id ConsumptionBudgetManagementGroupId) ID() string { - fmtString := "/providers/Microsoft.Management/managementGroups/%s/providers/Microsoft.Consumption/budgets/%s" - return fmt.Sprintf(fmtString, id.ManagementGroupName, id.BudgetName) -} - -// ConsumptionBudgetManagementGroupID parses a ConsumptionBudgetManagementGroup ID into an ConsumptionBudgetManagementGroupId struct -func ConsumptionBudgetManagementGroupID(input string) (*ConsumptionBudgetManagementGroupId, error) { - id, err := azure.ParseAzureResourceIDWithoutSubscription(input) - if err != nil { - return nil, err - } - - resourceId := ConsumptionBudgetManagementGroupId{} - - if resourceId.ManagementGroupName, err = id.PopSegment("managementGroups"); err != nil { - return nil, err - } - - if resourceId.BudgetName, err = id.PopSegment("budgets"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/consumption/parse/consumption_budget_management_group_test.go b/internal/services/consumption/parse/consumption_budget_management_group_test.go deleted file mode 100644 index bb8f8db99d64..000000000000 --- a/internal/services/consumption/parse/consumption_budget_management_group_test.go +++ /dev/null @@ -1,93 +0,0 @@ -package parse - -import ( - "testing" - - "github.com/hashicorp/terraform-provider-azurerm/internal/resourceid" -) - -var _ resourceid.Formatter = ConsumptionBudgetManagementGroupId{} - -func TestConsumptionBudgetManagementGroupIDFormatter(t *testing.T) { - actual := NewConsumptionBudgetManagementGroupID("12345678-1234-9876-4563-123456789012", "budget1").ID() - expected := "/providers/Microsoft.Management/managementGroups/12345678-1234-9876-4563-123456789012/providers/Microsoft.Consumption/budgets/budget1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestConsumptionBudgetManagementGroupID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *ConsumptionBudgetManagementGroupId - }{ - { - // empty - Input: "", - Error: true, - }, - - { - // missing ManagementGroupName - Input: "/providers/Microsoft.Management/", - Error: true, - }, - - { - // missing value for ManagementGroupName - Input: "/providers/Microsoft.Management/managementGroups/", - Error: true, - }, - - { - // missing BudgetName - Input: "/providers/Microsoft.Management/managementGroups/12345678-1234-9876-4563-123456789012/providers/Microsoft.Consumption/", - Error: true, - }, - - { - // missing value for BudgetName - Input: "/providers/Microsoft.Management/managementGroups/12345678-1234-9876-4563-123456789012/providers/Microsoft.Consumption/budgets/", - Error: true, - }, - - { - // valid - Input: "/providers/Microsoft.Management/managementGroups/12345678-1234-9876-4563-123456789012/providers/Microsoft.Consumption/budgets/budget1", - Expected: &ConsumptionBudgetManagementGroupId{ - ManagementGroupName: "12345678-1234-9876-4563-123456789012", - BudgetName: "budget1", - }, - }, - - { - // upper-cased - Input: "/PROVIDERS/MICROSOFT.MANAGEMENT/MANAGEMENTGROUPS/12345678-1234-9876-4563-123456789012/PROVIDERS/MICROSOFT.CONSUMPTION/BUDGETS/BUDGET1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := ConsumptionBudgetManagementGroupID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.ManagementGroupName != v.Expected.ManagementGroupName { - t.Fatalf("Expected %q but got %q for ManagementGroupName", v.Expected.ManagementGroupName, actual.ManagementGroupName) - } - if actual.BudgetName != v.Expected.BudgetName { - t.Fatalf("Expected %q but got %q for BudgetName", v.Expected.BudgetName, actual.BudgetName) - } - } -} diff --git a/internal/services/consumption/parse/consumption_budget_resource_group.go b/internal/services/consumption/parse/consumption_budget_resource_group.go deleted file mode 100644 index df388b794ce4..000000000000 --- a/internal/services/consumption/parse/consumption_budget_resource_group.go +++ /dev/null @@ -1,69 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - "strings" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -type ConsumptionBudgetResourceGroupId struct { - SubscriptionId string - ResourceGroup string - BudgetName string -} - -func NewConsumptionBudgetResourceGroupID(subscriptionId, resourceGroup, budgetName string) ConsumptionBudgetResourceGroupId { - return ConsumptionBudgetResourceGroupId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourceGroup, - BudgetName: budgetName, - } -} - -func (id ConsumptionBudgetResourceGroupId) String() string { - segments := []string{ - fmt.Sprintf("Budget Name %q", id.BudgetName), - fmt.Sprintf("Resource Group %q", id.ResourceGroup), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Consumption Budget Resource Group", segmentsStr) -} - -func (id ConsumptionBudgetResourceGroupId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Consumption/budgets/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.BudgetName) -} - -// ConsumptionBudgetResourceGroupID parses a ConsumptionBudgetResourceGroup ID into an ConsumptionBudgetResourceGroupId struct -func ConsumptionBudgetResourceGroupID(input string) (*ConsumptionBudgetResourceGroupId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := ConsumptionBudgetResourceGroupId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - if resourceId.BudgetName, err = id.PopSegment("budgets"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/consumption/parse/consumption_budget_resource_group_test.go b/internal/services/consumption/parse/consumption_budget_resource_group_test.go deleted file mode 100644 index ede1b168497e..000000000000 --- a/internal/services/consumption/parse/consumption_budget_resource_group_test.go +++ /dev/null @@ -1,112 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "testing" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -var _ resourceids.Id = ConsumptionBudgetResourceGroupId{} - -func TestConsumptionBudgetResourceGroupIDFormatter(t *testing.T) { - actual := NewConsumptionBudgetResourceGroupID("12345678-1234-9876-4563-123456789012", "resGroup1", "budget1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Consumption/budgets/budget1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestConsumptionBudgetResourceGroupID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *ConsumptionBudgetResourceGroupId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - - { - // missing BudgetName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Consumption/", - Error: true, - }, - - { - // missing value for BudgetName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Consumption/budgets/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Consumption/budgets/budget1", - Expected: &ConsumptionBudgetResourceGroupId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - BudgetName: "budget1", - }, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.CONSUMPTION/BUDGETS/BUDGET1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := ConsumptionBudgetResourceGroupID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - if actual.BudgetName != v.Expected.BudgetName { - t.Fatalf("Expected %q but got %q for BudgetName", v.Expected.BudgetName, actual.BudgetName) - } - } -} diff --git a/internal/services/consumption/parse/consumption_budget_subscription.go b/internal/services/consumption/parse/consumption_budget_subscription.go deleted file mode 100644 index db1d04240515..000000000000 --- a/internal/services/consumption/parse/consumption_budget_subscription.go +++ /dev/null @@ -1,61 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - "strings" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -type ConsumptionBudgetSubscriptionId struct { - SubscriptionId string - BudgetName string -} - -func NewConsumptionBudgetSubscriptionID(subscriptionId, budgetName string) ConsumptionBudgetSubscriptionId { - return ConsumptionBudgetSubscriptionId{ - SubscriptionId: subscriptionId, - BudgetName: budgetName, - } -} - -func (id ConsumptionBudgetSubscriptionId) String() string { - segments := []string{ - fmt.Sprintf("Budget Name %q", id.BudgetName), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Consumption Budget Subscription", segmentsStr) -} - -func (id ConsumptionBudgetSubscriptionId) ID() string { - fmtString := "/subscriptions/%s/providers/Microsoft.Consumption/budgets/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.BudgetName) -} - -// ConsumptionBudgetSubscriptionID parses a ConsumptionBudgetSubscription ID into an ConsumptionBudgetSubscriptionId struct -func ConsumptionBudgetSubscriptionID(input string) (*ConsumptionBudgetSubscriptionId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := ConsumptionBudgetSubscriptionId{ - SubscriptionId: id.SubscriptionID, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.BudgetName, err = id.PopSegment("budgets"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/consumption/parse/consumption_budget_subscription_test.go b/internal/services/consumption/parse/consumption_budget_subscription_test.go deleted file mode 100644 index 117a25d64148..000000000000 --- a/internal/services/consumption/parse/consumption_budget_subscription_test.go +++ /dev/null @@ -1,96 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "testing" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -var _ resourceids.Id = ConsumptionBudgetSubscriptionId{} - -func TestConsumptionBudgetSubscriptionIDFormatter(t *testing.T) { - actual := NewConsumptionBudgetSubscriptionID("12345678-1234-9876-4563-123456789012", "budget1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/providers/Microsoft.Consumption/budgets/budget1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestConsumptionBudgetSubscriptionID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *ConsumptionBudgetSubscriptionId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing BudgetName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/providers/Microsoft.Consumption/", - Error: true, - }, - - { - // missing value for BudgetName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/providers/Microsoft.Consumption/budgets/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/providers/Microsoft.Consumption/budgets/budget1", - Expected: &ConsumptionBudgetSubscriptionId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - BudgetName: "budget1", - }, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/PROVIDERS/MICROSOFT.CONSUMPTION/BUDGETS/BUDGET1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := ConsumptionBudgetSubscriptionID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.BudgetName != v.Expected.BudgetName { - t.Fatalf("Expected %q but got %q for BudgetName", v.Expected.BudgetName, actual.BudgetName) - } - } -} diff --git a/internal/services/consumption/parse/consumption_budget_test.go b/internal/services/consumption/parse/consumption_budget_test.go deleted file mode 100644 index a420cd80f457..000000000000 --- a/internal/services/consumption/parse/consumption_budget_test.go +++ /dev/null @@ -1,80 +0,0 @@ -package parse - -import ( - "testing" -) - -func TestCostManagementExportID(t *testing.T) { - testData := []struct { - Name string - Input string - Error bool - Expected *ConsumptionBudgetId - }{ - { - Name: "empty", - Input: "", - Error: true, - }, - { - Name: "resource group consumption budget", - Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/foo/providers/Microsoft.Consumption/budgets/budget1", - Expected: &ConsumptionBudgetId{ - Name: "budget1", - Scope: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/foo", - }, - }, - { - Name: "resource group consumption budget but no name", - Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/foo/providers/Microsoft.Consumption/budgets/", - Error: true, - }, - { - Name: "subscription consumption budget", - Input: "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Consumption/budgets/budget1", - Expected: &ConsumptionBudgetId{ - Name: "budget1", - Scope: "/subscriptions/00000000-0000-0000-0000-000000000000", - }, - }, - { - Name: "subscription consumption budget but no name", - Input: "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Consumption/budgets/", - Error: true, - }, - { - Name: "management group consumption budget", - Input: "/providers/Microsoft.Management/managementGroups/00000000-0000-0000-0000-000000000000/providers/Microsoft.Consumption/budgets/budget1", - Expected: &ConsumptionBudgetId{ - Name: "budget1", - Scope: "/providers/Microsoft.Management/managementGroups/00000000-0000-0000-0000-000000000000", - }, - }, - { - Name: "management group consumption budget but no name", - Input: "/providers/Microsoft.Management/managementGroups/00000000-0000-0000-0000-000000000000/providers/Microsoft.Consumption/budgets/", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Name) - - actual, err := ConsumptionBudgetID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expected a value but got an error: %+v", err) - } - - if actual.Name != v.Expected.Name { - t.Fatalf("Expected %q but got %q", v.Expected.Name, actual.Name) - } - - if v.Expected.Scope != actual.Scope { - t.Fatalf("Expected %+v but got %+v", v.Expected.Scope, actual.Scope) - } - } -} diff --git a/internal/services/consumption/resourceids.go b/internal/services/consumption/resourceids.go deleted file mode 100644 index 7628c18ee553..000000000000 --- a/internal/services/consumption/resourceids.go +++ /dev/null @@ -1,4 +0,0 @@ -package consumption - -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ConsumptionBudgetResourceGroup -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Consumption/budgets/budget1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ConsumptionBudgetSubscription -id=/subscriptions/12345678-1234-9876-4563-123456789012/providers/Microsoft.Consumption/budgets/budget1 diff --git a/internal/services/consumption/validate/consumption_budget_management_group_id.go b/internal/services/consumption/validate/consumption_budget_management_group_id.go deleted file mode 100644 index eccf397dd0fe..000000000000 --- a/internal/services/consumption/validate/consumption_budget_management_group_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/consumption/parse" -) - -func ConsumptionBudgetManagementGroupID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.ConsumptionBudgetManagementGroupID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/consumption/validate/consumption_budget_management_group_id_test.go b/internal/services/consumption/validate/consumption_budget_management_group_id_test.go deleted file mode 100644 index cabe6fd1e8bb..000000000000 --- a/internal/services/consumption/validate/consumption_budget_management_group_id_test.go +++ /dev/null @@ -1,63 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestConsumptionBudgetManagementGroupID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - { - // empty - Input: "", - Valid: false, - }, - - { - // missing ManagementGroupName - Input: "/providers/Microsoft.Management/", - Valid: false, - }, - - { - // missing value for ManagementGroupName - Input: "/providers/Microsoft.Management/managementGroups/", - Valid: false, - }, - - { - // missing BudgetName - Input: "/providers/Microsoft.Management/managementGroups/12345678-1234-9876-4563-123456789012/providers/Microsoft.Consumption/", - Valid: false, - }, - - { - // missing value for BudgetName - Input: "/providers/Microsoft.Management/managementGroups/12345678-1234-9876-4563-123456789012/providers/Microsoft.Consumption/budgets/", - Valid: false, - }, - - { - // valid - Input: "/providers/Microsoft.Management/managementGroups/12345678-1234-9876-4563-123456789012/providers/Microsoft.Consumption/budgets/budget1", - Valid: true, - }, - - { - // upper-cased - Input: "/PROVIDERS/MICROSOFT.MANAGEMENT/MANAGEMENTGROUPS/12345678-1234-9876-4563-123456789012/PROVIDERS/MICROSOFT.CONSUMPTION/BUDGETS/BUDGET1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := ConsumptionBudgetManagementGroupID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/consumption/validate/consumption_budget_resource_group_id.go b/internal/services/consumption/validate/consumption_budget_resource_group_id.go deleted file mode 100644 index 1e5abf14fb46..000000000000 --- a/internal/services/consumption/validate/consumption_budget_resource_group_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/consumption/parse" -) - -func ConsumptionBudgetResourceGroupID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.ConsumptionBudgetResourceGroupID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/consumption/validate/consumption_budget_resource_group_id_test.go b/internal/services/consumption/validate/consumption_budget_resource_group_id_test.go deleted file mode 100644 index 9595b0fdc466..000000000000 --- a/internal/services/consumption/validate/consumption_budget_resource_group_id_test.go +++ /dev/null @@ -1,76 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestConsumptionBudgetResourceGroupID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - - { - // empty - Input: "", - Valid: false, - }, - - { - // missing SubscriptionId - Input: "/", - Valid: false, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Valid: false, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Valid: false, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Valid: false, - }, - - { - // missing BudgetName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Consumption/", - Valid: false, - }, - - { - // missing value for BudgetName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Consumption/budgets/", - Valid: false, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Consumption/budgets/budget1", - Valid: true, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.CONSUMPTION/BUDGETS/BUDGET1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := ConsumptionBudgetResourceGroupID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/consumption/validate/consumption_budget_subscription_id.go b/internal/services/consumption/validate/consumption_budget_subscription_id.go deleted file mode 100644 index 9998395d62d5..000000000000 --- a/internal/services/consumption/validate/consumption_budget_subscription_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/consumption/parse" -) - -func ConsumptionBudgetSubscriptionID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.ConsumptionBudgetSubscriptionID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/consumption/validate/consumption_budget_subscription_id_test.go b/internal/services/consumption/validate/consumption_budget_subscription_id_test.go deleted file mode 100644 index 94d51b2b635c..000000000000 --- a/internal/services/consumption/validate/consumption_budget_subscription_id_test.go +++ /dev/null @@ -1,64 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestConsumptionBudgetSubscriptionID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - - { - // empty - Input: "", - Valid: false, - }, - - { - // missing SubscriptionId - Input: "/", - Valid: false, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Valid: false, - }, - - { - // missing BudgetName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/providers/Microsoft.Consumption/", - Valid: false, - }, - - { - // missing value for BudgetName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/providers/Microsoft.Consumption/budgets/", - Valid: false, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/providers/Microsoft.Consumption/budgets/budget1", - Valid: true, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/PROVIDERS/MICROSOFT.CONSUMPTION/BUDGETS/BUDGET1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := ConsumptionBudgetSubscriptionID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/containers/client/client.go b/internal/services/containers/client/client.go index f9d963845a92..3a4b108f7bc3 100644 --- a/internal/services/containers/client/client.go +++ b/internal/services/containers/client/client.go @@ -2,8 +2,7 @@ package client import ( legacy "github.com/Azure/azure-sdk-for-go/services/containerservice/mgmt/2019-08-01/containerservice" - legacyacr "github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2019-06-01-preview/containerregistry" - "github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2021-08-01-preview/containerregistry" + "github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2022-02-01-preview/containerregistry" "github.com/Azure/azure-sdk-for-go/services/preview/containerservice/mgmt/2022-03-02-preview/containerservice" "github.com/Azure/go-autorest/autorest/azure" "github.com/hashicorp/go-azure-sdk/resource-manager/containerinstance/2021-03-01/containerinstance" @@ -22,7 +21,8 @@ type Client struct { WebhooksClient *containerregistry.WebhooksClient TokensClient *containerregistry.TokensClient ScopeMapsClient *containerregistry.ScopeMapsClient - TasksClient *legacyacr.TasksClient + TasksClient *containerregistry.TasksClient + RunsClient *containerregistry.RunsClient ConnectedRegistriesClient *containerregistry.ConnectedRegistriesClient Environment azure.Environment @@ -47,9 +47,12 @@ func NewClient(o *common.ClientOptions) *Client { scopeMapsClient := containerregistry.NewScopeMapsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&scopeMapsClient.Client, o.ResourceManagerAuthorizer) - tasksClient := legacyacr.NewTasksClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + tasksClient := containerregistry.NewTasksClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&tasksClient.Client, o.ResourceManagerAuthorizer) + runsClient := containerregistry.NewRunsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&runsClient.Client, o.ResourceManagerAuthorizer) + containerInstanceClient := containerinstance.NewContainerInstanceClientWithBaseURI(o.ResourceManagerEndpoint) o.ConfigureClient(&containerInstanceClient.Client, o.ResourceManagerAuthorizer) @@ -83,6 +86,7 @@ func NewClient(o *common.ClientOptions) *Client { TokensClient: &tokensClient, ScopeMapsClient: &scopeMapsClient, TasksClient: &tasksClient, + RunsClient: &runsClient, ConnectedRegistriesClient: &connectedRegistriesClient, } } diff --git a/internal/services/containers/container_connected_registry_resource.go b/internal/services/containers/container_connected_registry_resource.go index 5a3742c2afdd..3015ac92e7f5 100644 --- a/internal/services/containers/container_connected_registry_resource.go +++ b/internal/services/containers/container_connected_registry_resource.go @@ -5,7 +5,7 @@ import ( "fmt" "time" - "github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2021-08-01-preview/containerregistry" + "github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2022-02-01-preview/containerregistry" "github.com/hashicorp/go-azure-helpers/lang/response" tfvalidate "github.com/hashicorp/terraform-provider-azurerm/helpers/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" diff --git a/internal/services/containers/container_group_data_source.go b/internal/services/containers/container_group_data_source.go index 4df21b832c1f..79b2373df6d6 100644 --- a/internal/services/containers/container_group_data_source.go +++ b/internal/services/containers/container_group_data_source.go @@ -76,8 +76,8 @@ func dataSourceContainerGroupRead(d *pluginsdk.ResourceData, meta interface{}) e return err } props := model.Properties - if address := props.IpAddress; address != nil { - d.Set("ip_address", address.Ip) + if address := props.IPAddress; address != nil { + d.Set("ip_address", address.IP) d.Set("fqdn", address.Fqdn) } } diff --git a/internal/services/containers/container_group_resource.go b/internal/services/containers/container_group_resource.go index e97f5dd8b2c6..8be496efa953 100644 --- a/internal/services/containers/container_group_resource.go +++ b/internal/services/containers/container_group_resource.go @@ -63,11 +63,11 @@ func resourceContainerGroup() *pluginsdk.Resource { "ip_address_type": { Type: pluginsdk.TypeString, Optional: true, - Default: string(containerinstance.ContainerGroupIpAddressTypePublic), + Default: string(containerinstance.ContainerGroupIPAddressTypePublic), ForceNew: true, ValidateFunc: validation.StringInSlice([]string{ - string(containerinstance.ContainerGroupIpAddressTypePublic), - string(containerinstance.ContainerGroupIpAddressTypePrivate), + string(containerinstance.ContainerGroupIPAddressTypePublic), + string(containerinstance.ContainerGroupIPAddressTypePrivate), "None", }, false), }, @@ -678,13 +678,13 @@ func resourceContainerGroupCreate(d *pluginsdk.ResourceData, meta interface{}) e } if IPAddressType != "None" { - containerGroup.Properties.IpAddress = &containerinstance.IpAddress{ + containerGroup.Properties.IPAddress = &containerinstance.IPAddress{ Ports: containerGroupPorts, - Type: containerinstance.ContainerGroupIpAddressType(IPAddressType), + Type: containerinstance.ContainerGroupIPAddressType(IPAddressType), } if dnsNameLabel := d.Get("dns_name_label").(string); dnsNameLabel != "" { - containerGroup.Properties.IpAddress.DnsNameLabel = &dnsNameLabel + containerGroup.Properties.IPAddress.DnsNameLabel = &dnsNameLabel } } @@ -800,9 +800,9 @@ func resourceContainerGroupRead(d *pluginsdk.ResourceData, meta interface{}) err return fmt.Errorf("setting `image_registry_credential`: %+v", err) } - if address := props.IpAddress; address != nil { + if address := props.IPAddress; address != nil { d.Set("ip_address_type", address.Type) - d.Set("ip_address", address.Ip) + d.Set("ip_address", address.IP) exposedPorts := make([]interface{}, len(address.Ports)) for i := range address.Ports { exposedPorts[i] = (address.Ports)[i] @@ -1475,11 +1475,11 @@ func expandContainerProbe(input interface{}) *containerinstance.ContainerProbe { scheme := x["scheme"].(string) httpGetScheme := containerinstance.Scheme(scheme) - probe.HttpGet = &containerinstance.ContainerHttpGet{ + probe.HTTPGet = &containerinstance.ContainerHTTPGet{ Path: pointer.FromString(path), Port: int64(port), Scheme: &httpGetScheme, - HttpHeaders: expandContainerProbeHttpHeaders(x["http_headers"].(map[string]interface{})), + HTTPHeaders: expandContainerProbeHttpHeaders(x["http_headers"].(map[string]interface{})), } } } @@ -1487,14 +1487,14 @@ func expandContainerProbe(input interface{}) *containerinstance.ContainerProbe { return &probe } -func expandContainerProbeHttpHeaders(input map[string]interface{}) *[]containerinstance.HttpHeader { +func expandContainerProbeHttpHeaders(input map[string]interface{}) *[]containerinstance.HTTPHeader { if len(input) == 0 { return nil } - headers := []containerinstance.HttpHeader{} + headers := []containerinstance.HTTPHeader{} for k, v := range input { - header := containerinstance.HttpHeader{ + header := containerinstance.HTTPHeader{ Name: pointer.FromString(k), Value: pointer.FromString(v.(string)), } @@ -1503,7 +1503,7 @@ func expandContainerProbeHttpHeaders(input map[string]interface{}) *[]containeri return &headers } -func flattenContainerProbeHttpHeaders(input *[]containerinstance.HttpHeader) map[string]interface{} { +func flattenContainerProbeHttpHeaders(input *[]containerinstance.HTTPHeader) map[string]interface{} { if input == nil { return nil } @@ -1815,14 +1815,14 @@ func flattenContainerProbes(input *containerinstance.ContainerProbe) []interface } httpGets := make([]interface{}, 0) - if get := input.HttpGet; get != nil { + if get := input.HTTPGet; get != nil { httpGet := make(map[string]interface{}) if v := get.Path; v != nil { httpGet["path"] = *v } httpGet["port"] = get.Port httpGet["scheme"] = get.Scheme - httpGet["http_headers"] = flattenContainerProbeHttpHeaders(get.HttpHeaders) + httpGet["http_headers"] = flattenContainerProbeHttpHeaders(get.HTTPHeaders) httpGets = append(httpGets, httpGet) } output["http_get"] = httpGets diff --git a/internal/services/containers/container_registry_agent_pool_resource.go b/internal/services/containers/container_registry_agent_pool_resource.go index a8d811ffbaf7..38db75cacf88 100644 --- a/internal/services/containers/container_registry_agent_pool_resource.go +++ b/internal/services/containers/container_registry_agent_pool_resource.go @@ -5,7 +5,7 @@ import ( "log" "time" - "github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2021-08-01-preview/containerregistry" + "github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2022-02-01-preview/containerregistry" "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" diff --git a/internal/services/containers/container_registry_resource.go b/internal/services/containers/container_registry_resource.go index 32e03554666f..bbb5d7579614 100644 --- a/internal/services/containers/container_registry_resource.go +++ b/internal/services/containers/container_registry_resource.go @@ -8,7 +8,7 @@ import ( "strings" "time" - "github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2021-08-01-preview/containerregistry" + "github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2022-02-01-preview/containerregistry" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/identity" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" @@ -187,11 +187,16 @@ func resourceContainerRegistryCreate(d *pluginsdk.ResourceData, meta interface{} retentionPolicyRaw := d.Get("retention_policy").([]interface{}) retentionPolicy := expandRetentionPolicy(retentionPolicyRaw) + softDeletePolicyRaw := d.Get("soft_delete_policy").([]interface{}) + softDeletePolicy := expandSoftDeletePolicy(softDeletePolicyRaw) + trustPolicyRaw := d.Get("trust_policy").([]interface{}) trustPolicy := expandTrustPolicy(trustPolicyRaw) exportPolicy := expandExportPolicy(d.Get("export_policy_enabled").(bool)) + aadAuthAsArmPolicy := expandAadAuthAsArmPolicy(d.Get("azuread_authentication_as_arm_policy_enabled").(bool)) + encryptionRaw := d.Get("encryption").([]interface{}) encryption := expandEncryption(encryptionRaw) @@ -222,10 +227,12 @@ func resourceContainerRegistryCreate(d *pluginsdk.ResourceData, meta interface{} Encryption: encryption, NetworkRuleSet: networkRuleSet, Policies: &containerregistry.Policies{ - QuarantinePolicy: quarantinePolicy, - RetentionPolicy: retentionPolicy, - TrustPolicy: trustPolicy, - ExportPolicy: exportPolicy, + AzureADAuthenticationAsArmPolicy: aadAuthAsArmPolicy, + SoftDeletePolicy: softDeletePolicy, + QuarantinePolicy: quarantinePolicy, + RetentionPolicy: retentionPolicy, + TrustPolicy: trustPolicy, + ExportPolicy: exportPolicy, }, PublicNetworkAccess: publicNetworkAccess, ZoneRedundancy: zoneRedundancy, @@ -300,7 +307,9 @@ func resourceContainerRegistryUpdate(d *pluginsdk.ResourceData, meta interface{} } quarantinePolicy := expandQuarantinePolicy(d.Get("quarantine_policy_enabled").(bool)) + aadAuthAsArmPolicy := expandAadAuthAsArmPolicy(d.Get("azuread_authentication_as_arm_policy_enabled").(bool)) retentionPolicy := expandRetentionPolicy(d.Get("retention_policy").([]interface{})) + softDeletePolicy := expandSoftDeletePolicy(d.Get("soft_delete_policy").([]interface{})) trustPolicy := expandTrustPolicy(d.Get("trust_policy").([]interface{})) exportPolicy := expandExportPolicy(d.Get("export_policy_enabled").(bool)) @@ -322,10 +331,12 @@ func resourceContainerRegistryUpdate(d *pluginsdk.ResourceData, meta interface{} AdminUserEnabled: utils.Bool(adminUserEnabled), NetworkRuleSet: networkRuleSet, Policies: &containerregistry.Policies{ - QuarantinePolicy: quarantinePolicy, - RetentionPolicy: retentionPolicy, - TrustPolicy: trustPolicy, - ExportPolicy: exportPolicy, + AzureADAuthenticationAsArmPolicy: aadAuthAsArmPolicy, + SoftDeletePolicy: softDeletePolicy, + QuarantinePolicy: quarantinePolicy, + RetentionPolicy: retentionPolicy, + TrustPolicy: trustPolicy, + ExportPolicy: exportPolicy, }, PublicNetworkAccess: publicNetworkAccess, Encryption: encryption, @@ -607,7 +618,11 @@ func resourceContainerRegistryRead(d *pluginsdk.ResourceData, meta interface{}) if err := d.Set("trust_policy", flattenTrustPolicy(properties.Policies)); err != nil { return fmt.Errorf("setting `trust_policy`: %+v", err) } + if err := d.Set("soft_delete_policy", flattenSoftDeletePolicy(properties.Policies)); err != nil { + return fmt.Errorf("setting `soft_delete_policy`: %+v", err) + } d.Set("export_policy_enabled", flattenExportPolicy(properties.Policies)) + d.Set("azuread_authentication_as_arm_policy_enabled", flattenAadAuthAsArmPolicy(properties.Policies)) if err := d.Set("encryption", flattenEncryption(properties.Encryption)); err != nil { return fmt.Errorf("setting `encryption`: %+v", err) } @@ -709,21 +724,9 @@ func expandNetworkRuleSet(profiles []interface{}) *containerregistry.NetworkRule ipRules = append(ipRules, newIpRule) } - networkRuleConfigs := profile["virtual_network"].(*pluginsdk.Set).List() - virtualNetworkRules := make([]containerregistry.VirtualNetworkRule, 0) - for _, networkRuleInterface := range networkRuleConfigs { - config := networkRuleInterface.(map[string]interface{}) - newVirtualNetworkRule := containerregistry.VirtualNetworkRule{ - Action: containerregistry.Action(config["action"].(string)), - VirtualNetworkResourceID: utils.String(config["subnet_id"].(string)), - } - virtualNetworkRules = append(virtualNetworkRules, newVirtualNetworkRule) - } - networkRuleSet := containerregistry.NetworkRuleSet{ - DefaultAction: containerregistry.DefaultAction(profile["default_action"].(string)), - IPRules: &ipRules, - VirtualNetworkRules: &virtualNetworkRules, + DefaultAction: containerregistry.DefaultAction(profile["default_action"].(string)), + IPRules: &ipRules, } return &networkRuleSet } @@ -758,6 +761,24 @@ func expandRetentionPolicy(p []interface{}) *containerregistry.RetentionPolicy { return &retentionPolicy } +func expandSoftDeletePolicy(p []interface{}) *containerregistry.SoftDeletePolicy { + policy := containerregistry.SoftDeletePolicy{ + Status: containerregistry.PolicyStatusDisabled, + } + + if len(p) > 0 { + v := p[0].(map[string]interface{}) + days := int32(v["retention_days"].(int)) + enabled := v["enabled"].(bool) + if enabled { + policy.Status = containerregistry.PolicyStatusEnabled + } + policy.RetentionDays = utils.Int32(days) + } + + return &policy +} + func expandTrustPolicy(p []interface{}) *containerregistry.TrustPolicy { trustPolicy := containerregistry.TrustPolicy{ Status: containerregistry.PolicyStatusDisabled, @@ -787,6 +808,18 @@ func expandExportPolicy(enabled bool) *containerregistry.ExportPolicy { return &exportPolicy } +func expandAadAuthAsArmPolicy(enabled bool) *containerregistry.AzureADAuthenticationAsArmPolicy { + policy := containerregistry.AzureADAuthenticationAsArmPolicy{ + Status: containerregistry.AzureADAuthenticationAsArmPolicyStatusDisabled, + } + + if enabled { + policy.Status = containerregistry.AzureADAuthenticationAsArmPolicyStatusEnabled + } + + return &policy +} + func expandReplicationsFromLocations(p []interface{}) []containerregistry.Replication { replications := make([]containerregistry.Replication, 0) for _, value := range p { @@ -930,20 +963,6 @@ func flattenNetworkRuleSet(networkRuleSet *containerregistry.NetworkRuleSet) []i values["ip_rule"] = ipRules - virtualNetworkRules := make([]interface{}, 0) - - if networkRuleSet.VirtualNetworkRules != nil { - for _, virtualNetworkRule := range *networkRuleSet.VirtualNetworkRules { - value := make(map[string]interface{}) - value["action"] = string(virtualNetworkRule.Action) - - value["subnet_id"] = virtualNetworkRule.VirtualNetworkResourceID - virtualNetworkRules = append(virtualNetworkRules, value) - } - } - - values["virtual_network"] = virtualNetworkRules - return []interface{}{values} } @@ -968,6 +987,24 @@ func flattenRetentionPolicy(p *containerregistry.Policies) []interface{} { return []interface{}{retentionPolicy} } +func flattenSoftDeletePolicy(p *containerregistry.Policies) []interface{} { + if p == nil || p.SoftDeletePolicy == nil { + return nil + } + + r := *p.SoftDeletePolicy + days := 0 + if r.RetentionDays != nil { + days = int(*r.RetentionDays) + } + return []interface{}{ + map[string]interface{}{ + "retention_days": days, + "enabled": strings.EqualFold(string(r.Status), string(containerregistry.PolicyStatusEnabled)), + }, + } +} + func flattenTrustPolicy(p *containerregistry.Policies) []interface{} { if p == nil || p.TrustPolicy == nil { return nil @@ -988,6 +1025,14 @@ func flattenExportPolicy(p *containerregistry.Policies) bool { return p.ExportPolicy.Status == containerregistry.ExportPolicyStatusEnabled } +func flattenAadAuthAsArmPolicy(p *containerregistry.Policies) bool { + if p == nil || p.AzureADAuthenticationAsArmPolicy == nil { + return false + } + + return p.AzureADAuthenticationAsArmPolicy.Status == containerregistry.AzureADAuthenticationAsArmPolicyStatusEnabled +} + func resourceContainerRegistrySchema() map[string]*pluginsdk.Schema { return map[string]*pluginsdk.Schema{ "name": { @@ -1133,28 +1178,6 @@ func resourceContainerRegistrySchema() map[string]*pluginsdk.Schema { }, }, }, - - "virtual_network": { - Type: pluginsdk.TypeSet, - Optional: true, - ConfigMode: pluginsdk.SchemaConfigModeAttr, - Elem: &pluginsdk.Resource{ - Schema: map[string]*pluginsdk.Schema{ - "action": { - Type: pluginsdk.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - string(containerregistry.ActionAllow), - }, false), - }, - "subnet_id": { - Type: pluginsdk.TypeString, - Required: true, - ValidateFunc: azure.ValidateResourceID, - }, - }, - }, - }, }, }, }, @@ -1204,6 +1227,34 @@ func resourceContainerRegistrySchema() map[string]*pluginsdk.Schema { }, }, + "soft_delete_policy": { + Type: pluginsdk.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + ConfigMode: pluginsdk.SchemaConfigModeAttr, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "retention_days": { + Type: pluginsdk.TypeInt, + Optional: true, + Default: 7, + }, + "enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: false, + }, + }, + }, + }, + + "azuread_authentication_as_arm_policy_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: true, + }, + "export_policy_enabled": { Type: pluginsdk.TypeBool, Optional: true, diff --git a/internal/services/containers/container_registry_resource_test.go b/internal/services/containers/container_registry_resource_test.go index 624e4d0c4569..6e6b80f0d4a5 100644 --- a/internal/services/containers/container_registry_resource_test.go +++ b/internal/services/containers/container_registry_resource_test.go @@ -338,41 +338,6 @@ func TestAccContainerRegistry_networkAccessProfile_update(t *testing.T) { ), }, data.ImportStep(), - { - Config: r.networkAccessProfile_vnet(data), - Check: acceptance.ComposeTestCheckFunc( - check.That(data.ResourceName).ExistsInAzure(r), - check.That(data.ResourceName).Key("network_rule_set.0.default_action").HasValue("Deny"), - check.That(data.ResourceName).Key("network_rule_set.0.virtual_network.#").HasValue("1"), - ), - }, - data.ImportStep(), - { - Config: r.networkAccessProfile_both(data), - Check: acceptance.ComposeTestCheckFunc( - check.That(data.ResourceName).ExistsInAzure(r), - check.That(data.ResourceName).Key("network_rule_set.0.default_action").HasValue("Deny"), - check.That(data.ResourceName).Key("network_rule_set.0.ip_rule.#").HasValue("1"), - ), - }, - data.ImportStep(), - }) -} - -func TestAccContainerRegistry_networkAccessProfileVnet(t *testing.T) { - data := acceptance.BuildTestData(t, "azurerm_container_registry", "test") - r := ContainerRegistryResource{} - - data.ResourceTest(t, r, []acceptance.TestStep{ - { - Config: r.networkAccessProfile_vnet(data), - Check: acceptance.ComposeTestCheckFunc( - check.That(data.ResourceName).ExistsInAzure(r), - check.That(data.ResourceName).Key("network_rule_set.0.default_action").HasValue("Deny"), - check.That(data.ResourceName).Key("network_rule_set.0.virtual_network.#").HasValue("1"), - ), - }, - data.ImportStep(), }) } @@ -394,6 +359,7 @@ func TestAccContainerRegistry_policies(t *testing.T) { check.That(data.ResourceName).Key("export_policy_enabled").HasValue("false"), ), }, + data.ImportStep(), { Config: r.policies(data, 20), Check: acceptance.ComposeTestCheckFunc( @@ -407,6 +373,7 @@ func TestAccContainerRegistry_policies(t *testing.T) { check.That(data.ResourceName).Key("export_policy_enabled").HasValue("false"), ), }, + data.ImportStep(), { Config: r.policies_downgradeUpdate(data), Check: acceptance.ComposeTestCheckFunc( @@ -901,108 +868,6 @@ resource "azurerm_container_registry" "test" { `, data.RandomInteger, data.Locations.Primary, sku) } -func (ContainerRegistryResource) networkAccessProfile_vnet(data acceptance.TestData) string { - return fmt.Sprintf(` -provider "azurerm" { - features {} -} - -resource "azurerm_resource_group" "test" { - name = "acctestRG-%[1]d" - location = "%[2]s" -} - -resource "azurerm_virtual_network" "test" { - name = "virtualNetwork1" - location = azurerm_resource_group.test.location - resource_group_name = azurerm_resource_group.test.name - address_space = ["10.0.0.0/16"] -} - -resource "azurerm_subnet" "test" { - name = "testsubnet" - resource_group_name = azurerm_resource_group.test.name - virtual_network_name = azurerm_virtual_network.test.name - address_prefixes = ["10.0.1.0/24"] - - service_endpoints = ["Microsoft.ContainerRegistry"] -} - -resource "azurerm_container_registry" "test" { - name = "testAccCr%[1]d" - resource_group_name = azurerm_resource_group.test.name - location = azurerm_resource_group.test.location - sku = "Premium" - admin_enabled = false - - network_rule_set { - default_action = "Deny" - - ip_rule { - action = "Allow" - ip_range = "8.8.8.8/32" - } - - virtual_network { - action = "Allow" - subnet_id = azurerm_subnet.test.id - } - } -} -`, data.RandomInteger, data.Locations.Primary) -} - -func (ContainerRegistryResource) networkAccessProfile_both(data acceptance.TestData) string { - return fmt.Sprintf(` -provider "azurerm" { - features {} -} - -resource "azurerm_resource_group" "test" { - name = "acctestRG-%[1]d" - location = "%[2]s" -} - -resource "azurerm_virtual_network" "test" { - name = "virtualNetwork1" - location = azurerm_resource_group.test.location - resource_group_name = azurerm_resource_group.test.name - address_space = ["10.0.0.0/16"] -} - -resource "azurerm_subnet" "test" { - name = "testsubnet" - resource_group_name = azurerm_resource_group.test.name - virtual_network_name = azurerm_virtual_network.test.name - address_prefixes = ["10.0.1.0/24"] - - service_endpoints = ["Microsoft.ContainerRegistry"] -} - -resource "azurerm_container_registry" "test" { - name = "testAccCr%[1]d" - resource_group_name = azurerm_resource_group.test.name - location = azurerm_resource_group.test.location - sku = "Premium" - admin_enabled = false - - network_rule_set { - default_action = "Deny" - - ip_rule { - action = "Allow" - ip_range = "8.8.8.8/32" - } - - virtual_network { - action = "Allow" - subnet_id = azurerm_subnet.test.id - } - } -} -`, data.RandomInteger, data.Locations.Primary) -} - func (ContainerRegistryResource) policies(data acceptance.TestData, days int) string { return fmt.Sprintf(` provider "azurerm" { @@ -1028,18 +893,24 @@ resource "azurerm_container_registry" "test" { enabled = true } + soft_delete_policy { + retention_days = %d + enabled = true + } + trust_policy { enabled = true } - export_policy_enabled = false - public_network_access_enabled = false + export_policy_enabled = false + azuread_authentication_as_arm_policy_enabled = false + public_network_access_enabled = false tags = { Environment = "Production" } } -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, days) +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, days, days) } func (ContainerRegistryResource) policies_downgradeUpdate(data acceptance.TestData) string { @@ -1063,6 +934,7 @@ resource "azurerm_container_registry" "test" { retention_policy {} trust_policy {} + soft_delete_policy {} tags = { Environment = "Production" diff --git a/internal/services/containers/container_registry_scope_map_resource.go b/internal/services/containers/container_registry_scope_map_resource.go index 62a2df365a16..5c633f0135ee 100644 --- a/internal/services/containers/container_registry_scope_map_resource.go +++ b/internal/services/containers/container_registry_scope_map_resource.go @@ -5,7 +5,7 @@ import ( "log" "time" - "github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2021-08-01-preview/containerregistry" + "github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2022-02-01-preview/containerregistry" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" diff --git a/internal/services/containers/container_registry_task_resource.go b/internal/services/containers/container_registry_task_resource.go index f3038b6d6a9c..479113a820bd 100644 --- a/internal/services/containers/container_registry_task_resource.go +++ b/internal/services/containers/container_registry_task_resource.go @@ -5,7 +5,7 @@ import ( "fmt" "time" - legacyacr "github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2019-06-01-preview/containerregistry" + "github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2022-02-01-preview/containerregistry" "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/identity" @@ -171,28 +171,28 @@ func (r ContainerRegistryTaskResource) Arguments() map[string]*pluginsdk.Schema Type: pluginsdk.TypeString, Required: true, ValidateFunc: validation.StringInSlice([]string{ - string(legacyacr.Windows), - string(legacyacr.Linux), + string(containerregistry.OSWindows), + string(containerregistry.OSLinux), }, false), }, "architecture": { Type: pluginsdk.TypeString, Optional: true, ValidateFunc: validation.StringInSlice([]string{ - string(legacyacr.Amd64), - string(legacyacr.Arm), - string(legacyacr.Arm64), - string(legacyacr.ThreeEightSix), - string(legacyacr.X86), + string(containerregistry.ArchitectureAmd64), + string(containerregistry.ArchitectureArm), + string(containerregistry.ArchitectureArm64), + string(containerregistry.ArchitectureThreeEightSix), + string(containerregistry.ArchitectureX86), }, false), }, "variant": { Type: pluginsdk.TypeString, Optional: true, ValidateFunc: validation.StringInSlice([]string{ - string(legacyacr.V6), - string(legacyacr.V7), - string(legacyacr.V8), + string(containerregistry.VariantV6), + string(containerregistry.VariantV7), + string(containerregistry.VariantV8), }, false), }, }, @@ -370,8 +370,8 @@ func (r ContainerRegistryTaskResource) Arguments() map[string]*pluginsdk.Schema Type: pluginsdk.TypeString, Required: true, ValidateFunc: validation.StringInSlice([]string{ - string(legacyacr.All), - string(legacyacr.Runtime), + string(containerregistry.BaseImageTriggerTypeAll), + string(containerregistry.BaseImageTriggerTypeRuntime), }, false), }, "enabled": { @@ -389,8 +389,8 @@ func (r ContainerRegistryTaskResource) Arguments() map[string]*pluginsdk.Schema Type: pluginsdk.TypeString, Optional: true, ValidateFunc: validation.StringInSlice([]string{ - string(legacyacr.UpdateTriggerPayloadTypeDefault), - string(legacyacr.UpdateTriggerPayloadTypeToken), + string(containerregistry.UpdateTriggerPayloadTypeDefault), + string(containerregistry.UpdateTriggerPayloadTypeToken), }, false), }, }, @@ -412,8 +412,8 @@ func (r ContainerRegistryTaskResource) Arguments() map[string]*pluginsdk.Schema Elem: &pluginsdk.Schema{ Type: pluginsdk.TypeString, ValidateFunc: validation.StringInSlice([]string{ - string(legacyacr.Commit), - string(legacyacr.Pullrequest), + string(containerregistry.SourceTriggerEventCommit), + string(containerregistry.SourceTriggerEventPullrequest), }, false), }, }, @@ -421,8 +421,8 @@ func (r ContainerRegistryTaskResource) Arguments() map[string]*pluginsdk.Schema Type: pluginsdk.TypeString, Required: true, ValidateFunc: validation.StringInSlice([]string{ - string(legacyacr.Github), - string(legacyacr.VisualStudioTeamService), + string(containerregistry.SourceControlTypeGithub), + string(containerregistry.SourceControlTypeVisualStudioTeamService), }, false), }, "repository_url": { @@ -444,8 +444,8 @@ func (r ContainerRegistryTaskResource) Arguments() map[string]*pluginsdk.Schema Type: pluginsdk.TypeString, Required: true, ValidateFunc: validation.StringInSlice([]string{ - string(legacyacr.PAT), - string(legacyacr.OAuth), + string(containerregistry.TokenTypePAT), + string(containerregistry.TokenTypeOAuth), }, false), }, "token": { @@ -521,8 +521,8 @@ func (r ContainerRegistryTaskResource) Arguments() map[string]*pluginsdk.Schema Type: pluginsdk.TypeString, Required: true, ValidateFunc: validation.StringInSlice([]string{ - string(legacyacr.SourceRegistryLoginModeNone), - string(legacyacr.SourceRegistryLoginModeDefault), + string(containerregistry.SourceRegistryLoginModeNone), + string(containerregistry.SourceRegistryLoginModeDefault), }, false), }, }, @@ -687,9 +687,9 @@ func (r ContainerRegistryTaskResource) Create() sdk.ResourceFunc { return metadata.ResourceRequiresImport(r.ResourceType(), id) } - status := legacyacr.TaskStatusDisabled + status := containerregistry.TaskStatusDisabled if model.Enabled { - status = legacyacr.TaskStatusEnabled + status = containerregistry.TaskStatusEnabled } expandedIdentity, err := expandRegistryTaskIdentity(metadata.ResourceData.Get("identity").([]interface{})) @@ -697,8 +697,8 @@ func (r ContainerRegistryTaskResource) Create() sdk.ResourceFunc { return fmt.Errorf("expanding `identity`: %+v", err) } - params := legacyacr.Task{ - TaskProperties: &legacyacr.TaskProperties{ + params := containerregistry.Task{ + TaskProperties: &containerregistry.TaskProperties{ Platform: expandRegistryTaskPlatform(model.Platform), Step: expandRegistryTaskStep(model), Trigger: expandRegistryTaskTrigger(model), @@ -789,7 +789,7 @@ func (r ContainerRegistryTaskResource) Read() sdk.ResourceFunc { logTemplate = *props.LogTemplate } platform = flattenRegistryTaskPlatform(props.Platform) - enabled = props.Status == legacyacr.TaskStatusEnabled + enabled = props.Status == containerregistry.TaskStatusEnabled if props.Timeout != nil { timeoutInSec = int(*props.Timeout) } @@ -926,9 +926,9 @@ func (r ContainerRegistryTaskResource) Update() sdk.ResourceFunc { existing.TaskProperties.AgentPoolName = &model.AgentPoolName } if metadata.ResourceData.HasChange("enabled") { - status := legacyacr.TaskStatusDisabled + status := containerregistry.TaskStatusDisabled if model.Enabled { - status = legacyacr.TaskStatusEnabled + status = containerregistry.TaskStatusEnabled } existing.TaskProperties.Status = status } @@ -957,52 +957,52 @@ func (r ContainerRegistryTaskResource) Update() sdk.ResourceFunc { } } -func expandRegistryTaskTrigger(model ContainerRegistryTaskModel) *legacyacr.TriggerProperties { +func expandRegistryTaskTrigger(model ContainerRegistryTaskModel) *containerregistry.TriggerProperties { baseImageTrigger := expandRegistryTaskBaseImageTrigger(model.BaseImageTrigger) sourceTriggers := expandRegistryTaskSourceTriggers(model.SourceTrigger) timerTriggers := expandRegistryTaskTimerTriggers(model.TimerTrigger) if baseImageTrigger == nil && sourceTriggers == nil && timerTriggers == nil { return nil } - return &legacyacr.TriggerProperties{ + return &containerregistry.TriggerProperties{ BaseImageTrigger: baseImageTrigger, SourceTriggers: sourceTriggers, TimerTriggers: timerTriggers, } } -func expandRegistryTaskBaseImageTrigger(triggers []BaseImageTrigger) *legacyacr.BaseImageTrigger { +func expandRegistryTaskBaseImageTrigger(triggers []BaseImageTrigger) *containerregistry.BaseImageTrigger { if len(triggers) == 0 { return nil } trigger := triggers[0] - status := legacyacr.TriggerStatusDisabled + status := containerregistry.TriggerStatusDisabled if trigger.Enabled { - status = legacyacr.TriggerStatusEnabled + status = containerregistry.TriggerStatusEnabled } - out := &legacyacr.BaseImageTrigger{ + out := &containerregistry.BaseImageTrigger{ Name: &trigger.Name, - BaseImageTriggerType: legacyacr.BaseImageTriggerType(trigger.Type), + BaseImageTriggerType: containerregistry.BaseImageTriggerType(trigger.Type), Status: status, } if trigger.UpdateTriggerEndpoint != "" { out.UpdateTriggerEndpoint = &trigger.UpdateTriggerEndpoint } if trigger.UpdateTriggerPayloadType != "" { - out.UpdateTriggerPayloadType = legacyacr.UpdateTriggerPayloadType(trigger.UpdateTriggerPayloadType) + out.UpdateTriggerPayloadType = containerregistry.UpdateTriggerPayloadType(trigger.UpdateTriggerPayloadType) } return out } -func flattenRegistryTaskBaseImageTrigger(trigger *legacyacr.BaseImageTrigger, model ContainerRegistryTaskModel) []BaseImageTrigger { +func flattenRegistryTaskBaseImageTrigger(trigger *containerregistry.BaseImageTrigger, model ContainerRegistryTaskModel) []BaseImageTrigger { if trigger == nil { return nil } obj := BaseImageTrigger{ Type: string(trigger.BaseImageTriggerType), - Enabled: trigger.Status == legacyacr.TriggerStatusEnabled, + Enabled: trigger.Status == containerregistry.TriggerStatusEnabled, UpdateTriggerPayloadType: string(trigger.UpdateTriggerPayloadType), } @@ -1018,28 +1018,28 @@ func flattenRegistryTaskBaseImageTrigger(trigger *legacyacr.BaseImageTrigger, mo return []BaseImageTrigger{obj} } -func expandRegistryTaskSourceTriggers(triggers []SourceTrigger) *[]legacyacr.SourceTrigger { +func expandRegistryTaskSourceTriggers(triggers []SourceTrigger) *[]containerregistry.SourceTrigger { if len(triggers) == 0 { return nil } - out := make([]legacyacr.SourceTrigger, 0, len(triggers)) + out := make([]containerregistry.SourceTrigger, 0, len(triggers)) for _, trigger := range triggers { - status := legacyacr.TriggerStatusDisabled + status := containerregistry.TriggerStatusDisabled if trigger.Enabled { - status = legacyacr.TriggerStatusEnabled + status = containerregistry.TriggerStatusEnabled } - sourceTrigger := legacyacr.SourceTrigger{ + sourceTrigger := containerregistry.SourceTrigger{ Name: &trigger.Name, Status: status, - SourceRepository: &legacyacr.SourceProperties{ - SourceControlType: legacyacr.SourceControlType(trigger.SourceType), + SourceRepository: &containerregistry.SourceProperties{ + SourceControlType: containerregistry.SourceControlType(trigger.SourceType), RepositoryURL: &trigger.RepositoryURL, }, } if len(trigger.Events) != 0 { - events := make([]legacyacr.SourceTriggerEvent, 0, len(trigger.Events)) + events := make([]containerregistry.SourceTriggerEvent, 0, len(trigger.Events)) for _, event := range trigger.Events { - events = append(events, legacyacr.SourceTriggerEvent(event)) + events = append(events, containerregistry.SourceTriggerEvent(event)) } sourceTrigger.SourceTriggerEvents = &events } @@ -1055,14 +1055,14 @@ func expandRegistryTaskSourceTriggers(triggers []SourceTrigger) *[]legacyacr.Sou return &out } -func flattenRegistryTaskSourceTriggers(triggers *[]legacyacr.SourceTrigger, model ContainerRegistryTaskModel) []SourceTrigger { +func flattenRegistryTaskSourceTriggers(triggers *[]containerregistry.SourceTrigger, model ContainerRegistryTaskModel) []SourceTrigger { if triggers == nil { return nil } out := make([]SourceTrigger, 0, len(*triggers)) for i, trigger := range *triggers { obj := SourceTrigger{ - Enabled: trigger.Status == legacyacr.TriggerStatusEnabled, + Enabled: trigger.Status == containerregistry.TriggerStatusEnabled, } if trigger.Name != nil { obj.Name = *trigger.Name @@ -1094,9 +1094,9 @@ func flattenRegistryTaskSourceTriggers(triggers *[]legacyacr.SourceTrigger, mode return out } -func expandRegistryTaskAuthInfo(auth Auth) *legacyacr.AuthInfo { - out := legacyacr.AuthInfo{ - TokenType: legacyacr.TokenType(auth.TokenType), +func expandRegistryTaskAuthInfo(auth Auth) *containerregistry.AuthInfo { + out := containerregistry.AuthInfo{ + TokenType: containerregistry.TokenType(auth.TokenType), Token: &auth.Token, } if auth.RefreshToken != "" { @@ -1111,17 +1111,17 @@ func expandRegistryTaskAuthInfo(auth Auth) *legacyacr.AuthInfo { return &out } -func expandRegistryTaskTimerTriggers(triggers []TimerTrigger) *[]legacyacr.TimerTrigger { +func expandRegistryTaskTimerTriggers(triggers []TimerTrigger) *[]containerregistry.TimerTrigger { if len(triggers) == 0 { return nil } - out := make([]legacyacr.TimerTrigger, 0, len(triggers)) + out := make([]containerregistry.TimerTrigger, 0, len(triggers)) for _, trigger := range triggers { - status := legacyacr.TriggerStatusDisabled + status := containerregistry.TriggerStatusDisabled if trigger.Enabled { - status = legacyacr.TriggerStatusEnabled + status = containerregistry.TriggerStatusEnabled } - timerTrigger := legacyacr.TimerTrigger{ + timerTrigger := containerregistry.TimerTrigger{ Name: &trigger.Name, Schedule: &trigger.Schedule, Status: status, @@ -1131,14 +1131,14 @@ func expandRegistryTaskTimerTriggers(triggers []TimerTrigger) *[]legacyacr.Timer return &out } -func flattenRegistryTaskTimerTriggers(triggers *[]legacyacr.TimerTrigger) []TimerTrigger { +func flattenRegistryTaskTimerTriggers(triggers *[]containerregistry.TimerTrigger) []TimerTrigger { if triggers == nil { return nil } out := make([]TimerTrigger, 0, len(*triggers)) for _, trigger := range *triggers { obj := TimerTrigger{ - Enabled: trigger.Status == legacyacr.TriggerStatusEnabled, + Enabled: trigger.Status == containerregistry.TriggerStatusEnabled, } if trigger.Name != nil { obj.Name = *trigger.Name @@ -1151,7 +1151,7 @@ func flattenRegistryTaskTimerTriggers(triggers *[]legacyacr.TimerTrigger) []Time return out } -func expandRegistryTaskStep(model ContainerRegistryTaskModel) legacyacr.BasicTaskStepProperties { +func expandRegistryTaskStep(model ContainerRegistryTaskModel) containerregistry.BasicTaskStepProperties { switch { case len(model.DockerStep) != 0: return expandRegistryTaskDockerStep(model.DockerStep[0]) @@ -1163,9 +1163,9 @@ func expandRegistryTaskStep(model ContainerRegistryTaskModel) legacyacr.BasicTas return nil } -func expandRegistryTaskDockerStep(step DockerStep) legacyacr.DockerBuildStep { - out := legacyacr.DockerBuildStep{ - Type: legacyacr.TypeDocker, +func expandRegistryTaskDockerStep(step DockerStep) containerregistry.DockerBuildStep { + out := containerregistry.DockerBuildStep{ + Type: containerregistry.TypeBasicTaskStepPropertiesTypeDocker, DockerFilePath: &step.DockerfilePath, IsPushEnabled: &step.IsPushEnabled, NoCache: utils.Bool(!step.IsCacheEnabled), @@ -1187,7 +1187,7 @@ func expandRegistryTaskDockerStep(step DockerStep) legacyacr.DockerBuildStep { return out } -func flattenRegistryTaskDockerStep(step legacyacr.BasicTaskStepProperties, model ContainerRegistryTaskModel) []DockerStep { +func flattenRegistryTaskDockerStep(step containerregistry.BasicTaskStepProperties, model ContainerRegistryTaskModel) []DockerStep { if step == nil { return nil } @@ -1231,9 +1231,9 @@ func flattenRegistryTaskDockerStep(step legacyacr.BasicTaskStepProperties, model return []DockerStep{obj} } -func expandRegistryTaskFileTaskStep(step FileTaskStep) legacyacr.FileTaskStep { - out := legacyacr.FileTaskStep{ - Type: legacyacr.TypeFileTask, +func expandRegistryTaskFileTaskStep(step FileTaskStep) containerregistry.FileTaskStep { + out := containerregistry.FileTaskStep{ + Type: containerregistry.TypeBasicTaskStepPropertiesTypeFileTask, TaskFilePath: &step.TaskFilePath, Values: expandRegistryTaskValues(step.Values, step.SecretValues), } @@ -1249,7 +1249,7 @@ func expandRegistryTaskFileTaskStep(step FileTaskStep) legacyacr.FileTaskStep { return out } -func flattenRegistryTaskFileTaskStep(step legacyacr.BasicTaskStepProperties, model ContainerRegistryTaskModel) []FileTaskStep { +func flattenRegistryTaskFileTaskStep(step containerregistry.BasicTaskStepProperties, model ContainerRegistryTaskModel) []FileTaskStep { if step == nil { return nil } @@ -1284,9 +1284,9 @@ func flattenRegistryTaskFileTaskStep(step legacyacr.BasicTaskStepProperties, mod return []FileTaskStep{obj} } -func expandRegistryTaskEncodedTaskStep(step EncodedTaskStep) legacyacr.EncodedTaskStep { - out := legacyacr.EncodedTaskStep{ - Type: legacyacr.TypeEncodedTask, +func expandRegistryTaskEncodedTaskStep(step EncodedTaskStep) containerregistry.EncodedTaskStep { + out := containerregistry.EncodedTaskStep{ + Type: containerregistry.TypeBasicTaskStepPropertiesTypeEncodedTask, EncodedTaskContent: utils.String(utils.Base64EncodeIfNot(step.TaskContent)), Values: expandRegistryTaskValues(step.Values, step.SecretValues), } @@ -1302,7 +1302,7 @@ func expandRegistryTaskEncodedTaskStep(step EncodedTaskStep) legacyacr.EncodedTa return out } -func flattenRegistryTaskEncodedTaskStep(step legacyacr.BasicTaskStepProperties, model ContainerRegistryTaskModel) []EncodedTaskStep { +func flattenRegistryTaskEncodedTaskStep(step containerregistry.BasicTaskStepProperties, model ContainerRegistryTaskModel) []EncodedTaskStep { if step == nil { return nil } @@ -1340,20 +1340,20 @@ func flattenRegistryTaskEncodedTaskStep(step legacyacr.BasicTaskStepProperties, return []EncodedTaskStep{obj} } -func expandRegistryTaskArguments(arguments map[string]string, secretArguments map[string]string) *[]legacyacr.Argument { +func expandRegistryTaskArguments(arguments map[string]string, secretArguments map[string]string) *[]containerregistry.Argument { if len(arguments) == 0 && len(secretArguments) == 0 { return nil } - out := make([]legacyacr.Argument, 0, len(arguments)+len(secretArguments)) + out := make([]containerregistry.Argument, 0, len(arguments)+len(secretArguments)) for k, v := range arguments { - out = append(out, legacyacr.Argument{ + out = append(out, containerregistry.Argument{ Name: utils.String(k), Value: utils.String(v), IsSecret: utils.Bool(false), }) } for k, v := range secretArguments { - out = append(out, legacyacr.Argument{ + out = append(out, containerregistry.Argument{ Name: utils.String(k), Value: utils.String(v), IsSecret: utils.Bool(true), @@ -1362,7 +1362,7 @@ func expandRegistryTaskArguments(arguments map[string]string, secretArguments ma return &out } -func flattenRegistryTaskArguments(arguments *[]legacyacr.Argument) map[string]string { +func flattenRegistryTaskArguments(arguments *[]containerregistry.Argument) map[string]string { if arguments == nil { return nil } @@ -1396,20 +1396,20 @@ func flattenRegistryTaskArguments(arguments *[]legacyacr.Argument) map[string]st return args } -func expandRegistryTaskValues(values map[string]string, secretValues map[string]string) *[]legacyacr.SetValue { +func expandRegistryTaskValues(values map[string]string, secretValues map[string]string) *[]containerregistry.SetValue { if len(values) == 0 && len(secretValues) == 0 { return nil } - out := make([]legacyacr.SetValue, 0, len(values)+len(secretValues)) + out := make([]containerregistry.SetValue, 0, len(values)+len(secretValues)) for k, v := range values { - out = append(out, legacyacr.SetValue{ + out = append(out, containerregistry.SetValue{ Name: utils.String(k), Value: utils.String(v), IsSecret: utils.Bool(false), }) } for k, v := range secretValues { - out = append(out, legacyacr.SetValue{ + out = append(out, containerregistry.SetValue{ Name: utils.String(k), Value: utils.String(v), IsSecret: utils.Bool(true), @@ -1418,7 +1418,7 @@ func expandRegistryTaskValues(values map[string]string, secretValues map[string] return &out } -func flattenRegistryTaskValues(values *[]legacyacr.SetValue) map[string]string { +func flattenRegistryTaskValues(values *[]containerregistry.SetValue) map[string]string { if values == nil { return nil } @@ -1451,19 +1451,19 @@ func flattenRegistryTaskValues(values *[]legacyacr.SetValue) map[string]string { return vals } -func expandRegistryTaskIdentity(input []interface{}) (*legacyacr.IdentityProperties, error) { +func expandRegistryTaskIdentity(input []interface{}) (*containerregistry.IdentityProperties, error) { expanded, err := identity.ExpandSystemAndUserAssignedMap(input) if err != nil { return nil, err } - out := legacyacr.IdentityProperties{ - Type: legacyacr.ResourceIdentityType(string(expanded.Type)), + out := containerregistry.IdentityProperties{ + Type: containerregistry.ResourceIdentityType(string(expanded.Type)), } if len(expanded.IdentityIds) > 0 { - out.UserAssignedIdentities = map[string]*legacyacr.UserIdentityProperties{} + out.UserAssignedIdentities = map[string]*containerregistry.UserIdentityProperties{} for k := range expanded.IdentityIds { - out.UserAssignedIdentities[k] = &legacyacr.UserIdentityProperties{ + out.UserAssignedIdentities[k] = &containerregistry.UserIdentityProperties{ // intentionally empty } } @@ -1471,7 +1471,7 @@ func expandRegistryTaskIdentity(input []interface{}) (*legacyacr.IdentityPropert return &out, nil } -func flattenRegistryTaskIdentity(input *legacyacr.IdentityProperties) (*[]interface{}, error) { +func flattenRegistryTaskIdentity(input *containerregistry.IdentityProperties) (*[]interface{}, error) { var transform *identity.SystemAndUserAssignedMap if input != nil { @@ -1496,24 +1496,24 @@ func flattenRegistryTaskIdentity(input *legacyacr.IdentityProperties) (*[]interf return identity.FlattenSystemAndUserAssignedMap(transform) } -func expandRegistryTaskPlatform(input []Platform) *legacyacr.PlatformProperties { +func expandRegistryTaskPlatform(input []Platform) *containerregistry.PlatformProperties { if len(input) == 0 { return nil } platform := input[0] - out := &legacyacr.PlatformProperties{ - Os: legacyacr.OS(platform.OS), + out := &containerregistry.PlatformProperties{ + Os: containerregistry.OS(platform.OS), } if arch := platform.Architecture; arch != "" { - out.Architecture = legacyacr.Architecture(arch) + out.Architecture = containerregistry.Architecture(arch) } if variant := platform.Variant; variant != "" { - out.Variant = legacyacr.Variant(variant) + out.Variant = containerregistry.Variant(variant) } return out } -func flattenRegistryTaskPlatform(platform *legacyacr.PlatformProperties) []Platform { +func flattenRegistryTaskPlatform(platform *containerregistry.PlatformProperties) []Platform { if platform == nil { return nil } @@ -1524,18 +1524,18 @@ func flattenRegistryTaskPlatform(platform *legacyacr.PlatformProperties) []Platf }} } -func expandRegistryTaskCredentials(input []RegistryCredential) *legacyacr.Credentials { +func expandRegistryTaskCredentials(input []RegistryCredential) *containerregistry.Credentials { if len(input) == 0 { return nil } - return &legacyacr.Credentials{ + return &containerregistry.Credentials{ SourceRegistry: expandSourceRegistryCredential(input[0].Source), CustomRegistries: expandCustomRegistryCredential(input[0].Custom), } } -func flattenRegistryTaskCredentials(input *legacyacr.Credentials, model ContainerRegistryTaskModel) []RegistryCredential { +func flattenRegistryTaskCredentials(input *containerregistry.Credentials, model ContainerRegistryTaskModel) []RegistryCredential { if input == nil { return nil } @@ -1554,15 +1554,15 @@ func flattenRegistryTaskCredentials(input *legacyacr.Credentials, model Containe } } -func expandSourceRegistryCredential(input []SourceRegistryCredential) *legacyacr.SourceRegistryCredentials { +func expandSourceRegistryCredential(input []SourceRegistryCredential) *containerregistry.SourceRegistryCredentials { if len(input) == 0 { return nil } - return &legacyacr.SourceRegistryCredentials{LoginMode: legacyacr.SourceRegistryLoginMode(input[0].LoginMode)} + return &containerregistry.SourceRegistryCredentials{LoginMode: containerregistry.SourceRegistryLoginMode(input[0].LoginMode)} } -func flattenSourceRegistryCredential(input *legacyacr.SourceRegistryCredentials) []SourceRegistryCredential { +func flattenSourceRegistryCredential(input *containerregistry.SourceRegistryCredentials) []SourceRegistryCredential { if input == nil { return nil } @@ -1570,31 +1570,31 @@ func flattenSourceRegistryCredential(input *legacyacr.SourceRegistryCredentials) return []SourceRegistryCredential{{LoginMode: string(input.LoginMode)}} } -func expandCustomRegistryCredential(input []CustomRegistryCredential) map[string]*legacyacr.CustomRegistryCredentials { +func expandCustomRegistryCredential(input []CustomRegistryCredential) map[string]*containerregistry.CustomRegistryCredentials { if len(input) == 0 { return nil } - out := map[string]*legacyacr.CustomRegistryCredentials{} + out := map[string]*containerregistry.CustomRegistryCredentials{} for _, credential := range input { - cred := &legacyacr.CustomRegistryCredentials{} + cred := &containerregistry.CustomRegistryCredentials{} if credential.UserName != "" { - usernameType := legacyacr.Opaque + usernameType := containerregistry.SecretObjectTypeOpaque if _, err := keyVaultParse.ParseNestedItemID(credential.UserName); err == nil { - usernameType = legacyacr.Vaultsecret + usernameType = containerregistry.SecretObjectTypeVaultsecret } - cred.UserName = &legacyacr.SecretObject{ + cred.UserName = &containerregistry.SecretObject{ Value: utils.String(credential.UserName), Type: usernameType, } } if credential.Password != "" { - passwordType := legacyacr.Opaque + passwordType := containerregistry.SecretObjectTypeOpaque if _, err := keyVaultParse.ParseNestedItemID(credential.Password); err == nil { - passwordType = legacyacr.Vaultsecret + passwordType = containerregistry.SecretObjectTypeVaultsecret } - cred.Password = &legacyacr.SecretObject{ + cred.Password = &containerregistry.SecretObject{ Value: utils.String(credential.Password), Type: passwordType, } @@ -1607,16 +1607,16 @@ func expandCustomRegistryCredential(input []CustomRegistryCredential) map[string return out } -func expandRegistryTaskAgentProperties(input []AgentConfig) *legacyacr.AgentProperties { +func expandRegistryTaskAgentProperties(input []AgentConfig) *containerregistry.AgentProperties { if len(input) == 0 { return nil } agentConfig := input[0] - return &legacyacr.AgentProperties{CPU: utils.Int32(int32(agentConfig.CPU))} + return &containerregistry.AgentProperties{CPU: utils.Int32(int32(agentConfig.CPU))} } -func flattenRegistryTaskAgentProperties(input *legacyacr.AgentProperties) []AgentConfig { +func flattenRegistryTaskAgentProperties(input *containerregistry.AgentProperties) []AgentConfig { if input == nil { return nil } @@ -1628,12 +1628,12 @@ func flattenRegistryTaskAgentProperties(input *legacyacr.AgentProperties) []Agen return []AgentConfig{{CPU: cpu}} } -func patchRegistryTaskTriggerSourceTrigger(triggers []legacyacr.SourceTrigger, model ContainerRegistryTaskModel) *[]legacyacr.SourceTrigger { +func patchRegistryTaskTriggerSourceTrigger(triggers []containerregistry.SourceTrigger, model ContainerRegistryTaskModel) *[]containerregistry.SourceTrigger { if len(triggers) != len(model.SourceTrigger) { return &triggers } - result := make([]legacyacr.SourceTrigger, len(triggers)) + result := make([]containerregistry.SourceTrigger, len(triggers)) for i, trigger := range model.SourceTrigger { t := (triggers)[i] if len(trigger.Auth) == 0 { diff --git a/internal/services/containers/container_registry_task_schedule_run_now_resource.go b/internal/services/containers/container_registry_task_schedule_run_now_resource.go new file mode 100644 index 000000000000..07ffa8b44d01 --- /dev/null +++ b/internal/services/containers/container_registry_task_schedule_run_now_resource.go @@ -0,0 +1,164 @@ +package containers + +import ( + "context" + "fmt" + "time" + + "github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2022-02-01-preview/containerregistry" + "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/containers/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/containers/validate" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type ContainerRegistryTaskScheduleResource struct{} + +var _ sdk.Resource = ContainerRegistryTaskScheduleResource{} + +type ContainerRegistryTaskScheduleModel struct { + TaskId string `tfschema:"container_registry_task_id"` +} + +func (r ContainerRegistryTaskScheduleResource) Arguments() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "container_registry_task_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.ContainerRegistryTaskID, + }, + } +} + +func (r ContainerRegistryTaskScheduleResource) Attributes() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{} +} + +func (r ContainerRegistryTaskScheduleResource) ResourceType() string { + return "azurerm_container_registry_task_schedule_run_now" +} + +func (r ContainerRegistryTaskScheduleResource) ModelObject() interface{} { + return &ContainerRegistryTaskScheduleModel{} +} + +func (r ContainerRegistryTaskScheduleResource) IDValidationFunc() pluginsdk.SchemaValidateFunc { + return validate.ContainerRegistryTaskScheduleID +} + +func (r ContainerRegistryTaskScheduleResource) Create() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + taskClient := metadata.Client.Containers.TasksClient + + var model ContainerRegistryTaskScheduleModel + if err := metadata.Decode(&model); err != nil { + return fmt.Errorf("decoding %+v", err) + } + + taskId, err := parse.ContainerRegistryTaskID(model.TaskId) + if err != nil { + return fmt.Errorf("parsing container registry task ID: %v", err) + } + + resp, err := taskClient.Get(ctx, taskId.ResourceGroup, taskId.RegistryName, taskId.TaskName) + if err != nil { + return fmt.Errorf("retrieving %q: %+v", taskId, err) + } + if resp.TaskProperties == nil { + return fmt.Errorf("unexpected nil `taskProperties` of %q", taskId) + } + if resp.TaskProperties.Step == nil { + return fmt.Errorf("unexpected nil `taskProperties.step` of %q", taskId) + } + + req := containerregistry.TaskRunRequest{ + TaskID: utils.String(taskId.ID()), + } + switch resp.TaskProperties.Step.(type) { + case containerregistry.DockerBuildStep: + req.Type = containerregistry.TypeDockerBuildRequest + case containerregistry.FileTaskStep: + req.Type = containerregistry.TypeFileTaskRunRequest + case containerregistry.EncodedTaskStep: + req.Type = containerregistry.TypeEncodedTaskRunRequest + default: + return fmt.Errorf("unexpected container registry task step type: %T", resp.TaskProperties.Step) + } + + registryClient := metadata.Client.Containers.RegistriesClient + future, err := registryClient.ScheduleRun(ctx, taskId.ResourceGroup, taskId.RegistryName, req) + if err != nil { + return fmt.Errorf("scheduling the task: %v", err) + } + if err := future.WaitForCompletionRef(ctx, registryClient.Client); err != nil { + return fmt.Errorf("waiting for schedule: %v", err) + } + + run, err := future.Result(*registryClient) + if err != nil { + return fmt.Errorf("getting the scheduled run: %v", err) + } + + if run.Name == nil { + return fmt.Errorf("unexpected nil scheduled run name") + } + + runsClient := metadata.Client.Containers.RunsClient + + timeout, _ := ctx.Deadline() + stateConf := &pluginsdk.StateChangeConf{ + Pending: []string{string(containerregistry.RunStatusQueued), string(containerregistry.RunStatusStarted), string(containerregistry.RunStatusRunning)}, + Target: []string{string(containerregistry.RunStatusSucceeded)}, + Refresh: func() (interface{}, string, error) { + resp, err := runsClient.Get(ctx, taskId.ResourceGroup, taskId.RegistryName, *run.Name) + if err != nil { + return nil, "", fmt.Errorf("getting the scheduled run: %v", err) + } + + if resp.RunProperties == nil { + return nil, "", fmt.Errorf("unexpected nil properties of the scheduled run") + } + + return run, string(resp.RunProperties.Status), nil + }, + ContinuousTargetOccurence: 1, + PollInterval: 5 * time.Second, + Timeout: time.Until(timeout), + } + if _, err := stateConf.WaitForStateContext(ctx); err != nil { + return fmt.Errorf("waiting for scheduled task to finish: %+v", err) + } + + metadata.SetID(parse.NewContainerRegistryTaskScheduleID(taskId.SubscriptionId, taskId.ResourceGroup, taskId.RegistryName, taskId.TaskName, "schedule")) + return nil + }, + } +} + +func (r ContainerRegistryTaskScheduleResource) Read() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 5 * time.Minute, + + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + id, err := parse.ContainerRegistryTaskScheduleID(metadata.ResourceData.Id()) + if err != nil { + return err + } + model := ContainerRegistryTaskScheduleModel{TaskId: parse.NewContainerRegistryTaskID(id.SubscriptionId, id.ResourceGroup, id.RegistryName, id.TaskName).ID()} + return metadata.Encode(&model) + }, + } +} + +func (r ContainerRegistryTaskScheduleResource) Delete() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + return nil + }, + } +} diff --git a/internal/services/containers/container_registry_task_schedule_run_now_resource_test.go b/internal/services/containers/container_registry_task_schedule_run_now_resource_test.go new file mode 100644 index 000000000000..317c5bcc8232 --- /dev/null +++ b/internal/services/containers/container_registry_task_schedule_run_now_resource_test.go @@ -0,0 +1,149 @@ +package containers_test + +import ( + "context" + "fmt" + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" +) + +type ContainerRegistryTaskScheduleResource struct { + githubRepo +} + +func TestAccContainerRegistryTaskSchedule_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_container_registry_task_schedule_run_now", "test") + + preCheckGithubRepo(t) + + r := ContainerRegistryTaskScheduleResource{ + githubRepo: githubRepo{ + url: os.Getenv("ARM_TEST_ACR_TASK_GITHUB_REPO_URL"), + token: os.Getenv("ARM_TEST_ACR_TASK_GITHUB_USER_TOKEN"), + }, + } + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data, r.dockerTaskStep), + }, + data.ImportStep(), + { + Config: r.basic(data, r.fileTaskStep), + }, + data.ImportStep(), + { + Config: r.basic(data, r.encodedTaskStep), + }, + data.ImportStep(), + }) +} + +func (r ContainerRegistryTaskScheduleResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + ret := false + return &ret, nil +} + +func (r ContainerRegistryTaskScheduleResource) basic(data acceptance.TestData, tpl func(data acceptance.TestData) string) string { + template := tpl(data) + return fmt.Sprintf(` +%s + +resource "azurerm_container_registry_task_schedule_run_now" "test" { + container_registry_task_id = azurerm_container_registry_task.test.id +} +`, template) +} + +func (r ContainerRegistryTaskScheduleResource) dockerTaskStep(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_container_registry_task" "test" { + name = "testacccrTask%d" + container_registry_id = azurerm_container_registry.test.id + platform { + os = "Linux" + } + docker_step { + dockerfile_path = "Dockerfile" + context_path = "%s" + context_access_token = "%s" + image_names = ["helloworld:{{.Run.ID}}"] + } +} +`, template, data.RandomInteger, r.githubRepo.url, r.githubRepo.token) +} + +func (r ContainerRegistryTaskScheduleResource) fileTaskStep(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_container_registry_task" "test" { + name = "testacccrTask%d" + container_registry_id = azurerm_container_registry.test.id + platform { + os = "Linux" + } + file_step { + task_file_path = "taskmulti.yaml" + context_path = "%s" + context_access_token = "%s" + } +} +`, template, data.RandomInteger, r.githubRepo.url, r.githubRepo.token) +} + +func (r ContainerRegistryTaskScheduleResource) encodedTaskStep(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_container_registry_task" "test" { + name = "testacccrTask%d" + container_registry_id = azurerm_container_registry.test.id + platform { + os = "Linux" + } + encoded_step { + task_content = < You can't upgrade a spot node pool since spot node pools can't guarantee cordon and drain. - // > You must replace your existing spot node pool with a new one to do operations such as upgrading - // > the Kubernetes version. To replace a spot node pool, create a new spot node pool with a different - // > version of Kubernetes, wait until its status is Ready, then remove the old node pool. - if strings.EqualFold(string(props.ScaleSetPriority), string(containerservice.ScaleSetPrioritySpot)) { - // ^ the Scale Set Priority isn't returned when Regular - return fmt.Errorf("the Orchestrator Version cannot be updated when using a Spot Node Pool") - } - existingNodePool, err := client.Get(ctx, id.ResourceGroup, id.ManagedClusterName, id.AgentPoolName) if err != nil { return fmt.Errorf("retrieving Node Pool %s: %+v", *id, err) @@ -917,7 +907,7 @@ func upgradeSettingsForDataSourceSchema() *pluginsdk.Schema { func expandUpgradeSettings(input []interface{}) *containerservice.AgentPoolUpgradeSettings { setting := &containerservice.AgentPoolUpgradeSettings{} - if len(input) == 0 { + if len(input) == 0 || input[0] == nil { return setting } diff --git a/internal/services/containers/kubernetes_cluster_other_resource_test.go b/internal/services/containers/kubernetes_cluster_other_resource_test.go index e319eb8d09bb..b36176c0d2d3 100644 --- a/internal/services/containers/kubernetes_cluster_other_resource_test.go +++ b/internal/services/containers/kubernetes_cluster_other_resource_test.go @@ -166,7 +166,7 @@ func TestAccKubernetesCluster_nodeLabels(t *testing.T) { Config: r.nodeLabelsConfig(data, labels3), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), - acceptance.TestCheckNoResourceAttr(data.ResourceName, "default_node_pool.0.node_labels"), + check.That(data.ResourceName).Key("default_node_pool.0.node_labels.%").HasValue("0"), ), }, }) diff --git a/internal/services/containers/kubernetes_cluster_resource.go b/internal/services/containers/kubernetes_cluster_resource.go index 9c796f5e9d05..10c06c79a33d 100644 --- a/internal/services/containers/kubernetes_cluster_resource.go +++ b/internal/services/containers/kubernetes_cluster_resource.go @@ -13,6 +13,7 @@ import ( "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/identity" + "github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces" "github.com/hashicorp/go-azure-sdk/resource-manager/privatedns/2018-09-01/privatezones" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" @@ -24,7 +25,6 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/internal/services/containers/migration" "github.com/hashicorp/terraform-provider-azurerm/internal/services/containers/parse" containerValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/containers/validate" - logAnalyticsValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/loganalytics/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/suppress" @@ -396,7 +396,7 @@ func resourceKubernetesCluster() *pluginsdk.Resource { "log_analytics_workspace_id": { Type: pluginsdk.TypeString, Required: true, - ValidateFunc: logAnalyticsValidate.LogAnalyticsWorkspaceID, + ValidateFunc: workspaces.ValidateWorkspaceID, }, }, }, @@ -1925,7 +1925,7 @@ func flattenKubernetesClusterAccessProfile(profile containerservice.ManagedClust rawConfig := string(*kubeConfigRaw) var flattenedKubeConfig []interface{} - if strings.Contains(rawConfig, "apiserver-id:") { + if strings.Contains(rawConfig, "apiserver-id:") || strings.Contains(rawConfig, "exec") { kubeConfigAAD, err := kubernetes.ParseKubeConfigAAD(rawConfig) if err != nil { return utils.String(rawConfig), []interface{}{} diff --git a/internal/services/containers/kubernetes_cluster_resource_test.go b/internal/services/containers/kubernetes_cluster_resource_test.go index 08c986c1fcef..8e885685f710 100644 --- a/internal/services/containers/kubernetes_cluster_resource_test.go +++ b/internal/services/containers/kubernetes_cluster_resource_test.go @@ -17,8 +17,8 @@ import ( type KubernetesClusterResource struct{} var ( - olderKubernetesVersion = "1.21.7" - currentKubernetesVersion = "1.22.4" + olderKubernetesVersion = "1.22.11" + currentKubernetesVersion = "1.23.5" olderKubernetesVersionAlias = "1.22" currentKubernetesVersionAlias = "1.23" ) @@ -286,3 +286,18 @@ resource "azurerm_kubernetes_cluster" "test" { } `, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, maxSurge) } + +func TestAccResourceKubernetesCluster_roleBasedAccessControlAAD_VOneDotTwoFourDotThree(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_kubernetes_cluster", "test") + r := KubernetesClusterResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.roleBasedAccessControlAADManagedConfigVOneDotTwoFourDotThree(data, ""), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("kube_config.#").HasValue("1"), + check.That(data.ResourceName).Key("kube_config.0.host").IsSet(), + ), + }, + }) +} diff --git a/internal/services/containers/kubernetes_cluster_upgrade_test.go b/internal/services/containers/kubernetes_cluster_upgrade_test.go index fbff4a10149b..0491ec91a2ac 100644 --- a/internal/services/containers/kubernetes_cluster_upgrade_test.go +++ b/internal/services/containers/kubernetes_cluster_upgrade_test.go @@ -239,6 +239,37 @@ func TestAccKubernetesCluster_upgradeControlPlaneAndAllPoolsTogetherVersionAlias }) } +func TestAccKubernetesCluster_upgradeControlPlaneAndAllPoolsTogetherSpot(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_kubernetes_cluster", "test") + r := KubernetesClusterResource{} + nodePoolName := "azurerm_kubernetes_cluster_node_pool.test" + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + // all on the older version + Config: r.upgradeVersionsConfigSpot(data, olderKubernetesVersion, olderKubernetesVersion, olderKubernetesVersion), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("kubernetes_version").HasValue(olderKubernetesVersion), + check.That(data.ResourceName).Key("default_node_pool.0.orchestrator_version").HasValue(olderKubernetesVersion), + check.That(nodePoolName).Key("orchestrator_version").HasValue(olderKubernetesVersion), + ), + }, + data.ImportStep(), + { + // upgrade control plane, default and custom node pools + Config: r.upgradeVersionsConfigSpot(data, currentKubernetesVersion, currentKubernetesVersion, currentKubernetesVersion), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("kubernetes_version").HasValue(currentKubernetesVersion), + check.That(data.ResourceName).Key("default_node_pool.0.orchestrator_version").HasValue(currentKubernetesVersion), + check.That(nodePoolName).Key("orchestrator_version").HasValue(currentKubernetesVersion), + ), + }, + data.ImportStep(), + }) +} + func TestAccKubernetesCluster_upgradeSettings(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_kubernetes_cluster", "test") r := KubernetesClusterResource{} @@ -350,6 +381,29 @@ resource "azurerm_kubernetes_cluster_node_pool" "test" { `, r.upgradeControlPlaneDefaultNodePoolConfig(data, controlPlaneVersion, defaultNodePoolVersion), customNodePoolVersion) } +func (r KubernetesClusterResource) upgradeVersionsConfigSpot(data acceptance.TestData, controlPlaneVersion, defaultNodePoolVersion, customNodePoolVersion string) string { + return fmt.Sprintf(` +%s + +resource "azurerm_kubernetes_cluster_node_pool" "test" { + name = "internal" + kubernetes_cluster_id = azurerm_kubernetes_cluster.test.id + vm_size = "Standard_DS2_v2" + node_count = 1 + orchestrator_version = %q + priority = "Spot" + eviction_policy = "Delete" + spot_max_price = 0.5 # high, but this is a maximum (we pay less) so ensures this won't fail + node_labels = { + "kubernetes.azure.com/scalesetpriority" = "spot" + } + node_taints = [ + "kubernetes.azure.com/scalesetpriority=spot:NoSchedule" + ] +} +`, r.upgradeControlPlaneDefaultNodePoolConfig(data, controlPlaneVersion, defaultNodePoolVersion), customNodePoolVersion) +} + func (KubernetesClusterResource) upgradeAutoScaleMinCountConfig(data acceptance.TestData, controlPlaneVersion string, minCount int, maxCount int) string { return fmt.Sprintf(` provider "azurerm" { diff --git a/internal/services/containers/kubernetes_nodepool.go b/internal/services/containers/kubernetes_nodepool.go index eb8a5a576a10..3171c321bc19 100644 --- a/internal/services/containers/kubernetes_nodepool.go +++ b/internal/services/containers/kubernetes_nodepool.go @@ -6,6 +6,8 @@ import ( "strconv" "strings" + "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/proximityplacementgroups" + "github.com/Azure/azure-sdk-for-go/services/preview/containerservice/mgmt/2022-03-02-preview/containerservice" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/zones" @@ -216,7 +218,7 @@ func SchemaDefaultNodePool() *pluginsdk.Schema { Type: pluginsdk.TypeString, Optional: true, ForceNew: true, - ValidateFunc: computeValidate.ProximityPlacementGroupID, + ValidateFunc: proximityplacementgroups.ValidateProximityPlacementGroupID, }, "only_critical_addons_enabled": { Type: pluginsdk.TypeBool, diff --git a/internal/services/containers/parse/container_registry_task_schedule.go b/internal/services/containers/parse/container_registry_task_schedule.go new file mode 100644 index 000000000000..56ac6e41db0b --- /dev/null +++ b/internal/services/containers/parse/container_registry_task_schedule.go @@ -0,0 +1,81 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + "strings" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +type ContainerRegistryTaskScheduleId struct { + SubscriptionId string + ResourceGroup string + RegistryName string + TaskName string + ScheduleName string +} + +func NewContainerRegistryTaskScheduleID(subscriptionId, resourceGroup, registryName, taskName, scheduleName string) ContainerRegistryTaskScheduleId { + return ContainerRegistryTaskScheduleId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + RegistryName: registryName, + TaskName: taskName, + ScheduleName: scheduleName, + } +} + +func (id ContainerRegistryTaskScheduleId) String() string { + segments := []string{ + fmt.Sprintf("Schedule Name %q", id.ScheduleName), + fmt.Sprintf("Task Name %q", id.TaskName), + fmt.Sprintf("Registry Name %q", id.RegistryName), + fmt.Sprintf("Resource Group %q", id.ResourceGroup), + } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "Container Registry Task Schedule", segmentsStr) +} + +func (id ContainerRegistryTaskScheduleId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.ContainerRegistry/registries/%s/tasks/%s/schedule/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.RegistryName, id.TaskName, id.ScheduleName) +} + +// ContainerRegistryTaskScheduleID parses a ContainerRegistryTaskSchedule ID into an ContainerRegistryTaskScheduleId struct +func ContainerRegistryTaskScheduleID(input string) (*ContainerRegistryTaskScheduleId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := ContainerRegistryTaskScheduleId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + if resourceId.RegistryName, err = id.PopSegment("registries"); err != nil { + return nil, err + } + if resourceId.TaskName, err = id.PopSegment("tasks"); err != nil { + return nil, err + } + if resourceId.ScheduleName, err = id.PopSegment("schedule"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} diff --git a/internal/services/containers/parse/container_registry_task_schedule_test.go b/internal/services/containers/parse/container_registry_task_schedule_test.go new file mode 100644 index 000000000000..3066737ff56c --- /dev/null +++ b/internal/services/containers/parse/container_registry_task_schedule_test.go @@ -0,0 +1,144 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "testing" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +var _ resourceids.Id = ContainerRegistryTaskScheduleId{} + +func TestContainerRegistryTaskScheduleIDFormatter(t *testing.T) { + actual := NewContainerRegistryTaskScheduleID("12345678-1234-9876-4563-123456789012", "group1", "registry1", "task1", "schedule1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.ContainerRegistry/registries/registry1/tasks/task1/schedule/schedule1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestContainerRegistryTaskScheduleID(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *ContainerRegistryTaskScheduleId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing RegistryName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.ContainerRegistry/", + Error: true, + }, + + { + // missing value for RegistryName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.ContainerRegistry/registries/", + Error: true, + }, + + { + // missing TaskName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.ContainerRegistry/registries/registry1/", + Error: true, + }, + + { + // missing value for TaskName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.ContainerRegistry/registries/registry1/tasks/", + Error: true, + }, + + { + // missing ScheduleName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.ContainerRegistry/registries/registry1/tasks/task1/", + Error: true, + }, + + { + // missing value for ScheduleName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.ContainerRegistry/registries/registry1/tasks/task1/schedule/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.ContainerRegistry/registries/registry1/tasks/task1/schedule/schedule1", + Expected: &ContainerRegistryTaskScheduleId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "group1", + RegistryName: "registry1", + TaskName: "task1", + ScheduleName: "schedule1", + }, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/GROUP1/PROVIDERS/MICROSOFT.CONTAINERREGISTRY/REGISTRIES/REGISTRY1/TASKS/TASK1/SCHEDULE/SCHEDULE1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := ContainerRegistryTaskScheduleID(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.RegistryName != v.Expected.RegistryName { + t.Fatalf("Expected %q but got %q for RegistryName", v.Expected.RegistryName, actual.RegistryName) + } + if actual.TaskName != v.Expected.TaskName { + t.Fatalf("Expected %q but got %q for TaskName", v.Expected.TaskName, actual.TaskName) + } + if actual.ScheduleName != v.Expected.ScheduleName { + t.Fatalf("Expected %q but got %q for ScheduleName", v.Expected.ScheduleName, actual.ScheduleName) + } + } +} diff --git a/internal/services/containers/registration.go b/internal/services/containers/registration.go index 837f680913fd..ac80b28dd481 100644 --- a/internal/services/containers/registration.go +++ b/internal/services/containers/registration.go @@ -53,6 +53,7 @@ func (r Registration) DataSources() []sdk.DataSource { func (r Registration) Resources() []sdk.Resource { return []sdk.Resource{ ContainerRegistryTaskResource{}, + ContainerRegistryTaskScheduleResource{}, ContainerConnectedRegistryResource{}, } } diff --git a/internal/services/containers/resourceids.go b/internal/services/containers/resourceids.go index 6e9486c55413..783dd89761c7 100644 --- a/internal/services/containers/resourceids.go +++ b/internal/services/containers/resourceids.go @@ -5,6 +5,7 @@ package containers //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=NodePool -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ContainerService/managedClusters/cluster1/agentPools/pool1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ContainerRegistryScopeMap -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ContainerRegistry/registries/registry1/scopeMaps/scopeMap1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ContainerRegistryTask -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.ContainerRegistry/registries/registry1/tasks/task1 +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ContainerRegistryTaskSchedule -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.ContainerRegistry/registries/registry1/tasks/task1/schedule/schedule1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ContainerRegistryToken -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ContainerRegistry/registries/registry1/tokens/token1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Registry -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.ContainerRegistry/registries/registry1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Webhook -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.ContainerRegistry/registries/registry1/webhooks/webhook1 diff --git a/internal/services/containers/validate/container_registry_task_schedule_id.go b/internal/services/containers/validate/container_registry_task_schedule_id.go new file mode 100644 index 000000000000..417723db6e2a --- /dev/null +++ b/internal/services/containers/validate/container_registry_task_schedule_id.go @@ -0,0 +1,23 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + + "github.com/hashicorp/terraform-provider-azurerm/internal/services/containers/parse" +) + +func ContainerRegistryTaskScheduleID(input interface{}, key string) (warnings []string, errors []error) { + v, ok := input.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected %q to be a string", key)) + return + } + + if _, err := parse.ContainerRegistryTaskScheduleID(v); err != nil { + errors = append(errors, err) + } + + return +} diff --git a/internal/services/containers/validate/container_registry_task_schedule_id_test.go b/internal/services/containers/validate/container_registry_task_schedule_id_test.go new file mode 100644 index 000000000000..a28599f40e1a --- /dev/null +++ b/internal/services/containers/validate/container_registry_task_schedule_id_test.go @@ -0,0 +1,100 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import "testing" + +func TestContainerRegistryTaskScheduleID(t *testing.T) { + cases := []struct { + Input string + Valid bool + }{ + + { + // empty + Input: "", + Valid: false, + }, + + { + // missing SubscriptionId + Input: "/", + Valid: false, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Valid: false, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Valid: false, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Valid: false, + }, + + { + // missing RegistryName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.ContainerRegistry/", + Valid: false, + }, + + { + // missing value for RegistryName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.ContainerRegistry/registries/", + Valid: false, + }, + + { + // missing TaskName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.ContainerRegistry/registries/registry1/", + Valid: false, + }, + + { + // missing value for TaskName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.ContainerRegistry/registries/registry1/tasks/", + Valid: false, + }, + + { + // missing ScheduleName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.ContainerRegistry/registries/registry1/tasks/task1/", + Valid: false, + }, + + { + // missing value for ScheduleName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.ContainerRegistry/registries/registry1/tasks/task1/schedule/", + Valid: false, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.ContainerRegistry/registries/registry1/tasks/task1/schedule/schedule1", + Valid: true, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/GROUP1/PROVIDERS/MICROSOFT.CONTAINERREGISTRY/REGISTRIES/REGISTRY1/TASKS/TASK1/SCHEDULE/SCHEDULE1", + Valid: false, + }, + } + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.Input) + _, errors := ContainerRegistryTaskScheduleID(tc.Input, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} diff --git a/internal/services/cosmos/client/client.go b/internal/services/cosmos/client/client.go index 3e6245a290ab..2a705c55ca69 100644 --- a/internal/services/cosmos/client/client.go +++ b/internal/services/cosmos/client/client.go @@ -2,6 +2,7 @@ package client import ( "github.com/Azure/azure-sdk-for-go/services/cosmos-db/mgmt/2021-10-15/documentdb" + "github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/sqldedicatedgateway" "github.com/hashicorp/terraform-provider-azurerm/internal/common" ) @@ -14,6 +15,7 @@ type Client struct { MongoDbClient *documentdb.MongoDBResourcesClient NotebookWorkspaceClient *documentdb.NotebookWorkspacesClient RestorableDatabaseAccountsClient *documentdb.RestorableDatabaseAccountsClient + SqlDedicatedGatewayClient *sqldedicatedgateway.SqlDedicatedGatewayClient SqlClient *documentdb.SQLResourcesClient SqlResourceClient *documentdb.SQLResourcesClient TableClient *documentdb.TableResourcesClient @@ -44,6 +46,9 @@ func NewClient(o *common.ClientOptions) *Client { restorableDatabaseAccountsClient := documentdb.NewRestorableDatabaseAccountsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&restorableDatabaseAccountsClient.Client, o.ResourceManagerAuthorizer) + sqlDedicatedGatewayClient := sqldedicatedgateway.NewSqlDedicatedGatewayClientWithBaseURI(o.ResourceManagerEndpoint) + o.ConfigureClient(&sqlDedicatedGatewayClient.Client, o.ResourceManagerAuthorizer) + sqlClient := documentdb.NewSQLResourcesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&sqlClient.Client, o.ResourceManagerAuthorizer) @@ -62,6 +67,7 @@ func NewClient(o *common.ClientOptions) *Client { MongoDbClient: &mongoDbClient, NotebookWorkspaceClient: ¬ebookWorkspaceClient, RestorableDatabaseAccountsClient: &restorableDatabaseAccountsClient, + SqlDedicatedGatewayClient: &sqlDedicatedGatewayClient, SqlClient: &sqlClient, SqlResourceClient: &sqlResourceClient, TableClient: &tableClient, diff --git a/internal/services/cosmos/common/autoscale_settings.go b/internal/services/cosmos/common/autoscale_settings.go index 9d8eded444db..c8e3644b21bb 100644 --- a/internal/services/cosmos/common/autoscale_settings.go +++ b/internal/services/cosmos/common/autoscale_settings.go @@ -55,8 +55,12 @@ func FlattenCosmosDbAutoscaleSettings(throughputResponse documentdb.ThroughputSe func ExpandCosmosDbAutoscaleSettingsResource(d *pluginsdk.ResourceData) *documentdb.AutoscaleSettingsResource { autoscaleSettings := ExpandCosmosDbAutoscaleSettings(d) - autoscaleSettingResource := documentdb.AutoscaleSettingsResource{} - autoscaleSettingResource.MaxThroughput = autoscaleSettings.MaxThroughput - return &autoscaleSettingResource + if autoscaleSettings == nil { + return nil + } + + return &documentdb.AutoscaleSettingsResource{ + MaxThroughput: autoscaleSettings.MaxThroughput, + } } diff --git a/internal/services/cosmos/cosmosdb_cassandra_cluster_resource.go b/internal/services/cosmos/cosmosdb_cassandra_cluster_resource.go index 2a988f2f21f8..eef97f9e3518 100644 --- a/internal/services/cosmos/cosmosdb_cassandra_cluster_resource.go +++ b/internal/services/cosmos/cosmosdb_cassandra_cluster_resource.go @@ -292,10 +292,13 @@ func resourceCassandraClusterUpdate(d *pluginsdk.ResourceData, meta interface{}) } // Though there is update method but Service API complains it isn't implemented - _, err = client.CreateUpdate(ctx, id.ResourceGroup, id.Name, body) + future, err := client.CreateUpdate(ctx, id.ResourceGroup, id.Name, body) if err != nil { return fmt.Errorf("updating %q: %+v", id, err) } + if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for update of %q: %+v", id, err) + } // Issue: https://github.com/Azure/azure-rest-api-specs/issues/19021 // There is a long running issue on updating this resource. diff --git a/internal/services/cosmos/cosmosdb_sql_dedicated_gateway_resource.go b/internal/services/cosmos/cosmosdb_sql_dedicated_gateway_resource.go new file mode 100644 index 000000000000..865c1d443f08 --- /dev/null +++ b/internal/services/cosmos/cosmosdb_sql_dedicated_gateway_resource.go @@ -0,0 +1,224 @@ +package cosmos + +import ( + "context" + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/cosmosdb" + "github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/sqldedicatedgateway" + "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" +) + +type CosmosDbSqlDedicatedGatewayModel struct { + CosmosDbAccountId string `tfschema:"cosmosdb_account_id"` + InstanceCount int64 `tfschema:"instance_count"` + InstanceSize sqldedicatedgateway.ServiceSize `tfschema:"instance_size"` +} + +type CosmosDbSqlDedicatedGatewayResource struct{} + +var _ sdk.ResourceWithUpdate = CosmosDbSqlDedicatedGatewayResource{} + +func (r CosmosDbSqlDedicatedGatewayResource) ResourceType() string { + return "azurerm_cosmosdb_sql_dedicated_gateway" +} + +func (r CosmosDbSqlDedicatedGatewayResource) ModelObject() interface{} { + return &CosmosDbSqlDedicatedGatewayModel{} +} + +func (r CosmosDbSqlDedicatedGatewayResource) IDValidationFunc() pluginsdk.SchemaValidateFunc { + return sqldedicatedgateway.ValidateServiceID +} + +func (r CosmosDbSqlDedicatedGatewayResource) Arguments() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "cosmosdb_account_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: cosmosdb.ValidateDatabaseAccountID, + }, + + "instance_size": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{ + string(sqldedicatedgateway.ServiceSizeCosmosPointDFours), + string(sqldedicatedgateway.ServiceSizeCosmosPointDEights), + string(sqldedicatedgateway.ServiceSizeCosmosPointDOneSixs), + }, false), + }, + + "instance_count": { + Type: pluginsdk.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(1, 5), + }, + } +} + +func (r CosmosDbSqlDedicatedGatewayResource) Attributes() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{} +} + +func (r CosmosDbSqlDedicatedGatewayResource) Create() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + var model CosmosDbSqlDedicatedGatewayModel + if err := metadata.Decode(&model); err != nil { + return fmt.Errorf("decoding: %+v", err) + } + + client := metadata.Client.Cosmos.SqlDedicatedGatewayClient + cosmosdbAccountId, err := cosmosdb.ParseDatabaseAccountID(model.CosmosDbAccountId) + if err != nil { + return err + } + + id := sqldedicatedgateway.NewServiceID(cosmosdbAccountId.SubscriptionId, cosmosdbAccountId.ResourceGroupName, cosmosdbAccountId.AccountName, string(sqldedicatedgateway.ServiceTypeSqlDedicatedGateway)) + existing, err := client.ServiceGet(ctx, id) + if err != nil && !response.WasNotFound(existing.HttpResponse) { + return fmt.Errorf("checking for existing %s: %+v", id, err) + } + + if !response.WasNotFound(existing.HttpResponse) { + return metadata.ResourceRequiresImport(r.ResourceType(), id) + } + + serviceType := sqldedicatedgateway.ServiceTypeSqlDedicatedGateway + + parameters := &sqldedicatedgateway.ServiceResourceCreateUpdateParameters{ + Properties: &sqldedicatedgateway.ServiceResourceCreateUpdateProperties{ + ServiceType: &serviceType, + InstanceCount: &model.InstanceCount, + InstanceSize: &model.InstanceSize, + }, + } + + if err := client.ServiceCreateThenPoll(ctx, id, *parameters); err != nil { + return fmt.Errorf("creating %s: %+v", id, err) + } + + metadata.SetID(id) + return nil + }, + } +} + +func (r CosmosDbSqlDedicatedGatewayResource) Update() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.Cosmos.SqlDedicatedGatewayClient + + id, err := sqldedicatedgateway.ParseServiceID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + var model CosmosDbSqlDedicatedGatewayModel + if err := metadata.Decode(&model); err != nil { + return fmt.Errorf("decoding: %+v", err) + } + + resp, err := client.ServiceGet(ctx, *id) + if err != nil { + return fmt.Errorf("retrieving %s: %+v", *id, err) + } + + properties := resp.Model + if properties == nil { + return fmt.Errorf("retrieving %s: properties was nil", id) + } + + serviceType := sqldedicatedgateway.ServiceTypeSqlDedicatedGateway + + parameters := &sqldedicatedgateway.ServiceResourceCreateUpdateParameters{ + Properties: &sqldedicatedgateway.ServiceResourceCreateUpdateProperties{ + ServiceType: &serviceType, + InstanceCount: &model.InstanceCount, + InstanceSize: &model.InstanceSize, + }, + } + + if err := client.ServiceCreateThenPoll(ctx, *id, *parameters); err != nil { + return fmt.Errorf("updating %s: %+v", *id, err) + } + + return nil + }, + } +} + +func (r CosmosDbSqlDedicatedGatewayResource) Read() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 5 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.Cosmos.SqlDedicatedGatewayClient + + id, err := sqldedicatedgateway.ParseServiceID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + resp, err := client.ServiceGet(ctx, *id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return metadata.MarkAsGone(id) + } + + return fmt.Errorf("retrieving %s: %+v", *id, err) + } + + model := resp.Model + if model == nil { + return fmt.Errorf("retrieving %s: model was nil", id) + } + + state := CosmosDbSqlDedicatedGatewayModel{ + CosmosDbAccountId: cosmosdb.NewDatabaseAccountID(id.SubscriptionId, id.ResourceGroupName, id.AccountName).ID(), + } + + if props := model.Properties; props != nil { + existing := props.(sqldedicatedgateway.SqlDedicatedGatewayServiceResourceProperties) + + if existing.InstanceCount != nil { + state.InstanceCount = *existing.InstanceCount + } + + if existing.InstanceSize != nil { + state.InstanceSize = *existing.InstanceSize + } + } + + return metadata.Encode(&state) + }, + } +} + +func (r CosmosDbSqlDedicatedGatewayResource) Delete() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.Cosmos.SqlDedicatedGatewayClient + + id, err := sqldedicatedgateway.ParseServiceID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + if err := client.ServiceDeleteThenPoll(ctx, *id); err != nil { + return fmt.Errorf("deleting %s: %+v", id, err) + } + + return nil + }, + } +} diff --git a/internal/services/cosmos/cosmosdb_sql_dedicated_gateway_resource_test.go b/internal/services/cosmos/cosmosdb_sql_dedicated_gateway_resource_test.go new file mode 100644 index 000000000000..0e3ccbce5bb3 --- /dev/null +++ b/internal/services/cosmos/cosmosdb_sql_dedicated_gateway_resource_test.go @@ -0,0 +1,158 @@ +package cosmos_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/cosmosdb/2022-05-15/sqldedicatedgateway" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type CosmosDbSqlDedicatedGatewayResource struct{} + +func TestAccCosmosDbSqlDedicatedGateway_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_cosmosdb_sql_dedicated_gateway", "test") + r := CosmosDbSqlDedicatedGatewayResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccCosmosDbSqlDedicatedGateway_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_cosmosdb_sql_dedicated_gateway", "test") + r := CosmosDbSqlDedicatedGatewayResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func TestAccCosmosDbSqlDedicatedGateway_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_cosmosdb_sql_dedicated_gateway", "test") + r := CosmosDbSqlDedicatedGatewayResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.update(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func (r CosmosDbSqlDedicatedGatewayResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + id, err := sqldedicatedgateway.ParseServiceID(state.ID) + if err != nil { + return nil, err + } + + client := clients.Cosmos.SqlDedicatedGatewayClient + resp, err := client.ServiceGet(ctx, *id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return utils.Bool(false), nil + } + return nil, fmt.Errorf("retrieving %s: %+v", id, err) + } + return utils.Bool(resp.Model != nil), nil +} + +func (r CosmosDbSqlDedicatedGatewayResource) template(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctest-rg-%d" + location = "%s" +} + +resource "azurerm_cosmosdb_account" "test" { + name = "acctest-ca-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + offer_type = "Standard" + kind = "GlobalDocumentDB" + + consistency_policy { + consistency_level = "BoundedStaleness" + } + + geo_location { + location = azurerm_resource_group.test.location + failover_priority = 0 + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger) +} + +func (r CosmosDbSqlDedicatedGatewayResource) basic(data acceptance.TestData) string { + template := r.template(data) + + return fmt.Sprintf(` +%s + +resource "azurerm_cosmosdb_sql_dedicated_gateway" "test" { + cosmosdb_account_id = azurerm_cosmosdb_account.test.id + instance_size = "Cosmos.D4s" + instance_count = 1 +} +`, template) +} + +func (r CosmosDbSqlDedicatedGatewayResource) requiresImport(data acceptance.TestData) string { + config := r.basic(data) + + return fmt.Sprintf(` +%s + +resource "azurerm_cosmosdb_sql_dedicated_gateway" "import" { + cosmosdb_account_id = azurerm_cosmosdb_sql_dedicated_gateway.test.cosmosdb_account_id + instance_count = azurerm_cosmosdb_sql_dedicated_gateway.test.instance_count + instance_size = azurerm_cosmosdb_sql_dedicated_gateway.test.instance_size +} +`, config) +} + +func (r CosmosDbSqlDedicatedGatewayResource) update(data acceptance.TestData) string { + template := r.template(data) + + return fmt.Sprintf(` +%s + +resource "azurerm_cosmosdb_sql_dedicated_gateway" "test" { + cosmosdb_account_id = azurerm_cosmosdb_account.test.id + instance_size = "Cosmos.D4s" + instance_count = 2 +} +`, template) +} diff --git a/internal/services/cosmos/registration.go b/internal/services/cosmos/registration.go index 92cca6ee1851..7e19826f18f1 100644 --- a/internal/services/cosmos/registration.go +++ b/internal/services/cosmos/registration.go @@ -7,12 +7,25 @@ import ( type Registration struct{} -var _ sdk.UntypedServiceRegistrationWithAGitHubLabel = Registration{} +var ( + _ sdk.TypedServiceRegistration = Registration{} + _ sdk.UntypedServiceRegistrationWithAGitHubLabel = Registration{} +) func (r Registration) AssociatedGitHubLabel() string { return "service/cosmosdb" } +func (r Registration) DataSources() []sdk.DataSource { + return []sdk.DataSource{} +} + +func (r Registration) Resources() []sdk.Resource { + return []sdk.Resource{ + CosmosDbSqlDedicatedGatewayResource{}, + } +} + // Name is the name of this Service func (r Registration) Name() string { return "CosmosDB" diff --git a/internal/services/costmanagement/client/client.go b/internal/services/costmanagement/client/client.go index 7aad7f59b174..a72e8e4735eb 100644 --- a/internal/services/costmanagement/client/client.go +++ b/internal/services/costmanagement/client/client.go @@ -1,16 +1,16 @@ package client import ( - "github.com/Azure/azure-sdk-for-go/services/costmanagement/mgmt/2020-06-01/costmanagement" + "github.com/hashicorp/go-azure-sdk/resource-manager/costmanagement/2021-10-01/exports" "github.com/hashicorp/terraform-provider-azurerm/internal/common" ) type Client struct { - ExportClient *costmanagement.ExportsClient + ExportClient *exports.ExportsClient } func NewClient(o *common.ClientOptions) *Client { - ExportClient := costmanagement.NewExportsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + ExportClient := exports.NewExportsClientWithBaseURI(o.ResourceManagerEndpoint) o.ConfigureClient(&ExportClient.Client, o.ResourceManagerAuthorizer) return &Client{ diff --git a/internal/services/costmanagement/export_base_resource.go b/internal/services/costmanagement/export_base_resource.go index cb8ea970ab31..5595512d9900 100644 --- a/internal/services/costmanagement/export_base_resource.go +++ b/internal/services/costmanagement/export_base_resource.go @@ -5,11 +5,10 @@ import ( "fmt" "time" - "github.com/Azure/azure-sdk-for-go/services/costmanagement/mgmt/2020-06-01/costmanagement" - "github.com/Azure/go-autorest/autorest/date" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/costmanagement/2021-10-01/exports" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/costmanagement/parse" storageParse "github.com/hashicorp/terraform-provider-azurerm/internal/services/storage/parse" storageValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/storage/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" @@ -31,10 +30,10 @@ func (br costManagementExportBaseResource) arguments(fields map[string]*pluginsd Type: pluginsdk.TypeString, Required: true, ValidateFunc: validation.StringInSlice([]string{ - string(costmanagement.RecurrenceTypeDaily), - string(costmanagement.RecurrenceTypeWeekly), - string(costmanagement.RecurrenceTypeMonthly), - string(costmanagement.RecurrenceTypeAnnually), + string(exports.RecurrenceTypeDaily), + string(exports.RecurrenceTypeWeekly), + string(exports.RecurrenceTypeMonthly), + string(exports.RecurrenceTypeAnnually), }, false), }, @@ -82,9 +81,9 @@ func (br costManagementExportBaseResource) arguments(fields map[string]*pluginsd Type: pluginsdk.TypeString, Required: true, ValidateFunc: validation.StringInSlice([]string{ - string(costmanagement.ExportTypeActualCost), - string(costmanagement.ExportTypeAmortizedCost), - string(costmanagement.ExportTypeUsage), + string(exports.ExportTypeActualCost), + string(exports.ExportTypeAmortizedCost), + string(exports.ExportTypeUsage), }, false), }, @@ -92,12 +91,12 @@ func (br costManagementExportBaseResource) arguments(fields map[string]*pluginsd Type: pluginsdk.TypeString, Required: true, ValidateFunc: validation.StringInSlice([]string{ - string(costmanagement.Custom), - string(costmanagement.BillingMonthToDate), - string(costmanagement.TheLastBillingMonth), - string(costmanagement.TheLastMonth), - string(costmanagement.WeekToDate), - string(costmanagement.MonthToDate), + string(exports.TimeframeTypeCustom), + string(exports.TimeframeTypeBillingMonthToDate), + string(exports.TimeframeTypeTheLastBillingMonth), + string(exports.TimeframeTypeTheLastMonth), + string(exports.TimeframeTypeWeekToDate), + string(exports.TimeframeTypeMonthToDate), }, false), }, }, @@ -121,15 +120,16 @@ func (br costManagementExportBaseResource) createFunc(resourceName, scopeFieldNa Timeout: 30 * time.Minute, Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { client := metadata.Client.CostManagement.ExportClient - id := parse.NewCostManagementExportId(metadata.ResourceData.Get(scopeFieldName).(string), metadata.ResourceData.Get("name").(string)) - existing, err := client.Get(ctx, id.Scope, id.Name, "") + id := exports.NewScopedExportID(metadata.ResourceData.Get(scopeFieldName).(string), metadata.ResourceData.Get("name").(string)) + var opts exports.GetOperationOptions + existing, err := client.Get(ctx, id, opts) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return fmt.Errorf("checking for presence of existing %s: %+v", id, err) } } - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return tf.ImportAsExistsError(resourceName, id.ID()) } @@ -149,46 +149,48 @@ func (br costManagementExportBaseResource) readFunc(scopeFieldName string) sdk.R Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { client := metadata.Client.CostManagement.ExportClient - id, err := parse.CostManagementExportID(metadata.ResourceData.Id()) + id, err := exports.ParseScopedExportID(metadata.ResourceData.Id()) if err != nil { return err } - resp, err := client.Get(ctx, id.Scope, id.Name, "") + var opts exports.GetOperationOptions + resp, err := client.Get(ctx, *id, opts) if err != nil { - if !utils.ResponseWasNotFound(resp.Response) { + if !response.WasNotFound(resp.HttpResponse) { return metadata.MarkAsGone(id) } return fmt.Errorf("reading %s: %+v", *id, err) } - metadata.ResourceData.Set("name", id.Name) + metadata.ResourceData.Set("name", id.ExportName) //lintignore:R001 metadata.ResourceData.Set(scopeFieldName, id.Scope) - if schedule := resp.Schedule; schedule != nil { - if recurrencePeriod := schedule.RecurrencePeriod; recurrencePeriod != nil { - metadata.ResourceData.Set("recurrence_period_start_date", recurrencePeriod.From.Format(time.RFC3339)) - metadata.ResourceData.Set("recurrence_period_end_date", recurrencePeriod.To.Format(time.RFC3339)) + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + if schedule := props.Schedule; schedule != nil { + if recurrencePeriod := schedule.RecurrencePeriod; recurrencePeriod != nil { + metadata.ResourceData.Set("recurrence_period_start_date", recurrencePeriod.From) + metadata.ResourceData.Set("recurrence_period_end_date", recurrencePeriod.To) + } + status := *schedule.Status == exports.StatusTypeActive + + metadata.ResourceData.Set("active", status) + metadata.ResourceData.Set("recurrence_type", schedule.Recurrence) + } + + exportDeliveryInfo, err := flattenExportDataStorageLocation(&props.DeliveryInfo) + if err != nil { + return fmt.Errorf("flattening `export_data_storage_location`: %+v", err) + } + if err := metadata.ResourceData.Set("export_data_storage_location", exportDeliveryInfo); err != nil { + return fmt.Errorf("setting `export_data_storage_location`: %+v", err) + } + if err := metadata.ResourceData.Set("export_data_options", flattenExportDefinition(&props.Definition)); err != nil { + return fmt.Errorf("setting `export_data_options`: %+v", err) + } } - - status := schedule.Status == costmanagement.Active - - metadata.ResourceData.Set("active", status) - metadata.ResourceData.Set("recurrence_type", schedule.Recurrence) - } - - exportDeliveryInfo, err := flattenExportDataStorageLocation(resp.DeliveryInfo) - if err != nil { - return fmt.Errorf("flattening `export_data_storage_location`: %+v", err) - } - - if err := metadata.ResourceData.Set("export_data_storage_location", exportDeliveryInfo); err != nil { - return fmt.Errorf("setting `export_data_storage_location`: %+v", err) - } - - if err := metadata.ResourceData.Set("export_data_options", flattenExportDefinition(resp.Definition)); err != nil { - return fmt.Errorf("setting `export_data_options`: %+v", err) } return nil @@ -202,12 +204,12 @@ func (br costManagementExportBaseResource) deleteFunc() sdk.ResourceFunc { Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { client := metadata.Client.CostManagement.ExportClient - id, err := parse.CostManagementExportID(metadata.ResourceData.Id()) + id, err := exports.ParseScopedExportID(metadata.ResourceData.Id()) if err != nil { return err } - if _, err = client.Delete(ctx, id.Scope, id.Name); err != nil { + if _, err = client.Delete(ctx, *id); err != nil { return fmt.Errorf("deleting %s: %+v", *id, err) } @@ -222,20 +224,25 @@ func (br costManagementExportBaseResource) updateFunc() sdk.ResourceFunc { Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { client := metadata.Client.CostManagement.ExportClient - id, err := parse.CostManagementExportID(metadata.ResourceData.Id()) + id, err := exports.ParseScopedExportID(metadata.ResourceData.Id()) if err != nil { return err } // Update operation requires latest eTag to be set in the request. - resp, err := client.Get(ctx, id.Scope, id.Name, "") + var opts exports.GetOperationOptions + resp, err := client.Get(ctx, *id, opts) if err != nil { return fmt.Errorf("reading %s: %+v", *id, err) } - if resp.ETag == nil { - return fmt.Errorf("add %s: etag was nil", *id) + + if model := resp.Model; model != nil { + if model.ETag == nil { + return fmt.Errorf("add %s: etag was nil", *id) + } } - if err := createOrUpdateCostManagementExport(ctx, client, metadata, *id, resp.ETag); err != nil { + + if err := createOrUpdateCostManagementExport(ctx, client, metadata, *id, resp.Model.ETag); err != nil { return fmt.Errorf("updating %s: %+v", *id, err) } @@ -244,13 +251,10 @@ func (br costManagementExportBaseResource) updateFunc() sdk.ResourceFunc { } } -func createOrUpdateCostManagementExport(ctx context.Context, client *costmanagement.ExportsClient, metadata sdk.ResourceMetaData, id parse.CostManagementExportId, etag *string) error { - from, _ := time.Parse(time.RFC3339, metadata.ResourceData.Get("recurrence_period_start_date").(string)) - to, _ := time.Parse(time.RFC3339, metadata.ResourceData.Get("recurrence_period_end_date").(string)) - - status := costmanagement.Active +func createOrUpdateCostManagementExport(ctx context.Context, client *exports.ExportsClient, metadata sdk.ResourceMetaData, id exports.ScopedExportId, etag *string) error { + status := exports.StatusTypeActive if v := metadata.ResourceData.Get("active"); !v.(bool) { - status = costmanagement.Inactive + status = exports.StatusTypeInactive } deliveryInfo, err := expandExportDataStorageLocation(metadata.ResourceData.Get("export_data_storage_location").([]interface{})) @@ -258,29 +262,31 @@ func createOrUpdateCostManagementExport(ctx context.Context, client *costmanagem return fmt.Errorf("expanding `export_data_storage_location`: %+v", err) } - props := costmanagement.Export{ + format := exports.FormatTypeCsv + recurrenceType := exports.RecurrenceType(metadata.ResourceData.Get("recurrence_type").(string)) + props := exports.Export{ ETag: etag, - ExportProperties: &costmanagement.ExportProperties{ - Schedule: &costmanagement.ExportSchedule{ - Recurrence: costmanagement.RecurrenceType(metadata.ResourceData.Get("recurrence_type").(string)), - RecurrencePeriod: &costmanagement.ExportRecurrencePeriod{ - From: &date.Time{Time: from}, - To: &date.Time{Time: to}, + Properties: &exports.ExportProperties{ + Schedule: &exports.ExportSchedule{ + Recurrence: &recurrenceType, + RecurrencePeriod: &exports.ExportRecurrencePeriod{ + From: metadata.ResourceData.Get("recurrence_period_start_date").(string), + To: utils.String(metadata.ResourceData.Get("recurrence_period_end_date").(string)), }, - Status: status, + Status: &status, }, - DeliveryInfo: deliveryInfo, - Format: costmanagement.Csv, - Definition: expandExportDefinition(metadata.ResourceData.Get("export_data_options").([]interface{})), + DeliveryInfo: *deliveryInfo, + Format: &format, + Definition: *expandExportDefinition(metadata.ResourceData.Get("export_data_options").([]interface{})), }, } - _, err = client.CreateOrUpdate(ctx, id.Scope, id.Name, props) + _, err = client.CreateOrUpdate(ctx, id, props) return err } -func expandExportDataStorageLocation(input []interface{}) (*costmanagement.ExportDeliveryInfo, error) { +func expandExportDataStorageLocation(input []interface{}) (*exports.ExportDeliveryInfo, error) { if len(input) == 0 || input[0] == nil { return nil, nil } @@ -293,10 +299,10 @@ func expandExportDataStorageLocation(input []interface{}) (*costmanagement.Expor storageId := storageParse.NewStorageAccountID(containerId.SubscriptionId, containerId.ResourceGroup, containerId.StorageAccountName) - deliveryInfo := &costmanagement.ExportDeliveryInfo{ - Destination: &costmanagement.ExportDeliveryDestination{ - ResourceID: utils.String(storageId.ID()), - Container: utils.String(containerId.ContainerName), + deliveryInfo := &exports.ExportDeliveryInfo{ + Destination: exports.ExportDeliveryDestination{ + ResourceId: utils.String(storageId.ID()), + Container: containerId.ContainerName, RootFolderPath: utils.String(attrs["root_folder_path"].(string)), }, } @@ -304,22 +310,22 @@ func expandExportDataStorageLocation(input []interface{}) (*costmanagement.Expor return deliveryInfo, nil } -func expandExportDefinition(input []interface{}) *costmanagement.ExportDefinition { +func expandExportDefinition(input []interface{}) *exports.ExportDefinition { if len(input) == 0 || input[0] == nil { return nil } attrs := input[0].(map[string]interface{}) - definitionInfo := &costmanagement.ExportDefinition{ - Type: costmanagement.ExportType(attrs["type"].(string)), - Timeframe: costmanagement.TimeframeType(attrs["time_frame"].(string)), + definitionInfo := &exports.ExportDefinition{ + Type: exports.ExportType(attrs["type"].(string)), + Timeframe: exports.TimeframeType(attrs["time_frame"].(string)), } return definitionInfo } -func flattenExportDataStorageLocation(input *costmanagement.ExportDeliveryInfo) ([]interface{}, error) { - if input == nil || input.Destination == nil { +func flattenExportDataStorageLocation(input *exports.ExportDeliveryInfo) ([]interface{}, error) { + if input == nil { return []interface{}{}, nil } @@ -327,7 +333,7 @@ func flattenExportDataStorageLocation(input *costmanagement.ExportDeliveryInfo) var err error var storageAccountId *storageParse.StorageAccountId - if v := destination.ResourceID; v != nil { + if v := destination.ResourceId; v != nil { storageAccountId, err = storageParse.StorageAccountID(*v) if err != nil { return nil, err @@ -335,8 +341,8 @@ func flattenExportDataStorageLocation(input *costmanagement.ExportDeliveryInfo) } containerId := "" - if v := destination.Container; v != nil && storageAccountId != nil { - containerId = storageParse.NewStorageContainerResourceManagerID(storageAccountId.SubscriptionId, storageAccountId.ResourceGroup, storageAccountId.Name, "default", *v).ID() + if v := destination.Container; v != "" && storageAccountId != nil { + containerId = storageParse.NewStorageContainerResourceManagerID(storageAccountId.SubscriptionId, storageAccountId.ResourceGroup, storageAccountId.Name, "default", v).ID() } rootFolderPath := "" @@ -352,7 +358,7 @@ func flattenExportDataStorageLocation(input *costmanagement.ExportDeliveryInfo) }, nil } -func flattenExportDefinition(input *costmanagement.ExportDefinition) []interface{} { +func flattenExportDefinition(input *exports.ExportDefinition) []interface{} { if input == nil { return []interface{}{} } diff --git a/internal/services/costmanagement/export_resource_group_resource_test.go b/internal/services/costmanagement/export_resource_group_resource_test.go index ef412cef48f6..650a40b50852 100644 --- a/internal/services/costmanagement/export_resource_group_resource_test.go +++ b/internal/services/costmanagement/export_resource_group_resource_test.go @@ -6,10 +6,10 @@ import ( "testing" "time" + "github.com/hashicorp/go-azure-sdk/resource-manager/costmanagement/2021-10-01/exports" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/costmanagement/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -79,17 +79,18 @@ func TestAccResourceGroupCostManagementExport_requiresImport(t *testing.T) { } func (t ResourceGroupCostManagementExport) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.CostManagementExportID(state.ID) + id, err := exports.ParseScopedExportID(state.ID) if err != nil { return nil, err } - resp, err := clients.CostManagement.ExportClient.Get(ctx, id.Scope, id.Name, "") + var opts exports.GetOperationOptions + resp, err := clients.CostManagement.ExportClient.Get(ctx, *id, opts) if err != nil { return nil, fmt.Errorf("retrieving (%s): %+v", *id, err) } - return utils.Bool(resp.ExportProperties != nil), nil + return utils.Bool(resp.Model != nil), nil } func (ResourceGroupCostManagementExport) basic(data acceptance.TestData) string { diff --git a/internal/services/costmanagement/export_subscription_resource_test.go b/internal/services/costmanagement/export_subscription_resource_test.go index f4cd5e6460ca..905ab865b551 100644 --- a/internal/services/costmanagement/export_subscription_resource_test.go +++ b/internal/services/costmanagement/export_subscription_resource_test.go @@ -6,10 +6,10 @@ import ( "testing" "time" + "github.com/hashicorp/go-azure-sdk/resource-manager/costmanagement/2021-10-01/exports" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/costmanagement/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -79,17 +79,18 @@ func TestAccSubscriptionCostManagementExport_requiresImport(t *testing.T) { } func (t SubscriptionCostManagementExport) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.CostManagementExportID(state.ID) + id, err := exports.ParseScopedExportID(state.ID) if err != nil { return nil, err } - resp, err := clients.CostManagement.ExportClient.Get(ctx, id.Scope, id.Name, "") + var opts exports.GetOperationOptions + resp, err := clients.CostManagement.ExportClient.Get(ctx, *id, opts) if err != nil { return nil, fmt.Errorf("retrieving (%s): %+v", *id, err) } - return utils.Bool(resp.ExportProperties != nil), nil + return utils.Bool(resp.Model != nil), nil } func (SubscriptionCostManagementExport) basic(data acceptance.TestData) string { diff --git a/internal/services/dashboard/client/client.go b/internal/services/dashboard/client/client.go new file mode 100644 index 000000000000..e6ade515621c --- /dev/null +++ b/internal/services/dashboard/client/client.go @@ -0,0 +1,20 @@ +package client + +import ( + "github.com/hashicorp/go-azure-sdk/resource-manager/dashboard/2022-08-01/grafanaresource" + "github.com/hashicorp/terraform-provider-azurerm/internal/common" +) + +type Client struct { + GrafanaResourceClient *grafanaresource.GrafanaResourceClient +} + +func NewClient(o *common.ClientOptions) *Client { + + grafanaResourceClient := grafanaresource.NewGrafanaResourceClientWithBaseURI(o.ResourceManagerEndpoint) + o.ConfigureClient(&grafanaResourceClient.Client, o.ResourceManagerAuthorizer) + + return &Client{ + GrafanaResourceClient: &grafanaResourceClient, + } +} diff --git a/internal/services/dashboard/dashboard_grafana_resource.go b/internal/services/dashboard/dashboard_grafana_resource.go new file mode 100644 index 000000000000..3ae860e973da --- /dev/null +++ b/internal/services/dashboard/dashboard_grafana_resource.go @@ -0,0 +1,433 @@ +package dashboard + +import ( + "context" + "fmt" + "regexp" + "time" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/identity" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + + "github.com/hashicorp/go-azure-sdk/resource-manager/dashboard/2022-08-01/grafanaresource" + "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type DashboardGrafanaModel struct { + Name string `tfschema:"name"` + ResourceGroupName string `tfschema:"resource_group_name"` + ApiKeyEnabled bool `tfschema:"api_key_enabled"` + AutoGeneratedDomainNameLabelScope grafanaresource.AutoGeneratedDomainNameLabelScope `tfschema:"auto_generated_domain_name_label_scope"` + DeterministicOutboundIPEnabled bool `tfschema:"deterministic_outbound_ip_enabled"` + Location string `tfschema:"location"` + PublicNetworkAccessEnabled bool `tfschema:"public_network_access_enabled"` + Sku string `tfschema:"sku"` + Tags map[string]string `tfschema:"tags"` + ZoneRedundancyEnabled bool `tfschema:"zone_redundancy_enabled"` + Endpoint string `tfschema:"endpoint"` + GrafanaVersion string `tfschema:"grafana_version"` + OutboundIPs []string `tfschema:"outbound_ip"` +} + +type DashboardGrafanaResource struct{} + +var _ sdk.ResourceWithUpdate = DashboardGrafanaResource{} + +func (r DashboardGrafanaResource) ResourceType() string { + return "azurerm_dashboard_grafana" +} + +func (r DashboardGrafanaResource) ModelObject() interface{} { + return &DashboardGrafanaModel{} +} + +func (r DashboardGrafanaResource) IDValidationFunc() pluginsdk.SchemaValidateFunc { + return grafanaresource.ValidateGrafanaID +} + +func (r DashboardGrafanaResource) Arguments() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringMatch( + regexp.MustCompile(`^[a-zA-Z][-a-zA-Z\d]{0,21}[a-zA-Z\d]$`), + `The name length must be from 2 to 23 characters. The name can only contain letters, numbers and dashes, and it must begin with a letter and end with a letter or digit.`, + ), + }, + + "resource_group_name": commonschema.ResourceGroupName(), + + "location": commonschema.Location(), + + "api_key_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: false, + }, + + "auto_generated_domain_name_label_scope": { + Type: pluginsdk.TypeString, + Optional: true, + Default: string(grafanaresource.AutoGeneratedDomainNameLabelScopeTenantReuse), + ValidateFunc: validation.StringInSlice([]string{ + string(grafanaresource.AutoGeneratedDomainNameLabelScopeTenantReuse), + }, false), + }, + + "deterministic_outbound_ip_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: false, + }, + + "identity": commonschema.SystemAssignedIdentityOptionalForceNew(), + + "public_network_access_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: true, + }, + + "sku": { + Type: pluginsdk.TypeString, + Optional: true, + ForceNew: true, + Default: "Standard", + ValidateFunc: validation.StringInSlice([]string{ + "Standard", + }, false), + }, + + "tags": commonschema.Tags(), + + "zone_redundancy_enabled": { + Type: pluginsdk.TypeBool, + ForceNew: true, + Optional: true, + Default: false, + }, + } +} + +func (r DashboardGrafanaResource) Attributes() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "endpoint": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "grafana_version": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "outbound_ip": { + Type: pluginsdk.TypeList, + Computed: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + }, + }, + } +} + +func (r DashboardGrafanaResource) Create() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + var model DashboardGrafanaModel + if err := metadata.Decode(&model); err != nil { + return fmt.Errorf("decoding: %+v", err) + } + + client := metadata.Client.Dashboard.GrafanaResourceClient + subscriptionId := metadata.Client.Account.SubscriptionId + id := grafanaresource.NewGrafanaID(subscriptionId, model.ResourceGroupName, model.Name) + existing, err := client.GrafanaGet(ctx, id) + if err != nil && !response.WasNotFound(existing.HttpResponse) { + return fmt.Errorf("checking for existing %s: %+v", id, err) + } + + if !response.WasNotFound(existing.HttpResponse) { + return metadata.ResourceRequiresImport(r.ResourceType(), id) + } + + identityValue, err := expandLegacySystemAndUserAssignedMap(metadata.ResourceData.Get("identity").([]interface{})) + if err != nil { + return fmt.Errorf("expanding `identity`: %+v", err) + } + + apiKey := grafanaresource.ApiKeyDisabled + if model.ApiKeyEnabled { + apiKey = grafanaresource.ApiKeyEnabled + } + + deterministicOutboundIP := grafanaresource.DeterministicOutboundIPDisabled + if model.DeterministicOutboundIPEnabled { + deterministicOutboundIP = grafanaresource.DeterministicOutboundIPEnabled + } + + publicNetworkAccess := grafanaresource.PublicNetworkAccessDisabled + if model.PublicNetworkAccessEnabled { + publicNetworkAccess = grafanaresource.PublicNetworkAccessEnabled + } + + zoneRedundancy := grafanaresource.ZoneRedundancyDisabled + if model.ZoneRedundancyEnabled { + zoneRedundancy = grafanaresource.ZoneRedundancyEnabled + } + + properties := &grafanaresource.ManagedGrafana{ + Identity: identityValue, + Location: utils.String(location.Normalize(model.Location)), + Properties: &grafanaresource.ManagedGrafanaProperties{ + ApiKey: &apiKey, + AutoGeneratedDomainNameLabelScope: &model.AutoGeneratedDomainNameLabelScope, + DeterministicOutboundIP: &deterministicOutboundIP, + PublicNetworkAccess: &publicNetworkAccess, + ZoneRedundancy: &zoneRedundancy, + }, + Sku: &grafanaresource.ResourceSku{ + Name: model.Sku, + }, + Tags: &model.Tags, + } + + if err := client.GrafanaCreateThenPoll(ctx, id, *properties); err != nil { + return fmt.Errorf("creating %s: %+v", id, err) + } + + metadata.SetID(id) + return nil + }, + } +} + +func (r DashboardGrafanaResource) Update() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.Dashboard.GrafanaResourceClient + + id, err := grafanaresource.ParseGrafanaID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + var model DashboardGrafanaModel + if err := metadata.Decode(&model); err != nil { + return fmt.Errorf("decoding: %+v", err) + } + + resp, err := client.GrafanaGet(ctx, *id) + if err != nil { + return fmt.Errorf("retrieving %s: %+v", *id, err) + } + + properties := resp.Model + if properties == nil { + return fmt.Errorf("retrieving %s: properties was nil", id) + } + + if metadata.ResourceData.HasChange("api_key_enabled") { + apiKey := grafanaresource.ApiKeyDisabled + if model.ApiKeyEnabled { + apiKey = grafanaresource.ApiKeyEnabled + } + + properties.Properties.ApiKey = &apiKey + } + + if metadata.ResourceData.HasChange("auto_generated_domain_name_label_scope") { + properties.Properties.AutoGeneratedDomainNameLabelScope = &model.AutoGeneratedDomainNameLabelScope + } + + if metadata.ResourceData.HasChange("deterministic_outbound_ip_enabled") { + deterministicOutboundIP := grafanaresource.DeterministicOutboundIPDisabled + if model.DeterministicOutboundIPEnabled { + deterministicOutboundIP = grafanaresource.DeterministicOutboundIPEnabled + } + + properties.Properties.DeterministicOutboundIP = &deterministicOutboundIP + } + + if metadata.ResourceData.HasChange("public_network_access_enabled") { + publicNetworkAccess := grafanaresource.PublicNetworkAccessDisabled + if model.PublicNetworkAccessEnabled { + publicNetworkAccess = grafanaresource.PublicNetworkAccessEnabled + } + + properties.Properties.PublicNetworkAccess = &publicNetworkAccess + } + + properties.SystemData = nil + + if metadata.ResourceData.HasChange("tags") { + properties.Tags = &model.Tags + } + + if err := client.GrafanaCreateThenPoll(ctx, *id, *properties); err != nil { + return fmt.Errorf("updating %s: %+v", *id, err) + } + + return nil + }, + } +} + +func (r DashboardGrafanaResource) Read() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 5 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.Dashboard.GrafanaResourceClient + + id, err := grafanaresource.ParseGrafanaID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + resp, err := client.GrafanaGet(ctx, *id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return metadata.MarkAsGone(id) + } + + return fmt.Errorf("retrieving %s: %+v", *id, err) + } + + model := resp.Model + if model == nil { + return fmt.Errorf("retrieving %s: model was nil", id) + } + + state := DashboardGrafanaModel{ + Name: id.WorkspaceName, + ResourceGroupName: id.ResourceGroupName, + Location: location.NormalizeNilable(model.Location), + } + + identityValue, err := flattenLegacySystemAndUserAssignedMap(model.Identity) + if err != nil { + return fmt.Errorf("flattening `identity`: %+v", err) + } + + if err := metadata.ResourceData.Set("identity", identityValue); err != nil { + return fmt.Errorf("setting `identity`: %+v", err) + } + + if properties := model.Properties; properties != nil { + if properties.ApiKey != nil { + if *properties.ApiKey == grafanaresource.ApiKeyEnabled { + state.ApiKeyEnabled = true + } else { + state.ApiKeyEnabled = false + } + } + + if properties.AutoGeneratedDomainNameLabelScope != nil { + state.AutoGeneratedDomainNameLabelScope = *properties.AutoGeneratedDomainNameLabelScope + } + + if properties.DeterministicOutboundIP != nil { + if *properties.DeterministicOutboundIP == grafanaresource.DeterministicOutboundIPEnabled { + state.DeterministicOutboundIPEnabled = true + } else { + state.DeterministicOutboundIPEnabled = false + } + } + + if properties.Endpoint != nil { + state.Endpoint = *properties.Endpoint + } + + if properties.GrafanaVersion != nil { + state.GrafanaVersion = *properties.GrafanaVersion + } + + if properties.OutboundIPs != nil { + state.OutboundIPs = *properties.OutboundIPs + } + + if properties.PublicNetworkAccess != nil { + if *properties.PublicNetworkAccess == grafanaresource.PublicNetworkAccessEnabled { + state.PublicNetworkAccessEnabled = true + } else { + state.PublicNetworkAccessEnabled = false + } + } + + if properties.ZoneRedundancy != nil { + if *properties.ZoneRedundancy == grafanaresource.ZoneRedundancyEnabled { + state.ZoneRedundancyEnabled = true + } else { + state.ZoneRedundancyEnabled = false + } + } + } + + if model.Sku != nil { + state.Sku = model.Sku.Name + } + + if model.Tags != nil { + state.Tags = *model.Tags + } + + return metadata.Encode(&state) + }, + } +} + +func (r DashboardGrafanaResource) Delete() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.Dashboard.GrafanaResourceClient + + id, err := grafanaresource.ParseGrafanaID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + if err := client.GrafanaDeleteThenPoll(ctx, *id); err != nil { + return fmt.Errorf("deleting %s: %+v", id, err) + } + + return nil + }, + } +} + +func expandLegacySystemAndUserAssignedMap(input []interface{}) (*identity.LegacySystemAndUserAssignedMap, error) { + identityValue, err := identity.ExpandSystemAssigned(input) + if err != nil { + return nil, err + } + + return &identity.LegacySystemAndUserAssignedMap{ + Type: identityValue.Type, + }, nil +} + +func flattenLegacySystemAndUserAssignedMap(input *identity.LegacySystemAndUserAssignedMap) (*[]interface{}, error) { + if input == nil { + return &[]interface{}{}, nil + } + + identityValue := &identity.SystemAssigned{ + Type: input.Type, + PrincipalId: input.PrincipalId, + TenantId: input.TenantId, + } + + output := identity.FlattenSystemAssigned(identityValue) + return &output, nil +} diff --git a/internal/services/dashboard/dashboard_grafana_resource_test.go b/internal/services/dashboard/dashboard_grafana_resource_test.go new file mode 100644 index 000000000000..775f0fa9466e --- /dev/null +++ b/internal/services/dashboard/dashboard_grafana_resource_test.go @@ -0,0 +1,182 @@ +package dashboard_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/go-azure-sdk/resource-manager/dashboard/2022-08-01/grafanaresource" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type DashboardGrafanaResource struct{} + +func TestAccDashboardGrafana_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_dashboard_grafana", "test") + r := DashboardGrafanaResource{} + data.ResourceSequentialTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccDashboardGrafana_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_dashboard_grafana", "test") + r := DashboardGrafanaResource{} + data.ResourceSequentialTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func TestAccDashboardGrafana_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_dashboard_grafana", "test") + r := DashboardGrafanaResource{} + data.ResourceSequentialTest(t, r, []acceptance.TestStep{ + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccDashboardGrafana_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_dashboard_grafana", "test") + r := DashboardGrafanaResource{} + data.ResourceSequentialTest(t, r, []acceptance.TestStep{ + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.update(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func (r DashboardGrafanaResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + id, err := grafanaresource.ParseGrafanaID(state.ID) + if err != nil { + return nil, err + } + + client := clients.Dashboard.GrafanaResourceClient + resp, err := client.GrafanaGet(ctx, *id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return utils.Bool(false), nil + } + return nil, fmt.Errorf("retrieving %s: %+v", id, err) + } + return utils.Bool(resp.Model != nil), nil +} + +func (r DashboardGrafanaResource) template(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctest-rg-%d" + location = "%s" +} +`, data.RandomInteger, data.Locations.Primary) +} + +func (r DashboardGrafanaResource) basic(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` + %s + +resource "azurerm_dashboard_grafana" "test" { + name = "a-dg-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location +} +`, template, data.RandomInteger) +} + +func (r DashboardGrafanaResource) requiresImport(data acceptance.TestData) string { + config := r.basic(data) + return fmt.Sprintf(` + %s + +resource "azurerm_dashboard_grafana" "import" { + name = azurerm_dashboard_grafana.test.name + resource_group_name = azurerm_dashboard_grafana.test.resource_group_name + location = azurerm_dashboard_grafana.test.location +} +`, config) +} + +func (r DashboardGrafanaResource) complete(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` + %s + +resource "azurerm_dashboard_grafana" "test" { + name = "a-dg-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + api_key_enabled = true + deterministic_outbound_ip_enabled = true + public_network_access_enabled = false + + identity { + type = "SystemAssigned" + } + + tags = { + key = "value" + } +} +`, template, data.RandomInteger) +} + +func (r DashboardGrafanaResource) update(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` + %s + +resource "azurerm_dashboard_grafana" "test" { + name = "a-dg-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + + identity { + type = "SystemAssigned" + } + + tags = { + key2 = "value2" + } +} +`, template, data.RandomInteger) +} diff --git a/internal/services/dashboard/registration.go b/internal/services/dashboard/registration.go new file mode 100644 index 000000000000..8ee47c4e3879 --- /dev/null +++ b/internal/services/dashboard/registration.go @@ -0,0 +1,51 @@ +package dashboard + +import ( + "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" +) + +type Registration struct{} + +var ( + _ sdk.TypedServiceRegistrationWithAGitHubLabel = Registration{} + _ sdk.UntypedServiceRegistrationWithAGitHubLabel = Registration{} +) + +func (r Registration) AssociatedGitHubLabel() string { + return "service/dashboard" +} + +// Name is the name of this Service +func (r Registration) Name() string { + return "Dashboard" +} + +// WebsiteCategories returns a list of categories which can be used for the sidebar +func (r Registration) WebsiteCategories() []string { + return []string{ + "Dashboard", + } +} + +// SupportedDataSources returns the supported Data Sources supported by this Service +func (r Registration) SupportedDataSources() map[string]*pluginsdk.Resource { + return map[string]*pluginsdk.Resource{} +} + +// SupportedResources returns the supported Resources supported by this Service +func (r Registration) SupportedResources() map[string]*pluginsdk.Resource { + return map[string]*pluginsdk.Resource{} +} + +// DataSources returns a list of Data Sources supported by this Service +func (r Registration) DataSources() []sdk.DataSource { + return []sdk.DataSource{} +} + +// Resources returns a list of Resources supported by this Service +func (r Registration) Resources() []sdk.Resource { + return []sdk.Resource{ + DashboardGrafanaResource{}, + } +} diff --git a/internal/services/databricks/databricks_workspace_resource.go b/internal/services/databricks/databricks_workspace_resource.go index 3a930d0e060a..01284e50000b 100644 --- a/internal/services/databricks/databricks_workspace_resource.go +++ b/internal/services/databricks/databricks_workspace_resource.go @@ -684,7 +684,7 @@ func flattenWorkspaceCustomParameters(input *workspaces.WorkspaceCustomParameter parameters["nat_gateway_name"] = v.Value } - if v := input.PublicIpName; v != nil { + if v := input.PublicIPName; v != nil { parameters["public_ip_name"] = v.Value } @@ -704,7 +704,7 @@ func flattenWorkspaceCustomParameters(input *workspaces.WorkspaceCustomParameter parameters["machine_learning_workspace_id"] = v.Value } - if v := input.EnableNoPublicIp; v != nil { + if v := input.EnableNoPublicIP; v != nil { parameters["no_public_ip"] = v.Value } @@ -779,7 +779,7 @@ func expandWorkspaceCustomParameters(input []interface{}, customerManagedKeyEnab } if v, ok := config["public_ip_name"].(string); ok && v != "" { - parameters.PublicIpName = &workspaces.WorkspaceCustomStringParameter{ + parameters.PublicIPName = &workspaces.WorkspaceCustomStringParameter{ Value: v, } } @@ -809,7 +809,7 @@ func expandWorkspaceCustomParameters(input []interface{}, customerManagedKeyEnab } if v, ok := config["no_public_ip"].(bool); ok { - parameters.EnableNoPublicIp = &workspaces.WorkspaceCustomBooleanParameter{ + parameters.EnableNoPublicIP = &workspaces.WorkspaceCustomBooleanParameter{ Value: v, } } diff --git a/internal/services/datadog/client/client.go b/internal/services/datadog/client/client.go new file mode 100644 index 000000000000..8cc3beea0e73 --- /dev/null +++ b/internal/services/datadog/client/client.go @@ -0,0 +1,19 @@ +package client + +import ( + "github.com/Azure/azure-sdk-for-go/services/datadog/mgmt/2021-03-01/datadog" + "github.com/hashicorp/terraform-provider-azurerm/internal/common" +) + +type Client struct { + MonitorsClient *datadog.MonitorsClient +} + +func NewClient(o *common.ClientOptions) *Client { + monitorsClient := datadog.NewMonitorsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&monitorsClient.Client, o.ResourceManagerAuthorizer) + + return &Client{ + MonitorsClient: &monitorsClient, + } +} diff --git a/internal/services/datadog/datadog_monitors_resource.go b/internal/services/datadog/datadog_monitors_resource.go new file mode 100644 index 000000000000..9c38057eaa02 --- /dev/null +++ b/internal/services/datadog/datadog_monitors_resource.go @@ -0,0 +1,429 @@ +package datadog + +import ( + "fmt" + "log" + "time" + + "github.com/Azure/azure-sdk-for-go/services/datadog/mgmt/2021-03-01/datadog" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" + "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/datadog/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/datadog/validate" + "github.com/hashicorp/terraform-provider-azurerm/internal/tags" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +func resourceDatadogMonitor() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Create: resourceDatadogMonitorCreate, + Read: resourceDatadogMonitorRead, + Update: resourceDatadogMonitorUpdate, + Delete: resourceDatadogMonitorDelete, + + Timeouts: &pluginsdk.ResourceTimeout{ + Create: pluginsdk.DefaultTimeout(30 * time.Minute), + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + Update: pluginsdk.DefaultTimeout(30 * time.Minute), + Delete: pluginsdk.DefaultTimeout(30 * time.Minute), + }, + + Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { + _, err := parse.DatadogMonitorID(id) + return err + }), + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.DatadogMonitorsName, + }, + + "resource_group_name": azure.SchemaResourceGroupName(), + + "location": azure.SchemaLocation(), + + "datadog_organization": { + Type: pluginsdk.TypeList, + Required: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "api_key": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + Sensitive: true, + }, + + "application_key": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + Sensitive: true, + }, + + "enterprise_app_id": { + Type: pluginsdk.TypeString, + Optional: true, + ForceNew: true, + }, + + "linking_auth_code": { + Type: pluginsdk.TypeString, + Optional: true, + ForceNew: true, + Sensitive: true, + }, + + "linking_client_id": { + Type: pluginsdk.TypeString, + Optional: true, + ForceNew: true, + Sensitive: true, + }, + + "redirect_uri": { + Type: pluginsdk.TypeString, + Optional: true, + ForceNew: true, + }, + + "id": { + Type: pluginsdk.TypeString, + Computed: true, + }, + }, + }, + }, + + "identity": commonschema.SystemAssignedIdentityOptional(), + + "sku_name": { + Type: pluginsdk.TypeString, + Required: true, + DiffSuppressFunc: SkuNameDiffSuppress, + }, + + "user": { + Type: pluginsdk.TypeList, + Required: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.DatadogUsersName, + }, + + "email": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.DatadogMonitorsEmailAddress, + }, + + "phone_number": { + Type: pluginsdk.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validate.DatadogMonitorsPhoneNumber, + }, + }, + }, + }, + + "monitoring_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: true, + }, + + "marketplace_subscription_status": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "tags": tags.Schema(), + }, + } +} + +func resourceDatadogMonitorCreate(d *pluginsdk.ResourceData, meta interface{}) error { + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + client := meta.(*clients.Client).Datadog.MonitorsClient + ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) + defer cancel() + + name := d.Get("name").(string) + resourceGroup := d.Get("resource_group_name").(string) + + id := parse.NewDatadogMonitorID(subscriptionId, resourceGroup, name) + + existing, err := client.Get(ctx, resourceGroup, name) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("checking for existing %s: %+v", id, err) + } + } + if !utils.ResponseWasNotFound(existing.Response) { + return tf.ImportAsExistsError("azurerm_datadog_monitor", id.ID()) + } + + monitoringStatus := datadog.MonitoringStatusDisabled + if d.Get("monitoring_enabled").(bool) { + monitoringStatus = datadog.MonitoringStatusEnabled + } + + body := datadog.MonitorResource{ + Location: utils.String(location.Normalize(d.Get("location").(string))), + Identity: expandMonitorIdentityProperties(d.Get("identity").([]interface{})), + Sku: &datadog.ResourceSku{ + Name: utils.String(d.Get("sku_name").(string)), + }, + Properties: &datadog.MonitorProperties{ + DatadogOrganizationProperties: expandMonitorOrganizationProperties(d.Get("datadog_organization").([]interface{})), + UserInfo: expandMonitorUserInfo(d.Get("user").([]interface{})), + MonitoringStatus: monitoringStatus, + }, + Tags: tags.Expand(d.Get("tags").(map[string]interface{})), + } + future, err := client.Create(ctx, resourceGroup, name, &body) + if err != nil { + return fmt.Errorf("creating %s: %+v", id, err) + } + + if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for creation of %s: %+v", id, err) + } + + d.SetId(id.ID()) + return resourceDatadogMonitorRead(d, meta) +} + +func resourceDatadogMonitorRead(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Datadog.MonitorsClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.DatadogMonitorID(d.Id()) + if err != nil { + return err + } + + resp, err := client.Get(ctx, id.ResourceGroup, id.MonitorName) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[INFO] Datadog monitor %q does not exist - removing from state", d.Id()) + d.SetId("") + return nil + } + return fmt.Errorf("retrieving %s: %+v", id, err) + } + + d.Set("name", id.MonitorName) + d.Set("resource_group_name", id.ResourceGroup) + d.Set("location", location.NormalizeNilable(resp.Location)) + if err := d.Set("identity", flattenMonitorIdentityProperties(resp.Identity)); err != nil { + return fmt.Errorf("setting `identity`: %+v", err) + } + if props := resp.Properties; props != nil { + if err := d.Set("datadog_organization", flattenMonitorOrganizationProperties(props.DatadogOrganizationProperties, d)); err != nil { + return fmt.Errorf("setting `datadog_organization`: %+v", err) + } + d.Set("monitoring_enabled", props.MonitoringStatus == datadog.MonitoringStatusEnabled) + d.Set("marketplace_subscription_status", props.MarketplaceSubscriptionStatus) + } + if resp.Sku != nil { + d.Set("sku_name", *resp.Sku.Name) + } + + return tags.FlattenAndSet(d, resp.Tags) +} + +func resourceDatadogMonitorUpdate(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Datadog.MonitorsClient + ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.DatadogMonitorID(d.Id()) + if err != nil { + return err + } + + body := datadog.MonitorResourceUpdateParameters{ + Properties: &datadog.MonitorUpdateProperties{}, + } + if d.HasChange("sku_name") { + body.Sku = &datadog.ResourceSku{Name: utils.String(d.Get("sku_name").(string))} + } + if d.HasChange("monitoring_enabled") { + monitoringStatus := datadog.MonitoringStatusDisabled + if d.Get("monitoring_enabled").(bool) { + monitoringStatus = datadog.MonitoringStatusEnabled + } + body.Properties.MonitoringStatus = monitoringStatus + } + if d.HasChange("tags") { + body.Tags = tags.Expand(d.Get("tags").(map[string]interface{})) + } + + future, err := client.Update(ctx, id.ResourceGroup, id.MonitorName, &body) + if err != nil { + return fmt.Errorf("updating %s: %+v", id, err) + } + if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for updating of %s: %+v", id, err) + } + return resourceDatadogMonitorRead(d, meta) +} + +func resourceDatadogMonitorDelete(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Datadog.MonitorsClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.DatadogMonitorID(d.Id()) + if err != nil { + return err + } + + future, err := client.Delete(ctx, id.ResourceGroup, id.MonitorName) + if err != nil { + return fmt.Errorf("deleting of %s: %+v", id, err) + } + + if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for deletion of %s: %+v", id, err) + } + return nil +} + +func SkuNameDiffSuppress(_, old, new string, _ *pluginsdk.ResourceData) bool { + // During creating, accepts any sku name. + if old == "" { + return false + } + // Sku name of the datadog monitor has two kinds: + // - Concrete sku: E.g. "payg_v2_Monthly". These will be returned unchanged by API. + // - Linked sku: The value is named "Linked". This will be accepted and changed by the API, which will then return you the linked concrete sku. + if new == "Linked" { + return true + } + return old == new +} + +func expandMonitorIdentityProperties(input []interface{}) *datadog.IdentityProperties { + if len(input) == 0 { + return nil + } + v := input[0].(map[string]interface{}) + return &datadog.IdentityProperties{ + Type: datadog.ManagedIdentityTypes(v["type"].(string)), + } +} + +func expandMonitorOrganizationProperties(input []interface{}) *datadog.OrganizationProperties { + if len(input) == 0 || input[0] == nil { + return nil + } + v := input[0].(map[string]interface{}) + return &datadog.OrganizationProperties{ + LinkingAuthCode: utils.String(v["linking_auth_code"].(string)), + LinkingClientID: utils.String(v["linking_client_id"].(string)), + RedirectURI: utils.String(v["redirect_uri"].(string)), + APIKey: utils.String(v["api_key"].(string)), + ApplicationKey: utils.String(v["application_key"].(string)), + EnterpriseAppID: utils.String(v["enterprise_app_id"].(string)), + } +} + +func expandMonitorUserInfo(input []interface{}) *datadog.UserInfo { + if len(input) == 0 || input[0] == nil { + return nil + } + v := input[0].(map[string]interface{}) + return &datadog.UserInfo{ + Name: utils.String(v["name"].(string)), + EmailAddress: utils.String(v["email"].(string)), + PhoneNumber: utils.String(v["phone_number"].(string)), + } +} + +func flattenMonitorIdentityProperties(input *datadog.IdentityProperties) []interface{} { + if input == nil { + return make([]interface{}, 0) + } + + var t datadog.ManagedIdentityTypes + if input.Type != "" { + t = input.Type + } + var principalId string + if input.PrincipalID != nil { + principalId = *input.PrincipalID + } + var tenantId string + if input.TenantID != nil { + tenantId = *input.TenantID + } + return []interface{}{ + map[string]interface{}{ + "type": t, + "principal_id": principalId, + "tenant_id": tenantId, + }, + } +} + +func flattenMonitorOrganizationProperties(input *datadog.OrganizationProperties, d *pluginsdk.ResourceData) []interface{} { + + organisationProperties := d.Get("datadog_organization").([]interface{}) + if len(organisationProperties) == 0 { + return make([]interface{}, 0) + } + v := organisationProperties[0].(map[string]interface{}) + + var name string + if input.Name != nil { + name = *input.Name + } + var id string + if input.ID != nil { + id = *input.ID + } + var redirectUri string + if input.RedirectURI != nil { + redirectUri = *input.RedirectURI + } + var enterpriseAppID string + if input.EnterpriseAppID != nil { + enterpriseAppID = *input.EnterpriseAppID + } + return []interface{}{ + map[string]interface{}{ + "name": name, + "api_key": utils.String(v["api_key"].(string)), + "application_key": utils.String(v["application_key"].(string)), + "enterprise_app_id": enterpriseAppID, + "linking_auth_code": utils.String(v["linking_auth_code"].(string)), + "linking_client_id": utils.String(v["linking_client_id"].(string)), + "redirect_uri": redirectUri, + "id": id, + }, + } +} diff --git a/internal/services/datadog/datadog_monitors_resource_test.go b/internal/services/datadog/datadog_monitors_resource_test.go new file mode 100644 index 000000000000..f46bd1405be0 --- /dev/null +++ b/internal/services/datadog/datadog_monitors_resource_test.go @@ -0,0 +1,303 @@ +package datadog_test + +import ( + "context" + "fmt" + "os" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/datadog/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type DatadogMonitorResource struct{} + +func TestAccDatadogMonitor_basic(t *testing.T) { + if os.Getenv("ARM_TEST_DATADOG_API_KEY") == "" || os.Getenv("ARM_TEST_DATADOG_APPLICATION_KEY") == "" { + t.Skip("Skipping as ARM_TEST_DATADOG_API_KEY and/or ARM_TEST_DATADOG_APPLICATION_KEY are not specified") + return + } + data := acceptance.BuildTestData(t, "azurerm_datadog_monitor", "test") + r := DatadogMonitorResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("user", + "user.0.name", + "user.0.email", + "datadog_organization", + "datadog_organization.0", + "datadog_organization.0.id", + "datadog_organization.0.name", + "datadog_organization.0.api_key", + "datadog_organization.0.application_key", + "datadog_organization.0.enterprise_app_id", + "datadog_organization.0.linking_auth_code", + "datadog_organization.0.linking_client_id", + "datadog_organization.0.redirect_uri"), + }) +} + +func TestAccDatadogMonitor_requiresImport(t *testing.T) { + if os.Getenv("ARM_TEST_DATADOG_API_KEY") == "" || os.Getenv("ARM_TEST_DATADOG_APPLICATION_KEY") == "" { + t.Skip("Skipping as ARM_TEST_DATADOG_API_KEY and/or ARM_TEST_DATADOG_APPLICATION_KEY are not specified") + return + } + data := acceptance.BuildTestData(t, "azurerm_datadog_monitor", "test") + r := DatadogMonitorResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func TestAccDatadogMonitor_complete(t *testing.T) { + if os.Getenv("ARM_TEST_DATADOG_API_KEY") == "" || os.Getenv("ARM_TEST_DATADOG_APPLICATION_KEY") == "" { + t.Skip("Skipping as ARM_TEST_DATADOG_API_KEY and/or ARM_TEST_DATADOG_APPLICATION_KEY are not specified") + return + } + data := acceptance.BuildTestData(t, "azurerm_datadog_monitor", "test") + r := DatadogMonitorResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("user", + "user.0.name", + "user.0.email", + "datadog_organization", + "datadog_organization.0", + "datadog_organization.0.id", + "datadog_organization.0.name", + "datadog_organization.0.api_key", + "datadog_organization.0.application_key", + "datadog_organization.0.enterprise_app_id", + "datadog_organization.0.linking_auth_code", + "datadog_organization.0.linking_client_id", + "datadog_organization.0.redirect_uri"), + }) +} + +func TestAccDatadogMonitor_update(t *testing.T) { + if os.Getenv("ARM_TEST_DATADOG_API_KEY") == "" || os.Getenv("ARM_TEST_DATADOG_APPLICATION_KEY") == "" { + t.Skip("Skipping as ARM_TEST_DATADOG_API_KEY and/or ARM_TEST_DATADOG_APPLICATION_KEY are not specified") + return + } + data := acceptance.BuildTestData(t, "azurerm_datadog_monitor", "test") + r := DatadogMonitorResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("user", + "user.0.name", + "user.0.email", + "datadog_organization", + "datadog_organization.0", + "datadog_organization.0.id", + "datadog_organization.0.name", + "datadog_organization.0.api_key", + "datadog_organization.0.application_key", + "datadog_organization.0.enterprise_app_id", + "datadog_organization.0.linking_auth_code", + "datadog_organization.0.linking_client_id", + "datadog_organization.0.redirect_uri"), + { + Config: r.update(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("user", + "user.0.name", + "user.0.email", + "datadog_organization", + "datadog_organization.0", + "datadog_organization.0.id", + "datadog_organization.0.name", + "datadog_organization.0.api_key", + "datadog_organization.0.application_key", + "datadog_organization.0.enterprise_app_id", + "datadog_organization.0.linking_auth_code", + "datadog_organization.0.linking_client_id", + "datadog_organization.0.redirect_uri"), + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("user", + "user.0.name", + "user.0.email", + "datadog_organization", + "datadog_organization.0", + "datadog_organization.0.id", + "datadog_organization.0.name", + "datadog_organization.0.api_key", + "datadog_organization.0.application_key", + "datadog_organization.0.enterprise_app_id", + "datadog_organization.0.linking_auth_code", + "datadog_organization.0.linking_client_id", + "datadog_organization.0.redirect_uri"), + }) +} + +func (r DatadogMonitorResource) Exists(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + id, err := parse.DatadogMonitorID(state.ID) + if err != nil { + return nil, err + } + resp, err := client.Datadog.MonitorsClient.Get(ctx, id.ResourceGroup, id.MonitorName) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return utils.Bool(false), nil + } + return nil, fmt.Errorf("retrieving Datadog Monitor %q (Resource Group %q): %+v", id.MonitorName, id.ResourceGroup, err) + } + return utils.Bool(true), nil +} + +func (r DatadogMonitorResource) template(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} +resource "azurerm_resource_group" "test" { + name = "acctest-datadog-%d" + location = "%s" +} +`, data.RandomInteger, data.Locations.Primary) +} + +func (r DatadogMonitorResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` + %s + +resource "azurerm_datadog_monitor" "test" { + name = "acctest-datadog-%d" + resource_group_name = azurerm_resource_group.test.name + location = "WEST US 2" + datadog_organization { + api_key = %q + application_key = %q + } + user { + name = "Test Datadog" + email = "abc@xyz.com" + } + sku_name = "Linked" + identity { + type = "SystemAssigned" + } +} +`, r.template(data), data.RandomInteger%100, os.Getenv("ARM_TEST_DATADOG_API_KEY"), os.Getenv("ARM_TEST_DATADOG_APPLICATION_KEY")) +} + +func (r DatadogMonitorResource) update(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctest-datadog-%d" + location = "%s" +} +resource "azurerm_datadog_monitor" "test" { + name = "acctest-datadog-%d" + resource_group_name = azurerm_resource_group.test.name + location = "WEST US 2" + datadog_organization { + api_key = %q + application_key = %q + } + user { + name = "Test Datadog" + email = "abc@xyz.com" + } + sku_name = "Linked" + identity { + type = "SystemAssigned" + } + monitoring_enabled = false + tags = { + ENV = "Test" + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger%100, os.Getenv("ARM_TEST_DATADOG_API_KEY"), os.Getenv("ARM_TEST_DATADOG_APPLICATION_KEY")) +} + +func (r DatadogMonitorResource) requiresImport(data acceptance.TestData) string { + return fmt.Sprintf(` + %s +resource "azurerm_datadog_monitor" "import" { + name = azurerm_datadog_monitor.test.name + resource_group_name = azurerm_resource_group.test.name + location = azurerm_datadog_monitor.test.location + datadog_organization { + api_key = %q + application_key = %q + } + user { + name = "Test Datadog" + email = "abc@xyz.com" + } + sku_name = "Linked" + identity { + type = "SystemAssigned" + } +} +`, r.basic(data), os.Getenv("ARM_TEST_DATADOG_API_KEY"), os.Getenv("ARM_TEST_DATADOG_APPLICATION_KEY")) +} + +func (r DatadogMonitorResource) complete(data acceptance.TestData) string { + return fmt.Sprintf(` + %s +resource "azurerm_datadog_monitor" "test" { + name = "acctest-datadog-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + datadog_organization { + api_key = %q + application_key = %q + enterprise_app_id = "" + linking_auth_code = "" + linking_client_id = "" + redirect_uri = "" + } + identity { + type = "SystemAssigned" + } + sku_name = "Linked" + user { + name = "Test Datadog" + email = "abc@xyz.com" + phone_number = "" + } + monitoring_enabled = true + tags = { + ENV = "Test" + } +} +`, r.template(data), data.RandomInteger%100, os.Getenv("ARM_TEST_DATADOG_API_KEY"), os.Getenv("ARM_TEST_DATADOG_APPLICATION_KEY")) +} diff --git a/internal/services/datadog/parse/datadog_monitor.go b/internal/services/datadog/parse/datadog_monitor.go new file mode 100644 index 000000000000..9f0a8418058e --- /dev/null +++ b/internal/services/datadog/parse/datadog_monitor.go @@ -0,0 +1,69 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + "strings" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +type DatadogMonitorId struct { + SubscriptionId string + ResourceGroup string + MonitorName string +} + +func NewDatadogMonitorID(subscriptionId, resourceGroup, monitorName string) DatadogMonitorId { + return DatadogMonitorId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + MonitorName: monitorName, + } +} + +func (id DatadogMonitorId) String() string { + segments := []string{ + fmt.Sprintf("Monitor Name %q", id.MonitorName), + fmt.Sprintf("Resource Group %q", id.ResourceGroup), + } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "Datadog Monitor", segmentsStr) +} + +func (id DatadogMonitorId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Datadog/monitors/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.MonitorName) +} + +// DatadogMonitorID parses a DatadogMonitor ID into an DatadogMonitorId struct +func DatadogMonitorID(input string) (*DatadogMonitorId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := DatadogMonitorId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + if resourceId.MonitorName, err = id.PopSegment("monitors"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} diff --git a/internal/services/datadog/parse/datadog_monitor_test.go b/internal/services/datadog/parse/datadog_monitor_test.go new file mode 100644 index 000000000000..8371889301a1 --- /dev/null +++ b/internal/services/datadog/parse/datadog_monitor_test.go @@ -0,0 +1,112 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "testing" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +var _ resourceids.Id = DatadogMonitorId{} + +func TestDatadogMonitorIDFormatter(t *testing.T) { + actual := NewDatadogMonitorID("12345678-1234-9876-4563-123456789012", "resourceGroup1", "monitor1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Datadog/monitors/monitor1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestDatadogMonitorID(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *DatadogMonitorId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing MonitorName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Datadog/", + Error: true, + }, + + { + // missing value for MonitorName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Datadog/monitors/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Datadog/monitors/monitor1", + Expected: &DatadogMonitorId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resourceGroup1", + MonitorName: "monitor1", + }, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESOURCEGROUP1/PROVIDERS/MICROSOFT.DATADOG/MONITORS/MONITOR1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := DatadogMonitorID(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.MonitorName != v.Expected.MonitorName { + t.Fatalf("Expected %q but got %q for MonitorName", v.Expected.MonitorName, actual.MonitorName) + } + } +} diff --git a/internal/services/datadog/registration.go b/internal/services/datadog/registration.go new file mode 100644 index 000000000000..d583e5fcc608 --- /dev/null +++ b/internal/services/datadog/registration.go @@ -0,0 +1,29 @@ +package datadog + +import "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + +type Registration struct{} + +// Name is the name of this Service +func (r Registration) Name() string { + return "Datadog" +} + +// WebsiteCategories returns a list of categories which can be used for the sidebar +func (r Registration) WebsiteCategories() []string { + return []string{ + "Datadog", + } +} + +// SupportedDataSources returns the supported Data Sources supported by this Service +func (r Registration) SupportedDataSources() map[string]*pluginsdk.Resource { + return map[string]*pluginsdk.Resource{} +} + +// SupportedResources returns the supported Resources supported by this Service +func (r Registration) SupportedResources() map[string]*pluginsdk.Resource { + return map[string]*pluginsdk.Resource{ + "azurerm_datadog_monitor": resourceDatadogMonitor(), + } +} diff --git a/internal/services/datadog/resourceids.go b/internal/services/datadog/resourceids.go new file mode 100644 index 000000000000..cfc4642478c5 --- /dev/null +++ b/internal/services/datadog/resourceids.go @@ -0,0 +1,3 @@ +package datadog + +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=DatadogMonitor -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Datadog/monitors/monitor1 diff --git a/internal/services/datadog/validate/datadog_email_address.go b/internal/services/datadog/validate/datadog_email_address.go new file mode 100644 index 000000000000..acbe29fea3c1 --- /dev/null +++ b/internal/services/datadog/validate/datadog_email_address.go @@ -0,0 +1,19 @@ +package validate + +import ( + "fmt" + "regexp" +) + +func DatadogMonitorsEmailAddress(i interface{}, k string) (warnings []string, errors []error) { + v, ok := i.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected type of %s to be string", k)) + return + } + if !regexp.MustCompile(`^[A-Za-z0-9._%+-]+@(?:[A-Za-z0-9-]+\.)+[A-Za-z]{2,}$`).MatchString(v) { + errors = append(errors, fmt.Errorf("expected value of %s not match regular expression, got %v", k, v)) + return + } + return +} diff --git a/internal/services/datadog/validate/datadog_email_address_test.go b/internal/services/datadog/validate/datadog_email_address_test.go new file mode 100644 index 000000000000..c84f3bb07d97 --- /dev/null +++ b/internal/services/datadog/validate/datadog_email_address_test.go @@ -0,0 +1,38 @@ +package validate + +import "testing" + +func TestDatadogMonitorsEmailAddress(t *testing.T) { + testCases := []struct { + Input string + Expected bool + }{ + { + Input: "abc@xyz.com", + Expected: true, + }, + { + Input: "abc@dyg@jad.com", + Expected: false, + }, + { + Input: "abc@", + Expected: false, + }, + { + Input: "abc@xyz", + Expected: false, + }, + { + Input: "abcdyg@jad.com.cdhc", + Expected: true, + }, + } + for _, v := range testCases { + _, errors := DatadogMonitorsEmailAddress(v.Input, "email_address") + result := len(errors) == 0 + if result != v.Expected { + t.Fatalf("Expected the result to be %t but got %t (and %d errors)", v.Expected, result, len(errors)) + } + } +} diff --git a/internal/services/datadog/validate/datadog_monitor_id.go b/internal/services/datadog/validate/datadog_monitor_id.go new file mode 100644 index 000000000000..7626bf021d70 --- /dev/null +++ b/internal/services/datadog/validate/datadog_monitor_id.go @@ -0,0 +1,23 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + + "github.com/hashicorp/terraform-provider-azurerm/internal/services/datadog/parse" +) + +func DatadogMonitorID(input interface{}, key string) (warnings []string, errors []error) { + v, ok := input.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected %q to be a string", key)) + return + } + + if _, err := parse.DatadogMonitorID(v); err != nil { + errors = append(errors, err) + } + + return +} diff --git a/internal/services/datadog/validate/datadog_monitor_id_test.go b/internal/services/datadog/validate/datadog_monitor_id_test.go new file mode 100644 index 000000000000..c4c4b0415347 --- /dev/null +++ b/internal/services/datadog/validate/datadog_monitor_id_test.go @@ -0,0 +1,76 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import "testing" + +func TestDatadogMonitorID(t *testing.T) { + cases := []struct { + Input string + Valid bool + }{ + + { + // empty + Input: "", + Valid: false, + }, + + { + // missing SubscriptionId + Input: "/", + Valid: false, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Valid: false, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Valid: false, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Valid: false, + }, + + { + // missing MonitorName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Datadog/", + Valid: false, + }, + + { + // missing value for MonitorName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Datadog/monitors/", + Valid: false, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Datadog/monitors/monitor1", + Valid: true, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESOURCEGROUP1/PROVIDERS/MICROSOFT.DATADOG/MONITORS/MONITOR1", + Valid: false, + }, + } + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.Input) + _, errors := DatadogMonitorID(tc.Input, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} diff --git a/internal/services/datadog/validate/datadog_monitor_name.go b/internal/services/datadog/validate/datadog_monitor_name.go new file mode 100644 index 000000000000..593d2ee6f7c0 --- /dev/null +++ b/internal/services/datadog/validate/datadog_monitor_name.go @@ -0,0 +1,20 @@ +package validate + +import ( + "fmt" + "regexp" +) + +func DatadogMonitorsName(i interface{}, k string) (warnings []string, errors []error) { + v, ok := i.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected type of %s to be string", k)) + return + } + + if !regexp.MustCompile(`^[a-zA-Z0-9_-]{2,32}$`).MatchString(v) { + errors = append(errors, fmt.Errorf("%q must be between 2 and 32 characters in length, can only contain alphanumeric characters, underscore and hyphen symbols", k)) + } + + return +} diff --git a/internal/services/datadog/validate/datadog_monitor_name_test.go b/internal/services/datadog/validate/datadog_monitor_name_test.go new file mode 100644 index 000000000000..9d109bf03795 --- /dev/null +++ b/internal/services/datadog/validate/datadog_monitor_name_test.go @@ -0,0 +1,61 @@ +package validate + +import "testing" + +func TestDatadogMonitorsName(t *testing.T) { + testData := []struct { + input string + expected bool + }{ + { + // empty + input: "", + expected: false, + }, + { + // proper string + input: "hello", + expected: true, + }, + { + // end with exclamation + input: "hello!", + expected: false, + }, + { + // with hypen + input: "malcolm-in-the-middle", + expected: true, + }, + { + // end with fullstop + input: "hello.", + expected: false, + }, + { + // less than 32 + input: "qwertyuioplkjhgfdsazxcv", + expected: true, + }, + { + // with underscore + input: "qwertyuiop_jhgfdsazxcva", + expected: true, + }, + { + // more than 32 + input: "qwertyuioplkjhgfdsazxcvggeitofkjhkt", + expected: false, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q..", v.input) + + _, errors := DatadogMonitorsName(v.input, "name") + actual := len(errors) == 0 + if v.expected != actual { + t.Fatalf("Expected %t but got %t", v.expected, actual) + } + } +} diff --git a/internal/services/datadog/validate/datadog_phone_number.go b/internal/services/datadog/validate/datadog_phone_number.go new file mode 100644 index 000000000000..6f178ada2dec --- /dev/null +++ b/internal/services/datadog/validate/datadog_phone_number.go @@ -0,0 +1,18 @@ +package validate + +import ( + "fmt" +) + +func DatadogMonitorsPhoneNumber(i interface{}, k string) (warnings []string, errors []error) { + v, ok := i.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected type of %s to be string", k)) + return + } + if len(v) > 40 { + errors = append(errors, fmt.Errorf("length should be less than %d", 40)) + return + } + return +} diff --git a/internal/services/datadog/validate/datadog_phone_number_test.go b/internal/services/datadog/validate/datadog_phone_number_test.go new file mode 100644 index 000000000000..a88bbace5a6f --- /dev/null +++ b/internal/services/datadog/validate/datadog_phone_number_test.go @@ -0,0 +1,31 @@ +package validate + +import "testing" + +func TestDatadogMonitorsPhoneNumber(t *testing.T) { + testCases := []struct { + Input string + Expected bool + }{ + { + Input: "", + Expected: true, + }, + { + Input: "1234567890", + Expected: true, + }, + { + Input: "12345678901234567890123456789012345678901234567890", + Expected: false, + }, + } + + for _, v := range testCases { + _, errors := DatadogMonitorsPhoneNumber(v.Input, "phone_number") + result := len(errors) == 0 + if result != v.Expected { + t.Fatalf("Expected the result to be %t but got %t (and %d errors)", v.Expected, result, len(errors)) + } + } +} diff --git a/internal/services/datadog/validate/datadog_users_name.go b/internal/services/datadog/validate/datadog_users_name.go new file mode 100644 index 000000000000..0359ed04094c --- /dev/null +++ b/internal/services/datadog/validate/datadog_users_name.go @@ -0,0 +1,22 @@ +package validate + +import ( + "fmt" +) + +func DatadogUsersName(i interface{}, k string) (warnings []string, errors []error) { + v, ok := i.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected type of %s to be string", k)) + return + } + if len(v) == 0 { + errors = append(errors, fmt.Errorf("length cannot be %d", 0)) + return + } + if len(v) > 50 { + errors = append(errors, fmt.Errorf("length should be less than %d", 40)) + return + } + return +} diff --git a/internal/services/datadog/validate/datadog_users_name_test.go b/internal/services/datadog/validate/datadog_users_name_test.go new file mode 100644 index 000000000000..f73b8db8b39b --- /dev/null +++ b/internal/services/datadog/validate/datadog_users_name_test.go @@ -0,0 +1,31 @@ +package validate + +import "testing" + +func TestDatadogUsersName(t *testing.T) { + testCases := []struct { + Input string + Expected bool + }{ + { + Input: "", + Expected: false, + }, + { + Input: "Test", + Expected: true, + }, + { + Input: "qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm", + Expected: false, + }, + } + + for _, v := range testCases { + _, errors := DatadogUsersName(v.Input, "user_name") + result := len(errors) == 0 + if result != v.Expected { + t.Fatalf("Expected the result to be %t but got %t (and %d errors)", v.Expected, result, len(errors)) + } + } +} diff --git a/internal/services/datafactory/data_factory_data_flow.go b/internal/services/datafactory/data_factory_data_flow.go index 322036a4598e..38a35d2f48f9 100644 --- a/internal/services/datafactory/data_factory_data_flow.go +++ b/internal/services/datafactory/data_factory_data_flow.go @@ -48,6 +48,35 @@ func SchemaForDataFlowSourceAndSink() *pluginsdk.Schema { }, }, + "flowlet": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "parameters": { + Type: pluginsdk.TypeMap, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + }, + }, + + "dataset_parameters": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, + }, + }, + "linked_service": { Type: pluginsdk.TypeList, Optional: true, @@ -139,6 +168,35 @@ func SchemaForDataFlowSourceTransformation() *pluginsdk.Schema { }, }, + "flowlet": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "parameters": { + Type: pluginsdk.TypeMap, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + }, + }, + + "dataset_parameters": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, + }, + }, + "linked_service": { Type: pluginsdk.TypeList, Optional: true, @@ -180,6 +238,7 @@ func expandDataFactoryDataFlowSource(input []interface{}) *[]datafactory.DataFlo Dataset: expandDataFactoryDatasetReference(raw["dataset"].([]interface{})), LinkedService: expandDataFactoryLinkedServiceReference(raw["linked_service"].([]interface{})), SchemaLinkedService: expandDataFactoryLinkedServiceReference(raw["schema_linked_service"].([]interface{})), + Flowlet: expandDataFactoryDataFlowReference(raw["flowlet"].([]interface{})), }) } return &result @@ -199,6 +258,7 @@ func expandDataFactoryDataFlowSink(input []interface{}) *[]datafactory.DataFlowS Dataset: expandDataFactoryDatasetReference(raw["dataset"].([]interface{})), LinkedService: expandDataFactoryLinkedServiceReference(raw["linked_service"].([]interface{})), SchemaLinkedService: expandDataFactoryLinkedServiceReference(raw["schema_linked_service"].([]interface{})), + Flowlet: expandDataFactoryDataFlowReference(raw["flowlet"].([]interface{})), }) } return &result @@ -217,6 +277,7 @@ func expandDataFactoryDataFlowTransformation(input []interface{}) *[]datafactory Name: utils.String(raw["name"].(string)), Dataset: expandDataFactoryDatasetReference(raw["dataset"].([]interface{})), LinkedService: expandDataFactoryLinkedServiceReference(raw["linked_service"].([]interface{})), + Flowlet: expandDataFactoryDataFlowReference(raw["flowlet"].([]interface{})), }) } return &result @@ -248,6 +309,20 @@ func expandDataFactoryLinkedServiceReference(input []interface{}) *datafactory.L } } +func expandDataFactoryDataFlowReference(input []interface{}) *datafactory.DataFlowReference { + if len(input) == 0 || input[0] == nil { + return nil + } + + raw := input[0].(map[string]interface{}) + return &datafactory.DataFlowReference{ + Type: utils.String("DataFlowReference"), + ReferenceName: utils.String(raw["name"].(string)), + Parameters: raw["parameters"].(map[string]interface{}), + DatasetParameters: utils.String(raw["dataset_parameters"].(string)), + } +} + func flattenDataFactoryDataFlowSource(input *[]datafactory.DataFlowSource) []interface{} { if input == nil { return []interface{}{} @@ -269,6 +344,7 @@ func flattenDataFactoryDataFlowSource(input *[]datafactory.DataFlowSource) []int "dataset": flattenDataFactoryDatasetReference(v.Dataset), "linked_service": flattenDataFactoryLinkedServiceReference(v.LinkedService), "schema_linked_service": flattenDataFactoryLinkedServiceReference(v.SchemaLinkedService), + "flowlet": flattenDataFactoryDataFlowReference(v.Flowlet), }) } return result @@ -295,6 +371,7 @@ func flattenDataFactoryDataFlowSink(input *[]datafactory.DataFlowSink) []interfa "dataset": flattenDataFactoryDatasetReference(v.Dataset), "linked_service": flattenDataFactoryLinkedServiceReference(v.LinkedService), "schema_linked_service": flattenDataFactoryLinkedServiceReference(v.SchemaLinkedService), + "flowlet": flattenDataFactoryDataFlowReference(v.Flowlet), }) } return result @@ -320,6 +397,7 @@ func flattenDataFactoryDataFlowTransformation(input *[]datafactory.Transformatio "description": description, "dataset": flattenDataFactoryDatasetReference(v.Dataset), "linked_service": flattenDataFactoryLinkedServiceReference(v.LinkedService), + "flowlet": flattenDataFactoryDataFlowReference(v.Flowlet), }) } return result @@ -360,3 +438,22 @@ func flattenDataFactoryLinkedServiceReference(input *datafactory.LinkedServiceRe }, } } + +func flattenDataFactoryDataFlowReference(input *datafactory.DataFlowReference) []interface{} { + if input == nil { + return []interface{}{} + } + + name := "" + if input.ReferenceName != nil { + name = *input.ReferenceName + } + + return []interface{}{ + map[string]interface{}{ + "name": name, + "parameters": input.Parameters, + "dataset_parameters": input.DatasetParameters, + }, + } +} diff --git a/internal/services/datafactory/data_factory_data_flow_resource_test.go b/internal/services/datafactory/data_factory_data_flow_resource_test.go index 90134778f698..3795cd384961 100644 --- a/internal/services/datafactory/data_factory_data_flow_resource_test.go +++ b/internal/services/datafactory/data_factory_data_flow_resource_test.go @@ -174,7 +174,7 @@ func (r DataFlowResource) complete(data acceptance.TestData) string { %s resource "azurerm_data_factory_data_flow" "test" { - name = "acctestdf%d" + name = "acctestdf3%[2]d" data_factory_id = azurerm_data_factory.test.id description = "description for data flow" annotations = ["anno1", "anno2"] @@ -184,6 +184,13 @@ resource "azurerm_data_factory_data_flow" "test" { name = "source1" description = "description for source1" + flowlet { + name = azurerm_data_factory_flowlet_data_flow.test1.name + parameters = { + "Key1" = "value1" + } + } + linked_service { name = azurerm_data_factory_linked_custom_service.test.name parameters = { @@ -203,6 +210,13 @@ resource "azurerm_data_factory_data_flow" "test" { name = "sink1" description = "description for sink1" + flowlet { + name = azurerm_data_factory_flowlet_data_flow.test2.name + parameters = { + "Key1" = "value1" + } + } + linked_service { name = azurerm_data_factory_linked_custom_service.test.name parameters = { @@ -303,6 +317,60 @@ Filter1 sink(allowSchemaDrift: true, partitionBy('roundRobin', 3)) ~> sink1 EOT } + +resource "azurerm_data_factory_flowlet_data_flow" "test1" { + name = "acctest1fdf%[2]d" + data_factory_id = azurerm_data_factory.test.id + + source { + name = "source1" + } + + sink { + name = "sink1" + } + + script = < source1 +source1 sink( + allowSchemaDrift: true, + validateSchema: false, + skipDuplicateMapInputs: true, + skipDuplicateMapOutputs: true) ~> sink1 +EOT +} + +resource "azurerm_data_factory_flowlet_data_flow" "test2" { + name = "acctest2fdf%[2]d" + data_factory_id = azurerm_data_factory.test.id + + source { + name = "source1" + } + + sink { + name = "sink1" + } + + script = < source1 +source1 sink( + allowSchemaDrift: true, + validateSchema: false, + skipDuplicateMapInputs: true, + skipDuplicateMapOutputs: true) ~> sink1 +EOT +} `, r.template(data), data.RandomInteger) } @@ -313,12 +381,12 @@ provider "azurerm" { } resource "azurerm_resource_group" "test" { - name = "acctestRG-df-%d" - location = "%s" + name = "acctestRG-df-%[1]d" + location = "%[2]s" } resource "azurerm_storage_account" "test" { - name = "acctestsa%s" + name = "acctestsa%[3]s" location = azurerm_resource_group.test.location resource_group_name = azurerm_resource_group.test.name account_tier = "Standard" @@ -326,13 +394,13 @@ resource "azurerm_storage_account" "test" { } resource "azurerm_data_factory" "test" { - name = "acctestdf%d" + name = "acctestdf%[1]d" location = azurerm_resource_group.test.location resource_group_name = azurerm_resource_group.test.name } resource "azurerm_data_factory_linked_custom_service" "test" { - name = "acctestls%d" + name = "acctestls%[1]d" data_factory_id = azurerm_data_factory.test.id type = "AzureBlobStorage" type_properties_json = < source1 +source1 sink( + allowSchemaDrift: true, + validateSchema: false, + skipDuplicateMapInputs: true, + skipDuplicateMapOutputs: true) ~> sink1 +EOT +} +`, r.template(data), data.RandomInteger) +} + +func (r FlowletDataFlowResource) requiresImport(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_data_factory_flowlet_data_flow" "import" { + name = azurerm_data_factory_flowlet_data_flow.test.name + data_factory_id = azurerm_data_factory_flowlet_data_flow.test.data_factory_id + script = azurerm_data_factory_flowlet_data_flow.test.script + source { + name = azurerm_data_factory_flowlet_data_flow.test.source.0.name + linked_service { + name = azurerm_data_factory_flowlet_data_flow.test.source.0.linked_service.0.name + } + } + + sink { + name = azurerm_data_factory_flowlet_data_flow.test.sink.0.name + linked_service { + name = azurerm_data_factory_flowlet_data_flow.test.sink.0.linked_service.0.name + } + } +} +`, r.basic(data)) +} + +func (r FlowletDataFlowResource) complete(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_data_factory_flowlet_data_flow" "test" { + name = "acctestfdf%[2]d" + data_factory_id = azurerm_data_factory.test.id + description = "description for data flow" + annotations = ["anno1", "anno2"] + folder = "folder1" + + source { + name = "source1" + description = "description for source1" + + flowlet { + name = azurerm_data_factory_flowlet_data_flow.test1.name + parameters = { + "Key1" = "value1" + } + } + + linked_service { + name = azurerm_data_factory_linked_custom_service.test.name + parameters = { + "Key1" = "value1" + } + } + + schema_linked_service { + name = azurerm_data_factory_linked_custom_service.test.name + parameters = { + "Key1" = "value1" + } + } + } + + sink { + name = "sink1" + description = "description for sink1" + + flowlet { + name = azurerm_data_factory_flowlet_data_flow.test2.name + parameters = { + "Key1" = "value1" + } + } + + linked_service { + name = azurerm_data_factory_linked_custom_service.test.name + parameters = { + "Key1" = "value1" + } + } + + schema_linked_service { + name = azurerm_data_factory_linked_custom_service.test.name + parameters = { + "Key1" = "value1" + } + } + } + + transformation { + name = "filter1" + description = "description for filter1" + + dataset { + name = azurerm_data_factory_dataset_json.test1.name + parameters = { + "Key1" = "value1" + } + } + + linked_service { + name = azurerm_data_factory_linked_custom_service.test.name + parameters = { + "Key1" = "value1" + } + } + } + + script_lines = [< source1 +source1 filter(toInteger(year) >= 1910 && toInteger(year) <= 2000) ~> Filter1 +Filter1 sink(allowSchemaDrift: true, + validateSchema: false, + skipDuplicateMapInputs: true, + skipDuplicateMapOutputs: true, + saveOrder: 0, + partitionBy('roundRobin', 3)) ~> sink1 +EOT, +< source1 +source1 filter(toInteger(year) >= 1910 && toInteger(year) <= 2000) ~> Filter1 +Filter1 sink(allowSchemaDrift: true, + validateSchema: false, + skipDuplicateMapInputs: true, + skipDuplicateMapOutputs: true, + saveOrder: 0, + partitionBy('roundRobin', 3)) ~> sink1 +EOT + ] + + script = < source1 +source1 filter(toInteger(year) >= 1910 && toInteger(year) <= 2000) ~> Filter1 +Filter1 sink(allowSchemaDrift: true, + validateSchema: false, + skipDuplicateMapInputs: true, + skipDuplicateMapOutputs: true, + saveOrder: 0, + partitionBy('roundRobin', 3)) ~> sink1 +EOT +} + +resource "azurerm_data_factory_flowlet_data_flow" "test1" { + name = "acctest1fdf%[2]d" + data_factory_id = azurerm_data_factory.test.id + + source { + name = "source1" + } + + sink { + name = "sink1" + } + + script = < source1 +source1 sink( + allowSchemaDrift: true, + validateSchema: false, + skipDuplicateMapInputs: true, + skipDuplicateMapOutputs: true) ~> sink1 +EOT +} + +resource "azurerm_data_factory_flowlet_data_flow" "test2" { + name = "acctest2fdf%[2]d" + data_factory_id = azurerm_data_factory.test.id + + source { + name = "source1" + } + + sink { + name = "sink1" + } + + script = < source1 +source1 sink( + allowSchemaDrift: true, + validateSchema: false, + skipDuplicateMapInputs: true, + skipDuplicateMapOutputs: true) ~> sink1 +EOT +} +`, r.template(data), data.RandomInteger) +} + +func (FlowletDataFlowResource) template(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-df-%[1]d" + location = "%[2]s" +} + +resource "azurerm_storage_account" "test" { + name = "acctestsa%[3]s" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + account_tier = "Standard" + account_replication_type = "LRS" +} + +resource "azurerm_data_factory" "test" { + name = "acctestdf%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_data_factory_linked_custom_service" "test" { + name = "acctestls%[1]d" + data_factory_id = azurerm_data_factory.test.id + type = "AzureBlobStorage" + type_properties_json = < 0 { - if parameter, ok := (*props.PolicyInfo.PolicyParameters.DataStoreParametersList)[0].AsAzureOperationalStoreParameters(); ok { - if parameter.ResourceGroupID != nil { - resourceGroupId, err := resourceParse.ResourceGroupID(*parameter.ResourceGroupID) - if err != nil { - return err - } - d.Set("snapshot_resource_group_name", resourceGroupId.ResourceGroup) + parameter := (*props.PolicyInfo.PolicyParameters.DataStoreParametersList)[0].(backupinstances.AzureOperationalStoreParameters) + + if parameter.ResourceGroupId != nil { + resourceGroupId, err := resourceParse.ResourceGroupID(*parameter.ResourceGroupId) + if err != nil { + return err } + d.Set("snapshot_resource_group_name", resourceGroupId.ResourceGroup) } } } @@ -209,18 +204,15 @@ func resourceDataProtectionBackupInstanceDiskDelete(d *schema.ResourceData, meta ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.BackupInstanceID(d.Id()) + id, err := backupinstances.ParseBackupInstanceID(d.Id()) if err != nil { return err } - future, err := client.Delete(ctx, id.BackupVaultName, id.ResourceGroup, id.Name) + err = client.DeleteThenPoll(ctx, *id) if err != nil { return fmt.Errorf("deleting DataProtection BackupInstance (%q): %+v", id, err) } - if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for deletion of the DataProtection BackupInstance (%q): %+v", id.Name, err) - } return nil } diff --git a/internal/services/dataprotection/data_protection_backup_instance_disk_resource_test.go b/internal/services/dataprotection/data_protection_backup_instance_disk_resource_test.go index 57baadd82fc6..9038dfbf6a65 100644 --- a/internal/services/dataprotection/data_protection_backup_instance_disk_resource_test.go +++ b/internal/services/dataprotection/data_protection_backup_instance_disk_resource_test.go @@ -5,12 +5,13 @@ import ( "fmt" "testing" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dataprotection/parse" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -87,13 +88,13 @@ func TestAccDataProtectionBackupInstanceDisk_update(t *testing.T) { } func (r DataProtectionBackupInstanceDiskResource) Exists(ctx context.Context, client *clients.Client, state *terraform.InstanceState) (*bool, error) { - id, err := parse.BackupInstanceID(state.ID) + id, err := backupinstances.ParseBackupInstanceID(state.ID) if err != nil { return nil, err } - resp, err := client.DataProtection.BackupInstanceClient.Get(ctx, id.BackupVaultName, id.ResourceGroup, id.Name) + resp, err := client.DataProtection.BackupInstanceClient.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { return utils.Bool(false), nil } return nil, fmt.Errorf("retrieving DataProtection BackupInstance (%q): %+v", id, err) diff --git a/internal/services/dataprotection/data_protection_backup_instance_postgresql_resource.go b/internal/services/dataprotection/data_protection_backup_instance_postgresql_resource.go index 4a514e2f396f..f61bc4f73b00 100644 --- a/internal/services/dataprotection/data_protection_backup_instance_postgresql_resource.go +++ b/internal/services/dataprotection/data_protection_backup_instance_postgresql_resource.go @@ -6,17 +6,17 @@ import ( "log" "time" + "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances" + "github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/databases" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dataprotection/legacysdk/dataprotection" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dataprotection/parse" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dataprotection/validate" keyVaultValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/keyvault/validate" - postgresParse "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" - postgresValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" azSchema "github.com/hashicorp/terraform-provider-azurerm/internal/tf/schema" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" @@ -38,7 +38,7 @@ func resourceDataProtectionBackupInstancePostgreSQL() *pluginsdk.Resource { }, Importer: azSchema.ValidateResourceIDPriorToImport(func(id string) error { - _, err := parse.BackupInstanceID(id) + _, err := backupinstances.ParseBackupInstanceID(id) return err }), @@ -55,20 +55,20 @@ func resourceDataProtectionBackupInstancePostgreSQL() *pluginsdk.Resource { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: validate.BackupVaultID, + ValidateFunc: backupinstances.ValidateBackupVaultID, }, "database_id": { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: postgresValidate.DatabaseID, + ValidateFunc: databases.ValidateDatabaseID, }, "backup_policy_id": { Type: schema.TypeString, Required: true, - ValidateFunc: validate.BackupPolicyID, + ValidateFunc: backuppolicies.ValidateBackupPoliciesID, }, "database_credential_key_vault_secret_id": { @@ -87,71 +87,66 @@ func resourceDataProtectionBackupInstancePostgreSQLCreateUpdate(d *schema.Resour defer cancel() name := d.Get("name").(string) - vaultId, _ := parse.BackupVaultID(d.Get("vault_id").(string)) + vaultId, _ := backupinstances.ParseBackupVaultID(d.Get("vault_id").(string)) - id := parse.NewBackupInstanceID(subscriptionId, vaultId.ResourceGroup, vaultId.Name, name) + id := backupinstances.NewBackupInstanceID(subscriptionId, vaultId.ResourceGroupName, vaultId.VaultName, name) if d.IsNewResource() { - existing, err := client.Get(ctx, id.BackupVaultName, id.ResourceGroup, id.Name) + existing, err := client.Get(ctx, id) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return fmt.Errorf("checking for existing DataProtection BackupInstance (%q): %+v", id, err) } } - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return tf.ImportAsExistsError("azurerm_data_protection_backup_instance_postgresql", id.ID()) } } - databaseId, _ := postgresParse.DatabaseID(d.Get("database_id").(string)) + databaseId, _ := databases.ParseDatabaseID(d.Get("database_id").(string)) location := location.Normalize(d.Get("location").(string)) - serverId := postgresParse.NewServerID(databaseId.SubscriptionId, databaseId.ResourceGroup, databaseId.ServerName) - policyId, _ := parse.BackupPolicyID(d.Get("backup_policy_id").(string)) + serverId := servers.NewServerID(databaseId.SubscriptionId, databaseId.ResourceGroupName, databaseId.ServerName) + policyId, _ := backuppolicies.ParseBackupPoliciesID(d.Get("backup_policy_id").(string)) - parameters := dataprotection.BackupInstanceResource{ - Properties: &dataprotection.BackupInstance{ - DataSourceInfo: &dataprotection.Datasource{ + parameters := backupinstances.BackupInstanceResource{ + Properties: &backupinstances.BackupInstance{ + DataSourceInfo: backupinstances.Datasource{ DatasourceType: utils.String("Microsoft.DBforPostgreSQL/servers/databases"), ObjectType: utils.String("Datasource"), - ResourceID: utils.String(databaseId.ID()), + ResourceID: databaseId.ID(), ResourceLocation: utils.String(location), - ResourceName: utils.String(databaseId.Name), + ResourceName: utils.String(databaseId.DatabaseName), ResourceType: utils.String("Microsoft.DBforPostgreSQL/servers/databases"), - ResourceURI: utils.String(""), + ResourceUri: utils.String(""), }, - DataSourceSetInfo: &dataprotection.DatasourceSet{ + DataSourceSetInfo: &backupinstances.DatasourceSet{ DatasourceType: utils.String("Microsoft.DBForPostgreSQL/servers"), ObjectType: utils.String("DatasourceSet"), - ResourceID: utils.String(serverId.ID()), + ResourceID: serverId.ID(), ResourceLocation: utils.String(location), - ResourceName: utils.String(serverId.Name), + ResourceName: utils.String(serverId.ServerName), ResourceType: utils.String("Microsoft.DBForPostgreSQL/servers"), - ResourceURI: utils.String(""), + ResourceUri: utils.String(""), }, - FriendlyName: utils.String(id.Name), - PolicyInfo: &dataprotection.PolicyInfo{ - PolicyID: utils.String(policyId.ID()), + FriendlyName: utils.String(id.BackupInstanceName), + PolicyInfo: backupinstances.PolicyInfo{ + PolicyId: policyId.ID(), }, }, } if v, ok := d.GetOk("database_credential_key_vault_secret_id"); ok { - parameters.Properties.DatasourceAuthCredentials = &dataprotection.SecretStoreBasedAuthCredentials{ - SecretStoreResource: &dataprotection.SecretStoreResource{ - URI: utils.String(v.(string)), - SecretStoreType: dataprotection.SecretStoreTypeAzureKeyVault, + parameters.Properties.DatasourceAuthCredentials = backupinstances.SecretStoreBasedAuthCredentials{ + SecretStoreResource: &backupinstances.SecretStoreResource{ + Uri: utils.String(v.(string)), + SecretStoreType: backupinstances.SecretStoreTypeAzureKeyVault, }, - ObjectType: dataprotection.ObjectTypeSecretStoreBasedAuthCredentials, } } - future, err := client.CreateOrUpdate(ctx, id.BackupVaultName, id.ResourceGroup, id.Name, parameters) + err := client.CreateOrUpdateThenPoll(ctx, id, parameters) if err != nil { - return fmt.Errorf("creating/updating DataProtection BackupInstance (%q): %+v", id, err) - } - - if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for creation/update of the DataProtection BackupInstance (%q): %+v", id, err) + return fmt.Errorf("creating/updating %s: %+v", id, err) } deadline, ok := ctx.Deadline() @@ -159,8 +154,8 @@ func resourceDataProtectionBackupInstancePostgreSQLCreateUpdate(d *schema.Resour return fmt.Errorf("context had no deadline") } stateConf := &pluginsdk.StateChangeConf{ - Pending: []string{string(dataprotection.StatusConfiguringProtection), "UpdatingProtection"}, - Target: []string{string(dataprotection.StatusProtectionConfigured)}, + Pending: []string{string(backupinstances.StatusConfiguringProtection), "UpdatingProtection"}, + Target: []string{string(backupinstances.StatusProtectionConfigured)}, Refresh: policyProtectionStateRefreshFunc(ctx, client, id), MinTimeout: 1 * time.Minute, Timeout: time.Until(deadline), @@ -179,35 +174,34 @@ func resourceDataProtectionBackupInstancePostgreSQLRead(d *schema.ResourceData, ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.BackupInstanceID(d.Id()) + id, err := backupinstances.ParseBackupInstanceID(d.Id()) if err != nil { return err } - resp, err := client.Get(ctx, id.BackupVaultName, id.ResourceGroup, id.Name) + resp, err := client.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { log.Printf("[INFO] dataprotection %q does not exist - removing from state", d.Id()) d.SetId("") return nil } return fmt.Errorf("retrieving DataProtection BackupInstance (%q): %+v", id, err) } - vaultId := parse.NewBackupVaultID(id.SubscriptionId, id.ResourceGroup, id.BackupVaultName) - d.Set("name", id.Name) + vaultId := backupinstances.NewBackupVaultID(id.SubscriptionId, id.ResourceGroupName, id.VaultName) + d.Set("name", id.BackupInstanceName) d.Set("vault_id", vaultId.ID()) - if props := resp.Properties; props != nil { - if props.DataSourceInfo != nil { + + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { d.Set("database_id", props.DataSourceInfo.ResourceID) d.Set("location", props.DataSourceInfo.ResourceLocation) - } - if props.PolicyInfo != nil { - d.Set("backup_policy_id", props.PolicyInfo.PolicyID) - } - if props.DatasourceAuthCredentials != nil { - if credential, ok := props.DatasourceAuthCredentials.AsSecretStoreBasedAuthCredentials(); ok { + d.Set("backup_policy_id", props.PolicyInfo.PolicyId) + + if props.DatasourceAuthCredentials != nil { + credential := props.DatasourceAuthCredentials.(backupinstances.SecretStoreBasedAuthCredentials) if credential.SecretStoreResource != nil { - d.Set("database_credential_key_vault_secret_id", credential.SecretStoreResource.URI) + d.Set("database_credential_key_vault_secret_id", credential.SecretStoreResource.Uri) } } else { log.Printf("[DEBUG] Skipping setting database_credential_key_vault_secret_id since this DatasourceAuthCredentials is not supported") @@ -222,32 +216,29 @@ func resourceDataProtectionBackupInstancePostgreSQLDelete(d *schema.ResourceData ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.BackupInstanceID(d.Id()) + id, err := backupinstances.ParseBackupInstanceID(d.Id()) if err != nil { return err } - future, err := client.Delete(ctx, id.BackupVaultName, id.ResourceGroup, id.Name) + err = client.DeleteThenPoll(ctx, *id) if err != nil { return fmt.Errorf("deleting DataProtection BackupInstance (%q): %+v", id, err) } - if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for deletion of the DataProtection BackupInstance (%q): %+v", id.Name, err) - } return nil } -func policyProtectionStateRefreshFunc(ctx context.Context, client *dataprotection.BackupInstancesClient, id parse.BackupInstanceId) pluginsdk.StateRefreshFunc { +func policyProtectionStateRefreshFunc(ctx context.Context, client *backupinstances.BackupInstancesClient, id backupinstances.BackupInstanceId) pluginsdk.StateRefreshFunc { return func() (interface{}, string, error) { - res, err := client.Get(ctx, id.BackupVaultName, id.ResourceGroup, id.Name) + res, err := client.Get(ctx, id) if err != nil { return nil, "", fmt.Errorf("retrieving DataProtection BackupInstance (%q): %+v", id, err) } - if res.Properties == nil || res.Properties.ProtectionStatus == nil { + if res.Model == nil || res.Model.Properties == nil || res.Model.Properties.ProtectionStatus == nil || res.Model.Properties.ProtectionStatus.Status == nil { return nil, "", fmt.Errorf("reading DataProtection BackupInstance (%q) protection status: %+v", id, err) } - return res, string(res.Properties.ProtectionStatus.Status), nil + return res, string(*res.Model.Properties.ProtectionStatus.Status), nil } } diff --git a/internal/services/dataprotection/data_protection_backup_instance_postgresql_resource_test.go b/internal/services/dataprotection/data_protection_backup_instance_postgresql_resource_test.go index cf3fd742d178..0f2f6f689b4d 100644 --- a/internal/services/dataprotection/data_protection_backup_instance_postgresql_resource_test.go +++ b/internal/services/dataprotection/data_protection_backup_instance_postgresql_resource_test.go @@ -5,12 +5,13 @@ import ( "fmt" "testing" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupinstances" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dataprotection/parse" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -101,16 +102,16 @@ func TestAccDataProtectionBackupInstancePostgreSQL_update(t *testing.T) { } func (r DataProtectionBackupInstancePostgreSQLResource) Exists(ctx context.Context, client *clients.Client, state *terraform.InstanceState) (*bool, error) { - id, err := parse.BackupInstanceID(state.ID) + id, err := backupinstances.ParseBackupInstanceID(state.ID) if err != nil { return nil, err } - resp, err := client.DataProtection.BackupInstanceClient.Get(ctx, id.BackupVaultName, id.ResourceGroup, id.Name) + resp, err := client.DataProtection.BackupInstanceClient.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { return utils.Bool(false), nil } - return nil, fmt.Errorf("retrieving DataProtection BackupInstance (%q): %+v", id, err) + return nil, fmt.Errorf("retrieving %s: %+v", *id, err) } return utils.Bool(true), nil } diff --git a/internal/services/dataprotection/data_protection_backup_policy_blob_storage_resource.go b/internal/services/dataprotection/data_protection_backup_policy_blob_storage_resource.go index 6c01d0500c36..bbfdf86d6d88 100644 --- a/internal/services/dataprotection/data_protection_backup_policy_blob_storage_resource.go +++ b/internal/services/dataprotection/data_protection_backup_policy_blob_storage_resource.go @@ -6,13 +6,12 @@ import ( "regexp" "time" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" helperValidate "github.com/hashicorp/terraform-provider-azurerm/helpers/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dataprotection/legacysdk/dataprotection" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dataprotection/parse" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dataprotection/validate" azSchema "github.com/hashicorp/terraform-provider-azurerm/internal/tf/schema" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" @@ -33,7 +32,7 @@ func resourceDataProtectionBackupPolicyBlobStorage() *schema.Resource { }, Importer: azSchema.ValidateResourceIDPriorToImport(func(id string) error { - _, err := parse.BackupPolicyID(id) + _, err := backuppolicies.ParseBackupPoliciesID(id) return err }), @@ -52,7 +51,7 @@ func resourceDataProtectionBackupPolicyBlobStorage() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: validate.BackupVaultID, + ValidateFunc: backuppolicies.ValidateBackupVaultID, }, "retention_duration": { @@ -72,47 +71,44 @@ func resourceDataProtectionBackupPolicyBlobStorageCreate(d *schema.ResourceData, defer cancel() name := d.Get("name").(string) - vaultId, _ := parse.BackupVaultID(d.Get("vault_id").(string)) - id := parse.NewBackupPolicyID(subscriptionId, vaultId.ResourceGroup, vaultId.Name, name) + vaultId, _ := backuppolicies.ParseBackupVaultID(d.Get("vault_id").(string)) + id := backuppolicies.NewBackupPoliciesID(subscriptionId, vaultId.ResourceGroupName, vaultId.VaultName, name) - existing, err := client.Get(ctx, id.BackupVaultName, id.ResourceGroup, id.Name) + existing, err := client.Get(ctx, id) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return fmt.Errorf("checking for existing DataProtection BackupPolicy (%q): %+v", id, err) } } - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return tf.ImportAsExistsError("azurerm_data_protection_backup_policy_blob_storage", id.ID()) } - parameters := dataprotection.BaseBackupPolicyResource{ - Properties: &dataprotection.BackupPolicy{ - PolicyRules: &[]dataprotection.BasicBasePolicyRule{ - dataprotection.AzureRetentionRule{ - Name: utils.String("Default"), - ObjectType: dataprotection.ObjectTypeBasicBasePolicyRuleObjectTypeAzureRetentionRule, - IsDefault: utils.Bool(true), - Lifecycles: &[]dataprotection.SourceLifeCycle{ + parameters := backuppolicies.BaseBackupPolicyResource{ + Properties: &backuppolicies.BackupPolicy{ + PolicyRules: []backuppolicies.BasePolicyRule{ + backuppolicies.AzureRetentionRule{ + Name: "Default", + IsDefault: utils.Bool(true), + Lifecycles: []backuppolicies.SourceLifeCycle{ { - DeleteAfter: dataprotection.AbsoluteDeleteOption{ - Duration: utils.String(d.Get("retention_duration").(string)), - ObjectType: dataprotection.ObjectTypeBasicDeleteOptionObjectTypeAbsoluteDeleteOption, + DeleteAfter: backuppolicies.AbsoluteDeleteOption{ + Duration: d.Get("retention_duration").(string), }, - SourceDataStore: &dataprotection.DataStoreInfoBase{ + SourceDataStore: backuppolicies.DataStoreInfoBase{ DataStoreType: "OperationalStore", - ObjectType: utils.String("DataStoreInfoBase"), + ObjectType: "DataStoreInfoBase", }, - TargetDataStoreCopySettings: &[]dataprotection.TargetCopySetting{}, + TargetDataStoreCopySettings: &[]backuppolicies.TargetCopySetting{}, }, }, }, }, - DatasourceTypes: &[]string{"Microsoft.Storage/storageAccounts/blobServices"}, - ObjectType: dataprotection.ObjectTypeBasicBaseBackupPolicyObjectTypeBackupPolicy, + DatasourceTypes: []string{"Microsoft.Storage/storageAccounts/blobServices"}, }, } - if _, err := client.CreateOrUpdate(ctx, id.BackupVaultName, id.ResourceGroup, id.Name, parameters); err != nil { + if _, err := client.CreateOrUpdate(ctx, id, parameters); err != nil { return fmt.Errorf("creating/updating DataProtection BackupPolicy (%q): %+v", id, err) } @@ -125,27 +121,29 @@ func resourceDataProtectionBackupPolicyBlobStorageRead(d *schema.ResourceData, m ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.BackupPolicyID(d.Id()) + id, err := backuppolicies.ParseBackupPoliciesID(d.Id()) if err != nil { return err } - resp, err := client.Get(ctx, id.BackupVaultName, id.ResourceGroup, id.Name) + resp, err := client.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { log.Printf("[INFO] dataprotection %q does not exist - removing from state", d.Id()) d.SetId("") return nil } return fmt.Errorf("retrieving DataProtection BackupPolicy (%q): %+v", id, err) } - vaultId := parse.NewBackupVaultID(id.SubscriptionId, id.ResourceGroup, id.BackupVaultName) - d.Set("name", id.Name) + vaultId := backuppolicies.NewBackupVaultID(id.SubscriptionId, id.ResourceGroupName, id.VaultName) + d.Set("name", id.BackupPolicyName) d.Set("vault_id", vaultId.ID()) - if resp.Properties != nil { - if props, ok := resp.Properties.AsBackupPolicy(); ok { - if err := d.Set("retention_duration", flattenBackupPolicyBlobStorageDefaultRetentionRuleDuration(props.PolicyRules)); err != nil { - return fmt.Errorf("setting `default_retention_duration`: %+v", err) + if resp.Model != nil { + if resp.Model.Properties != nil { + if props, ok := resp.Model.Properties.(backuppolicies.BackupPolicy); ok { + if err := d.Set("retention_duration", flattenBackupPolicyBlobStorageDefaultRetentionRuleDuration(props.PolicyRules)); err != nil { + return fmt.Errorf("setting `default_retention_duration`: %+v", err) + } } } } @@ -157,13 +155,13 @@ func resourceDataProtectionBackupPolicyBlobStorageDelete(d *schema.ResourceData, ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.BackupPolicyID(d.Id()) + id, err := backuppolicies.ParseBackupPoliciesID(d.Id()) if err != nil { return err } - if resp, err := client.Delete(ctx, id.BackupVaultName, id.ResourceGroup, id.Name); err != nil { - if utils.ResponseWasNotFound(resp) { + if resp, err := client.Delete(ctx, *id); err != nil { + if response.WasNotFound(resp.HttpResponse) { return nil } @@ -172,16 +170,16 @@ func resourceDataProtectionBackupPolicyBlobStorageDelete(d *schema.ResourceData, return nil } -func flattenBackupPolicyBlobStorageDefaultRetentionRuleDuration(input *[]dataprotection.BasicBasePolicyRule) interface{} { +func flattenBackupPolicyBlobStorageDefaultRetentionRuleDuration(input []backuppolicies.BasePolicyRule) interface{} { if input == nil { return nil } - for _, item := range *input { - if retentionRule, ok := item.AsAzureRetentionRule(); ok && retentionRule.IsDefault != nil && *retentionRule.IsDefault { - if retentionRule.Lifecycles != nil && len(*retentionRule.Lifecycles) > 0 { - if deleteOption, ok := (*retentionRule.Lifecycles)[0].DeleteAfter.AsAbsoluteDeleteOption(); ok { - return *deleteOption.Duration + for _, item := range input { + if retentionRule, ok := item.(backuppolicies.AzureRetentionRule); ok && retentionRule.IsDefault != nil && *retentionRule.IsDefault { + if retentionRule.Lifecycles != nil && len(retentionRule.Lifecycles) > 0 { + if deleteOption, ok := (retentionRule.Lifecycles)[0].DeleteAfter.(backuppolicies.AbsoluteDeleteOption); ok { + return deleteOption.Duration } } } diff --git a/internal/services/dataprotection/data_protection_backup_policy_blob_storage_resource_test.go b/internal/services/dataprotection/data_protection_backup_policy_blob_storage_resource_test.go index a2965b1328e8..248e8af1c3f8 100644 --- a/internal/services/dataprotection/data_protection_backup_policy_blob_storage_resource_test.go +++ b/internal/services/dataprotection/data_protection_backup_policy_blob_storage_resource_test.go @@ -5,12 +5,13 @@ import ( "fmt" "testing" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dataprotection/parse" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -45,13 +46,13 @@ func TestAccDataProtectionBackupPolicyBlobStorage_requiresImport(t *testing.T) { } func (r DataProtectionBackupPolicyBlobStorageResource) Exists(ctx context.Context, client *clients.Client, state *terraform.InstanceState) (*bool, error) { - id, err := parse.BackupPolicyID(state.ID) + id, err := backuppolicies.ParseBackupPoliciesID(state.ID) if err != nil { return nil, err } - resp, err := client.DataProtection.BackupPolicyClient.Get(ctx, id.BackupVaultName, id.ResourceGroup, id.Name) + resp, err := client.DataProtection.BackupPolicyClient.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { return utils.Bool(false), nil } return nil, fmt.Errorf("retrieving DataProtection BackupPolicy (%q): %+v", id, err) diff --git a/internal/services/dataprotection/data_protection_backup_policy_disk_resource.go b/internal/services/dataprotection/data_protection_backup_policy_disk_resource.go index 4c2a209cf35e..60dd2cf37163 100644 --- a/internal/services/dataprotection/data_protection_backup_policy_disk_resource.go +++ b/internal/services/dataprotection/data_protection_backup_policy_disk_resource.go @@ -7,13 +7,12 @@ import ( "strings" "time" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" helperValidate "github.com/hashicorp/terraform-provider-azurerm/helpers/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dataprotection/legacysdk/dataprotection" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dataprotection/parse" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dataprotection/validate" azSchema "github.com/hashicorp/terraform-provider-azurerm/internal/tf/schema" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" @@ -34,7 +33,7 @@ func resourceDataProtectionBackupPolicyDisk() *schema.Resource { }, Importer: azSchema.ValidateResourceIDPriorToImport(func(id string) error { - _, err := parse.BackupPolicyID(id) + _, err := backuppolicies.ParseBackupPoliciesID(id) return err }), @@ -53,7 +52,7 @@ func resourceDataProtectionBackupPolicyDisk() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: validate.BackupVaultID, + ValidateFunc: backuppolicies.ValidateBackupVaultID, }, "backup_repeating_time_intervals": { @@ -104,8 +103,8 @@ func resourceDataProtectionBackupPolicyDisk() *schema.Resource { Optional: true, ForceNew: true, ValidateFunc: validation.StringInSlice([]string{ - string(dataprotection.AbsoluteMarkerFirstOfDay), - string(dataprotection.AbsoluteMarkerFirstOfWeek), + string(backuppolicies.AbsoluteMarkerFirstOfDay), + string(backuppolicies.AbsoluteMarkerFirstOfWeek), }, false), }, }, @@ -131,33 +130,32 @@ func resourceDataProtectionBackupPolicyDiskCreate(d *schema.ResourceData, meta i defer cancel() name := d.Get("name").(string) - vaultId, _ := parse.BackupVaultID(d.Get("vault_id").(string)) - id := parse.NewBackupPolicyID(subscriptionId, vaultId.ResourceGroup, vaultId.Name, name) + vaultId, _ := backuppolicies.ParseBackupVaultID(d.Get("vault_id").(string)) + id := backuppolicies.NewBackupPoliciesID(subscriptionId, vaultId.ResourceGroupName, vaultId.VaultName, name) - existing, err := client.Get(ctx, id.BackupVaultName, id.ResourceGroup, id.Name) + existing, err := client.Get(ctx, id) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return fmt.Errorf("checking for existing DataProtection BackupPolicy (%q): %+v", id, err) } } - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return tf.ImportAsExistsError("azurerm_data_protection_backup_policy_disk", id.ID()) } taggingCriteria := expandBackupPolicyDiskTaggingCriteriaArray(d.Get("retention_rule").([]interface{})) - policyRules := make([]dataprotection.BasicBasePolicyRule, 0) + policyRules := make([]backuppolicies.BasePolicyRule, 0) policyRules = append(policyRules, expandBackupPolicyDiskAzureBackupRuleArray(d.Get("backup_repeating_time_intervals").([]interface{}), taggingCriteria)...) policyRules = append(policyRules, expandBackupPolicyDiskDefaultAzureRetentionRule(d.Get("default_retention_duration"))) policyRules = append(policyRules, expandBackupPolicyDiskAzureRetentionRuleArray(d.Get("retention_rule").([]interface{}))...) - parameters := dataprotection.BaseBackupPolicyResource{ - Properties: &dataprotection.BackupPolicy{ - PolicyRules: &policyRules, - DatasourceTypes: &[]string{"Microsoft.Compute/disks"}, - ObjectType: dataprotection.ObjectTypeBasicBaseBackupPolicyObjectTypeBackupPolicy, + parameters := backuppolicies.BaseBackupPolicyResource{ + Properties: &backuppolicies.BackupPolicy{ + PolicyRules: policyRules, + DatasourceTypes: []string{"Microsoft.Compute/disks"}, }, } - if _, err := client.CreateOrUpdate(ctx, id.BackupVaultName, id.ResourceGroup, id.Name, parameters); err != nil { + if _, err := client.CreateOrUpdate(ctx, id, parameters); err != nil { return fmt.Errorf("creating/updating DataProtection BackupPolicy (%q): %+v", id, err) } @@ -170,33 +168,35 @@ func resourceDataProtectionBackupPolicyDiskRead(d *schema.ResourceData, meta int ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.BackupPolicyID(d.Id()) + id, err := backuppolicies.ParseBackupPoliciesID(d.Id()) if err != nil { return err } - resp, err := client.Get(ctx, id.BackupVaultName, id.ResourceGroup, id.Name) + resp, err := client.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { log.Printf("[INFO] dataprotection %q does not exist - removing from state", d.Id()) d.SetId("") return nil } return fmt.Errorf("retrieving DataProtection BackupPolicy (%q): %+v", id, err) } - vaultId := parse.NewBackupVaultID(id.SubscriptionId, id.ResourceGroup, id.BackupVaultName) - d.Set("name", id.Name) + vaultId := backuppolicies.NewBackupVaultID(id.SubscriptionId, id.ResourceGroupName, id.VaultName) + d.Set("name", id.BackupPolicyName) d.Set("vault_id", vaultId.ID()) - if resp.Properties != nil { - if props, ok := resp.Properties.AsBackupPolicy(); ok { - if err := d.Set("backup_repeating_time_intervals", flattenBackupPolicyDiskBackupRuleArray(props.PolicyRules)); err != nil { - return fmt.Errorf("setting `backup_repeating_time_intervals`: %+v", err) - } - if err := d.Set("default_retention_duration", flattenBackupPolicyDiskDefaultRetentionRuleDuration(props.PolicyRules)); err != nil { - return fmt.Errorf("setting `default_retention_duration`: %+v", err) - } - if err := d.Set("retention_rule", flattenBackupPolicyDiskRetentionRuleArray(props.PolicyRules)); err != nil { - return fmt.Errorf("setting `retention_rule`: %+v", err) + if resp.Model != nil { + if resp.Model.Properties != nil { + if props, ok := resp.Model.Properties.(backuppolicies.BackupPolicy); ok { + if err := d.Set("backup_repeating_time_intervals", flattenBackupPolicyDiskBackupRuleArray(&props.PolicyRules)); err != nil { + return fmt.Errorf("setting `backup_repeating_time_intervals`: %+v", err) + } + if err := d.Set("default_retention_duration", flattenBackupPolicyDiskDefaultRetentionRuleDuration(&props.PolicyRules)); err != nil { + return fmt.Errorf("setting `default_retention_duration`: %+v", err) + } + if err := d.Set("retention_rule", flattenBackupPolicyDiskRetentionRuleArray(&props.PolicyRules)); err != nil { + return fmt.Errorf("setting `retention_rule`: %+v", err) + } } } } @@ -208,13 +208,13 @@ func resourceDataProtectionBackupPolicyDiskDelete(d *schema.ResourceData, meta i ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.BackupPolicyID(d.Id()) + id, err := backuppolicies.ParseBackupPoliciesID(d.Id()) if err != nil { return err } - if resp, err := client.Delete(ctx, id.BackupVaultName, id.ResourceGroup, id.Name); err != nil { - if utils.ResponseWasNotFound(resp) { + if resp, err := client.Delete(ctx, *id); err != nil { + if response.WasNotFound(resp.HttpResponse) { return nil } @@ -223,50 +223,45 @@ func resourceDataProtectionBackupPolicyDiskDelete(d *schema.ResourceData, meta i return nil } -func expandBackupPolicyDiskAzureBackupRuleArray(input []interface{}, taggingCriteria *[]dataprotection.TaggingCriteria) []dataprotection.BasicBasePolicyRule { - results := make([]dataprotection.BasicBasePolicyRule, 0) +func expandBackupPolicyDiskAzureBackupRuleArray(input []interface{}, taggingCriteria *[]backuppolicies.TaggingCriteria) []backuppolicies.BasePolicyRule { + results := make([]backuppolicies.BasePolicyRule, 0) - results = append(results, dataprotection.AzureBackupRule{ - Name: utils.String("BackupIntervals"), - ObjectType: dataprotection.ObjectTypeBasicBasePolicyRuleObjectTypeAzureBackupRule, - DataStore: &dataprotection.DataStoreInfoBase{ - DataStoreType: dataprotection.DataStoreTypesOperationalStore, - ObjectType: utils.String("DataStoreInfoBase"), + results = append(results, backuppolicies.AzureBackupRule{ + Name: "BackupIntervals", + DataStore: backuppolicies.DataStoreInfoBase{ + DataStoreType: backuppolicies.DataStoreTypesOperationalStore, + ObjectType: "DataStoreInfoBase", }, - BackupParameters: &dataprotection.AzureBackupParams{ - BackupType: utils.String("Incremental"), - ObjectType: dataprotection.ObjectTypeBasicBackupParametersObjectTypeAzureBackupParams, + BackupParameters: &backuppolicies.AzureBackupParams{ + BackupType: "Incremental", }, - Trigger: dataprotection.ScheduleBasedTriggerContext{ - Schedule: &dataprotection.BackupSchedule{ - RepeatingTimeIntervals: utils.ExpandStringSlice(input), + Trigger: backuppolicies.ScheduleBasedTriggerContext{ + Schedule: backuppolicies.BackupSchedule{ + RepeatingTimeIntervals: *utils.ExpandStringSlice(input), }, - TaggingCriteria: taggingCriteria, - ObjectType: dataprotection.ObjectTypeBasicTriggerContextObjectTypeScheduleBasedTriggerContext, + TaggingCriteria: *taggingCriteria, }, }) return results } -func expandBackupPolicyDiskAzureRetentionRuleArray(input []interface{}) []dataprotection.BasicBasePolicyRule { - results := make([]dataprotection.BasicBasePolicyRule, 0) +func expandBackupPolicyDiskAzureRetentionRuleArray(input []interface{}) []backuppolicies.BasePolicyRule { + results := make([]backuppolicies.BasePolicyRule, 0) for _, item := range input { v := item.(map[string]interface{}) - results = append(results, dataprotection.AzureRetentionRule{ - Name: utils.String(v["name"].(string)), - ObjectType: dataprotection.ObjectTypeBasicBasePolicyRuleObjectTypeAzureRetentionRule, - IsDefault: utils.Bool(false), - Lifecycles: &[]dataprotection.SourceLifeCycle{ + results = append(results, backuppolicies.AzureRetentionRule{ + Name: v["name"].(string), + IsDefault: utils.Bool(false), + Lifecycles: []backuppolicies.SourceLifeCycle{ { - DeleteAfter: dataprotection.AbsoluteDeleteOption{ - Duration: utils.String(v["duration"].(string)), - ObjectType: dataprotection.ObjectTypeBasicDeleteOptionObjectTypeAbsoluteDeleteOption, + DeleteAfter: backuppolicies.AbsoluteDeleteOption{ + Duration: v["duration"].(string), }, - SourceDataStore: &dataprotection.DataStoreInfoBase{ + SourceDataStore: backuppolicies.DataStoreInfoBase{ DataStoreType: "OperationalStore", - ObjectType: utils.String("DataStoreInfoBase"), + ObjectType: "DataStoreInfoBase", }, - TargetDataStoreCopySettings: &[]dataprotection.TargetCopySetting{}, + TargetDataStoreCopySettings: &[]backuppolicies.TargetCopySetting{}, }, }, }) @@ -274,81 +269,76 @@ func expandBackupPolicyDiskAzureRetentionRuleArray(input []interface{}) []datapr return results } -func expandBackupPolicyDiskDefaultAzureRetentionRule(input interface{}) dataprotection.BasicBasePolicyRule { - return dataprotection.AzureRetentionRule{ - Name: utils.String("Default"), - ObjectType: dataprotection.ObjectTypeBasicBasePolicyRuleObjectTypeAzureRetentionRule, - IsDefault: utils.Bool(true), - Lifecycles: &[]dataprotection.SourceLifeCycle{ +func expandBackupPolicyDiskDefaultAzureRetentionRule(input interface{}) backuppolicies.BasePolicyRule { + return backuppolicies.AzureRetentionRule{ + Name: "Default", + IsDefault: utils.Bool(true), + Lifecycles: []backuppolicies.SourceLifeCycle{ { - DeleteAfter: dataprotection.AbsoluteDeleteOption{ - Duration: utils.String(input.(string)), - ObjectType: dataprotection.ObjectTypeBasicDeleteOptionObjectTypeAbsoluteDeleteOption, + DeleteAfter: backuppolicies.AbsoluteDeleteOption{ + Duration: input.(string), }, - SourceDataStore: &dataprotection.DataStoreInfoBase{ + SourceDataStore: backuppolicies.DataStoreInfoBase{ DataStoreType: "OperationalStore", - ObjectType: utils.String("DataStoreInfoBase"), + ObjectType: "DataStoreInfoBase", }, - TargetDataStoreCopySettings: &[]dataprotection.TargetCopySetting{}, + TargetDataStoreCopySettings: &[]backuppolicies.TargetCopySetting{}, }, }, } } -func expandBackupPolicyDiskTaggingCriteriaArray(input []interface{}) *[]dataprotection.TaggingCriteria { - results := []dataprotection.TaggingCriteria{ +func expandBackupPolicyDiskTaggingCriteriaArray(input []interface{}) *[]backuppolicies.TaggingCriteria { + results := []backuppolicies.TaggingCriteria{ { Criteria: nil, - IsDefault: utils.Bool(true), - TaggingPriority: utils.Int64(99), - TagInfo: &dataprotection.RetentionTag{ - ID: utils.String("Default_"), - TagName: utils.String("Default"), + IsDefault: true, + TaggingPriority: 99, + TagInfo: backuppolicies.RetentionTag{ + Id: utils.String("Default_"), + TagName: "Default", }, }, } for _, item := range input { v := item.(map[string]interface{}) - results = append(results, dataprotection.TaggingCriteria{ + results = append(results, backuppolicies.TaggingCriteria{ Criteria: expandBackupPolicyDiskCriteriaArray(v["criteria"].([]interface{})), - IsDefault: utils.Bool(false), - TaggingPriority: utils.Int64(int64(v["priority"].(int))), - TagInfo: &dataprotection.RetentionTag{ - ID: utils.String(v["name"].(string) + "_"), - TagName: utils.String(v["name"].(string)), + IsDefault: false, + TaggingPriority: int64(v["priority"].(int)), + TagInfo: backuppolicies.RetentionTag{ + Id: utils.String(v["name"].(string) + "_"), + TagName: v["name"].(string), }, }) } return &results } -func expandBackupPolicyDiskCriteriaArray(input []interface{}) *[]dataprotection.BasicBackupCriteria { - results := make([]dataprotection.BasicBackupCriteria, 0) +func expandBackupPolicyDiskCriteriaArray(input []interface{}) *[]backuppolicies.BackupCriteria { + results := make([]backuppolicies.BackupCriteria, 0) for _, item := range input { v := item.(map[string]interface{}) - var absoluteCriteria []dataprotection.AbsoluteMarker + var absoluteCriteria []backuppolicies.AbsoluteMarker if absoluteCriteriaRaw := v["absolute_criteria"].(string); len(absoluteCriteriaRaw) > 0 { - absoluteCriteria = []dataprotection.AbsoluteMarker{dataprotection.AbsoluteMarker(absoluteCriteriaRaw)} + absoluteCriteria = []backuppolicies.AbsoluteMarker{backuppolicies.AbsoluteMarker(absoluteCriteriaRaw)} } - results = append(results, dataprotection.ScheduleBasedBackupCriteria{ + results = append(results, backuppolicies.ScheduleBasedBackupCriteria{ AbsoluteCriteria: &absoluteCriteria, - ObjectType: dataprotection.ObjectTypeBasicBackupCriteriaObjectTypeScheduleBasedBackupCriteria, }) } return &results } -func flattenBackupPolicyDiskBackupRuleArray(input *[]dataprotection.BasicBasePolicyRule) []interface{} { +func flattenBackupPolicyDiskBackupRuleArray(input *[]backuppolicies.BasePolicyRule) []interface{} { if input == nil { return make([]interface{}, 0) } for _, item := range *input { - if backupRule, ok := item.AsAzureBackupRule(); ok { + if backupRule, ok := item.(backuppolicies.AzureBackupRule); ok { if backupRule.Trigger != nil { - if scheduleBasedTrigger, ok := backupRule.Trigger.AsScheduleBasedTriggerContext(); ok { - if scheduleBasedTrigger.Schedule != nil { - return utils.FlattenStringSlice(scheduleBasedTrigger.Schedule.RepeatingTimeIntervals) - } + if scheduleBasedTrigger, ok := backupRule.Trigger.(backuppolicies.ScheduleBasedTriggerContext); ok { + return utils.FlattenStringSlice(&scheduleBasedTrigger.Schedule.RepeatingTimeIntervals) } } } @@ -356,16 +346,16 @@ func flattenBackupPolicyDiskBackupRuleArray(input *[]dataprotection.BasicBasePol return make([]interface{}, 0) } -func flattenBackupPolicyDiskDefaultRetentionRuleDuration(input *[]dataprotection.BasicBasePolicyRule) interface{} { +func flattenBackupPolicyDiskDefaultRetentionRuleDuration(input *[]backuppolicies.BasePolicyRule) interface{} { if input == nil { return nil } for _, item := range *input { - if retentionRule, ok := item.AsAzureRetentionRule(); ok && retentionRule.IsDefault != nil && *retentionRule.IsDefault { - if retentionRule.Lifecycles != nil && len(*retentionRule.Lifecycles) > 0 { - if deleteOption, ok := (*retentionRule.Lifecycles)[0].DeleteAfter.AsAbsoluteDeleteOption(); ok { - return *deleteOption.Duration + if retentionRule, ok := item.(backuppolicies.AzureRetentionRule); ok && retentionRule.IsDefault != nil && *retentionRule.IsDefault { + if retentionRule.Lifecycles != nil && len(retentionRule.Lifecycles) > 0 { + if deleteOption, ok := (retentionRule.Lifecycles)[0].DeleteAfter.(backuppolicies.AbsoluteDeleteOption); ok { + return deleteOption.Duration } } } @@ -373,41 +363,38 @@ func flattenBackupPolicyDiskDefaultRetentionRuleDuration(input *[]dataprotection return nil } -func flattenBackupPolicyDiskRetentionRuleArray(input *[]dataprotection.BasicBasePolicyRule) []interface{} { +func flattenBackupPolicyDiskRetentionRuleArray(input *[]backuppolicies.BasePolicyRule) []interface{} { results := make([]interface{}, 0) if input == nil { return results } - var taggingCriterias []dataprotection.TaggingCriteria + var taggingCriterias []backuppolicies.TaggingCriteria for _, item := range *input { - if backupRule, ok := item.AsAzureBackupRule(); ok { - if trigger, ok := backupRule.Trigger.AsScheduleBasedTriggerContext(); ok { + if backupRule, ok := item.(backuppolicies.AzureBackupRule); ok { + if trigger, ok := backupRule.Trigger.(backuppolicies.ScheduleBasedTriggerContext); ok { if trigger.TaggingCriteria != nil { - taggingCriterias = *trigger.TaggingCriteria + taggingCriterias = trigger.TaggingCriteria } } } } for _, item := range *input { - if retentionRule, ok := item.AsAzureRetentionRule(); ok && (retentionRule.IsDefault == nil || !*retentionRule.IsDefault) { - var name string - if retentionRule.Name != nil { - name = *retentionRule.Name - } + if retentionRule, ok := item.(backuppolicies.AzureRetentionRule); ok && (retentionRule.IsDefault == nil || !*retentionRule.IsDefault) { + name := retentionRule.Name var taggingPriority int64 var taggingCriteria []interface{} for _, criteria := range taggingCriterias { - if criteria.TagInfo != nil && criteria.TagInfo.TagName != nil && strings.EqualFold(*criteria.TagInfo.TagName, name) { - taggingPriority = *criteria.TaggingPriority + if strings.EqualFold(criteria.TagInfo.TagName, name) { + taggingPriority = criteria.TaggingPriority taggingCriteria = flattenBackupPolicyDiskBackupCriteriaArray(criteria.Criteria) } } var duration string - if retentionRule.Lifecycles != nil && len(*retentionRule.Lifecycles) > 0 { - if deleteOption, ok := (*retentionRule.Lifecycles)[0].DeleteAfter.AsAbsoluteDeleteOption(); ok { - duration = *deleteOption.Duration + if retentionRule.Lifecycles != nil && len(retentionRule.Lifecycles) > 0 { + if deleteOption, ok := (retentionRule.Lifecycles)[0].DeleteAfter.(backuppolicies.AbsoluteDeleteOption); ok { + duration = deleteOption.Duration } } results = append(results, map[string]interface{}{ @@ -421,14 +408,14 @@ func flattenBackupPolicyDiskRetentionRuleArray(input *[]dataprotection.BasicBase return results } -func flattenBackupPolicyDiskBackupCriteriaArray(input *[]dataprotection.BasicBackupCriteria) []interface{} { +func flattenBackupPolicyDiskBackupCriteriaArray(input *[]backuppolicies.BackupCriteria) []interface{} { results := make([]interface{}, 0) if input == nil { return results } for _, item := range *input { - if criteria, ok := item.AsScheduleBasedBackupCriteria(); ok { + if criteria, ok := item.(backuppolicies.ScheduleBasedBackupCriteria); ok { var absoluteCriteria string if criteria.AbsoluteCriteria != nil && len(*criteria.AbsoluteCriteria) > 0 { absoluteCriteria = string((*criteria.AbsoluteCriteria)[0]) diff --git a/internal/services/dataprotection/data_protection_backup_policy_disk_resource_test.go b/internal/services/dataprotection/data_protection_backup_policy_disk_resource_test.go index 19291fa48421..b4ea6899ca91 100644 --- a/internal/services/dataprotection/data_protection_backup_policy_disk_resource_test.go +++ b/internal/services/dataprotection/data_protection_backup_policy_disk_resource_test.go @@ -5,12 +5,13 @@ import ( "fmt" "testing" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dataprotection/parse" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -87,13 +88,13 @@ func TestAccDataProtectionBackupPolicyDisk_update(t *testing.T) { } func (r DataProtectionBackupPolicyDiskResource) Exists(ctx context.Context, client *clients.Client, state *terraform.InstanceState) (*bool, error) { - id, err := parse.BackupPolicyID(state.ID) + id, err := backuppolicies.ParseBackupPoliciesID(state.ID) if err != nil { return nil, err } - resp, err := client.DataProtection.BackupPolicyClient.Get(ctx, id.BackupVaultName, id.ResourceGroup, id.Name) + resp, err := client.DataProtection.BackupPolicyClient.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { return utils.Bool(false), nil } return nil, fmt.Errorf("retrieving DataProtection BackupPolicy (%q): %+v", id, err) diff --git a/internal/services/dataprotection/data_protection_backup_policy_postgresql_resource.go b/internal/services/dataprotection/data_protection_backup_policy_postgresql_resource.go index 7d4a3ecf50f5..45ff75ddcd54 100644 --- a/internal/services/dataprotection/data_protection_backup_policy_postgresql_resource.go +++ b/internal/services/dataprotection/data_protection_backup_policy_postgresql_resource.go @@ -7,13 +7,12 @@ import ( "strings" "time" - "github.com/Azure/go-autorest/autorest/date" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/helpers/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dataprotection/legacysdk/dataprotection" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dataprotection/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" @@ -34,7 +33,7 @@ func resourceDataProtectionBackupPolicyPostgreSQL() *pluginsdk.Resource { }, Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - _, err := parse.BackupPolicyID(id) + _, err := backuppolicies.ParseBackupPoliciesID(id) return err }), @@ -105,11 +104,11 @@ func resourceDataProtectionBackupPolicyPostgreSQL() *pluginsdk.Resource { Optional: true, ForceNew: true, ValidateFunc: validation.StringInSlice([]string{ - string(dataprotection.AbsoluteMarkerAllBackup), - string(dataprotection.AbsoluteMarkerFirstOfDay), - string(dataprotection.AbsoluteMarkerFirstOfMonth), - string(dataprotection.AbsoluteMarkerFirstOfWeek), - string(dataprotection.AbsoluteMarkerFirstOfYear), + string(backuppolicies.AbsoluteMarkerAllBackup), + string(backuppolicies.AbsoluteMarkerFirstOfDay), + string(backuppolicies.AbsoluteMarkerFirstOfMonth), + string(backuppolicies.AbsoluteMarkerFirstOfWeek), + string(backuppolicies.AbsoluteMarkerFirstOfYear), }, false), }, @@ -154,11 +153,11 @@ func resourceDataProtectionBackupPolicyPostgreSQL() *pluginsdk.Resource { Elem: &pluginsdk.Schema{ Type: pluginsdk.TypeString, ValidateFunc: validation.StringInSlice([]string{ - string(dataprotection.WeekNumberFirst), - string(dataprotection.WeekNumberSecond), - string(dataprotection.WeekNumberThird), - string(dataprotection.WeekNumberFourth), - string(dataprotection.WeekNumberLast), + string(backuppolicies.WeekNumberFirst), + string(backuppolicies.WeekNumberSecond), + string(backuppolicies.WeekNumberThird), + string(backuppolicies.WeekNumberFourth), + string(backuppolicies.WeekNumberLast), }, false), }, }, @@ -188,32 +187,35 @@ func resourceDataProtectionBackupPolicyPostgreSQLCreate(d *pluginsdk.ResourceDat resourceGroup := d.Get("resource_group_name").(string) vaultName := d.Get("vault_name").(string) - id := parse.NewBackupPolicyID(subscriptionId, resourceGroup, vaultName, name) + id := backuppolicies.NewBackupPoliciesID(subscriptionId, resourceGroup, vaultName, name) - existing, err := client.Get(ctx, id.BackupVaultName, id.ResourceGroup, id.Name) + existing, err := client.Get(ctx, id) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return fmt.Errorf("checking for existing DataProtection BackupPolicy (%q): %+v", id, err) } } - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return tf.ImportAsExistsError("azurerm_data_protection_backup_policy_postgresql", id.ID()) } - taggingCriteria := expandBackupPolicyPostgreSQLTaggingCriteriaArray(d.Get("retention_rule").([]interface{})) - policyRules := make([]dataprotection.BasicBasePolicyRule, 0) + taggingCriteria, err := expandBackupPolicyPostgreSQLTaggingCriteriaArray(d.Get("retention_rule").([]interface{})) + if err != nil { + return err + } + + policyRules := make([]backuppolicies.BasePolicyRule, 0) policyRules = append(policyRules, expandBackupPolicyPostgreSQLAzureBackupRuleArray(d.Get("backup_repeating_time_intervals").([]interface{}), taggingCriteria)...) policyRules = append(policyRules, expandBackupPolicyPostgreSQLDefaultAzureRetentionRule(d.Get("default_retention_duration"))) policyRules = append(policyRules, expandBackupPolicyPostgreSQLAzureRetentionRuleArray(d.Get("retention_rule").([]interface{}))...) - parameters := dataprotection.BaseBackupPolicyResource{ - Properties: &dataprotection.BackupPolicy{ - PolicyRules: &policyRules, - DatasourceTypes: &[]string{"Microsoft.DBforPostgreSQL/servers/databases"}, - ObjectType: dataprotection.ObjectTypeBasicBaseBackupPolicyObjectTypeBackupPolicy, + parameters := backuppolicies.BaseBackupPolicyResource{ + Properties: &backuppolicies.BackupPolicy{ + PolicyRules: policyRules, + DatasourceTypes: []string{"Microsoft.DBforPostgreSQL/servers/databases"}, }, } - if _, err := client.CreateOrUpdate(ctx, id.BackupVaultName, id.ResourceGroup, id.Name, parameters); err != nil { + if _, err := client.CreateOrUpdate(ctx, id, parameters); err != nil { return fmt.Errorf("creating/updating DataProtection BackupPolicy (%q): %+v", id, err) } @@ -226,33 +228,36 @@ func resourceDataProtectionBackupPolicyPostgreSQLRead(d *pluginsdk.ResourceData, ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.BackupPolicyID(d.Id()) + id, err := backuppolicies.ParseBackupPoliciesID(d.Id()) if err != nil { return err } - resp, err := client.Get(ctx, id.BackupVaultName, id.ResourceGroup, id.Name) + resp, err := client.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { log.Printf("[INFO] dataprotection %q does not exist - removing from state", d.Id()) d.SetId("") return nil } return fmt.Errorf("retrieving DataProtection BackupPolicy (%q): %+v", id, err) } - d.Set("name", id.Name) - d.Set("resource_group_name", id.ResourceGroup) - d.Set("vault_name", id.BackupVaultName) - if resp.Properties != nil { - if props, ok := resp.Properties.AsBackupPolicy(); ok { - if err := d.Set("backup_repeating_time_intervals", flattenBackupPolicyPostgreSQLBackupRuleArray(props.PolicyRules)); err != nil { - return fmt.Errorf("setting `backup_rule`: %+v", err) - } - if err := d.Set("default_retention_duration", flattenBackupPolicyPostgreSQLDefaultRetentionRuleDuration(props.PolicyRules)); err != nil { - return fmt.Errorf("setting `default_retention_duration`: %+v", err) - } - if err := d.Set("retention_rule", flattenBackupPolicyPostgreSQLRetentionRuleArray(props.PolicyRules)); err != nil { - return fmt.Errorf("setting `retention_rule`: %+v", err) + d.Set("name", id.BackupPolicyName) + d.Set("resource_group_name", id.ResourceGroupName) + d.Set("vault_name", id.VaultName) + + if resp.Model != nil { + if resp.Model.Properties != nil { + if props, ok := resp.Model.Properties.(backuppolicies.BackupPolicy); ok { + if err := d.Set("backup_repeating_time_intervals", flattenBackupPolicyPostgreSQLBackupRuleArray(&props.PolicyRules)); err != nil { + return fmt.Errorf("setting `backup_rule`: %+v", err) + } + if err := d.Set("default_retention_duration", flattenBackupPolicyPostgreSQLDefaultRetentionRuleDuration(&props.PolicyRules)); err != nil { + return fmt.Errorf("setting `default_retention_duration`: %+v", err) + } + if err := d.Set("retention_rule", flattenBackupPolicyPostgreSQLRetentionRuleArray(&props.PolicyRules)); err != nil { + return fmt.Errorf("setting `retention_rule`: %+v", err) + } } } } @@ -264,13 +269,13 @@ func resourceDataProtectionBackupPolicyPostgreSQLDelete(d *pluginsdk.ResourceDat ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.BackupPolicyID(d.Id()) + id, err := backuppolicies.ParseBackupPoliciesID(d.Id()) if err != nil { return err } - if resp, err := client.Delete(ctx, id.BackupVaultName, id.ResourceGroup, id.Name); err != nil { - if utils.ResponseWasNotFound(resp) { + if resp, err := client.Delete(ctx, *id); err != nil { + if response.WasNotFound(resp.HttpResponse) { return nil } @@ -279,50 +284,45 @@ func resourceDataProtectionBackupPolicyPostgreSQLDelete(d *pluginsdk.ResourceDat return nil } -func expandBackupPolicyPostgreSQLAzureBackupRuleArray(input []interface{}, taggingCriteria *[]dataprotection.TaggingCriteria) []dataprotection.BasicBasePolicyRule { - results := make([]dataprotection.BasicBasePolicyRule, 0) - results = append(results, dataprotection.AzureBackupRule{ - Name: utils.String("BackupIntervals"), - ObjectType: dataprotection.ObjectTypeBasicBasePolicyRuleObjectTypeAzureBackupRule, - DataStore: &dataprotection.DataStoreInfoBase{ - DataStoreType: dataprotection.DataStoreTypesVaultStore, - ObjectType: utils.String("DataStoreInfoBase"), +func expandBackupPolicyPostgreSQLAzureBackupRuleArray(input []interface{}, taggingCriteria *[]backuppolicies.TaggingCriteria) []backuppolicies.BasePolicyRule { + results := make([]backuppolicies.BasePolicyRule, 0) + results = append(results, backuppolicies.AzureBackupRule{ + Name: "BackupIntervals", + DataStore: backuppolicies.DataStoreInfoBase{ + DataStoreType: backuppolicies.DataStoreTypesVaultStore, + ObjectType: "DataStoreInfoBase", }, - BackupParameters: &dataprotection.AzureBackupParams{ - BackupType: utils.String("Full"), - ObjectType: dataprotection.ObjectTypeBasicBackupParametersObjectTypeAzureBackupParams, + BackupParameters: &backuppolicies.AzureBackupParams{ + BackupType: "Full", }, - Trigger: dataprotection.ScheduleBasedTriggerContext{ - Schedule: &dataprotection.BackupSchedule{ - RepeatingTimeIntervals: utils.ExpandStringSlice(input), + Trigger: backuppolicies.ScheduleBasedTriggerContext{ + Schedule: backuppolicies.BackupSchedule{ + RepeatingTimeIntervals: *utils.ExpandStringSlice(input), }, - TaggingCriteria: taggingCriteria, - ObjectType: dataprotection.ObjectTypeBasicTriggerContextObjectTypeScheduleBasedTriggerContext, + TaggingCriteria: *taggingCriteria, }, }) return results } -func expandBackupPolicyPostgreSQLAzureRetentionRuleArray(input []interface{}) []dataprotection.BasicBasePolicyRule { - results := make([]dataprotection.BasicBasePolicyRule, 0) +func expandBackupPolicyPostgreSQLAzureRetentionRuleArray(input []interface{}) []backuppolicies.BasePolicyRule { + results := make([]backuppolicies.BasePolicyRule, 0) for _, item := range input { v := item.(map[string]interface{}) - results = append(results, dataprotection.AzureRetentionRule{ - Name: utils.String(v["name"].(string)), - ObjectType: dataprotection.ObjectTypeBasicBasePolicyRuleObjectTypeAzureRetentionRule, - IsDefault: utils.Bool(false), - Lifecycles: &[]dataprotection.SourceLifeCycle{ + results = append(results, backuppolicies.AzureRetentionRule{ + Name: v["name"].(string), + IsDefault: utils.Bool(false), + Lifecycles: []backuppolicies.SourceLifeCycle{ { - DeleteAfter: dataprotection.AbsoluteDeleteOption{ - Duration: utils.String(v["duration"].(string)), - ObjectType: dataprotection.ObjectTypeBasicDeleteOptionObjectTypeAbsoluteDeleteOption, + DeleteAfter: backuppolicies.AbsoluteDeleteOption{ + Duration: v["duration"].(string), }, - SourceDataStore: &dataprotection.DataStoreInfoBase{ + SourceDataStore: backuppolicies.DataStoreInfoBase{ DataStoreType: "VaultStore", - ObjectType: utils.String("DataStoreInfoBase"), + ObjectType: "DataStoreInfoBase", }, - TargetDataStoreCopySettings: &[]dataprotection.TargetCopySetting{}, + TargetDataStoreCopySettings: &[]backuppolicies.TargetCopySetting{}, }, }, }) @@ -330,119 +330,122 @@ func expandBackupPolicyPostgreSQLAzureRetentionRuleArray(input []interface{}) [] return results } -func expandBackupPolicyPostgreSQLDefaultAzureRetentionRule(input interface{}) dataprotection.BasicBasePolicyRule { - return dataprotection.AzureRetentionRule{ - Name: utils.String("Default"), - ObjectType: dataprotection.ObjectTypeBasicBasePolicyRuleObjectTypeAzureRetentionRule, - IsDefault: utils.Bool(true), - Lifecycles: &[]dataprotection.SourceLifeCycle{ +func expandBackupPolicyPostgreSQLDefaultAzureRetentionRule(input interface{}) backuppolicies.BasePolicyRule { + return backuppolicies.AzureRetentionRule{ + Name: "Default", + IsDefault: utils.Bool(true), + Lifecycles: []backuppolicies.SourceLifeCycle{ { - DeleteAfter: dataprotection.AbsoluteDeleteOption{ - Duration: utils.String(input.(string)), - ObjectType: dataprotection.ObjectTypeBasicDeleteOptionObjectTypeAbsoluteDeleteOption, + DeleteAfter: backuppolicies.AbsoluteDeleteOption{ + Duration: input.(string), }, - SourceDataStore: &dataprotection.DataStoreInfoBase{ + SourceDataStore: backuppolicies.DataStoreInfoBase{ DataStoreType: "VaultStore", - ObjectType: utils.String("DataStoreInfoBase"), + ObjectType: "DataStoreInfoBase", }, - TargetDataStoreCopySettings: &[]dataprotection.TargetCopySetting{}, + TargetDataStoreCopySettings: &[]backuppolicies.TargetCopySetting{}, }, }, } } -func expandBackupPolicyPostgreSQLTaggingCriteriaArray(input []interface{}) *[]dataprotection.TaggingCriteria { - results := []dataprotection.TaggingCriteria{ +func expandBackupPolicyPostgreSQLTaggingCriteriaArray(input []interface{}) (*[]backuppolicies.TaggingCriteria, error) { + results := []backuppolicies.TaggingCriteria{ + { Criteria: nil, - IsDefault: utils.Bool(true), - TaggingPriority: utils.Int64(99), - TagInfo: &dataprotection.RetentionTag{ - ID: utils.String("Default_"), - TagName: utils.String("Default"), + IsDefault: true, + TaggingPriority: 99, + TagInfo: backuppolicies.RetentionTag{ + Id: utils.String("Default_"), + TagName: "Default", }, }, } for _, item := range input { v := item.(map[string]interface{}) - results = append(results, dataprotection.TaggingCriteria{ - Criteria: expandBackupPolicyPostgreSQLCriteriaArray(v["criteria"].([]interface{})), - IsDefault: utils.Bool(false), - TaggingPriority: utils.Int64(int64(v["priority"].(int))), - TagInfo: &dataprotection.RetentionTag{ - ID: utils.String(v["name"].(string) + "_"), - TagName: utils.String(v["name"].(string)), + result := backuppolicies.TaggingCriteria{ + IsDefault: false, + TaggingPriority: int64(v["priority"].(int)), + TagInfo: backuppolicies.RetentionTag{ + Id: utils.String(v["name"].(string) + "_"), + TagName: v["name"].(string), }, - }) + } + + criteria, err := expandBackupPolicyPostgreSQLCriteriaArray(v["criteria"].([]interface{})) + if err != nil { + return nil, err + } + result.Criteria = criteria + + results = append(results, result) } - return &results + return &results, nil } -func expandBackupPolicyPostgreSQLCriteriaArray(input []interface{}) *[]dataprotection.BasicBackupCriteria { - results := make([]dataprotection.BasicBackupCriteria, 0) +func expandBackupPolicyPostgreSQLCriteriaArray(input []interface{}) (*[]backuppolicies.BackupCriteria, error) { + if len(input) == 0 || input[0] == nil { + return nil, fmt.Errorf("criteria is a required field, cannot leave blank") + } + results := make([]backuppolicies.BackupCriteria, 0) + for _, item := range input { v := item.(map[string]interface{}) - var absoluteCriteria []dataprotection.AbsoluteMarker + var absoluteCriteria []backuppolicies.AbsoluteMarker if absoluteCriteriaRaw := v["absolute_criteria"].(string); len(absoluteCriteriaRaw) > 0 { - absoluteCriteria = []dataprotection.AbsoluteMarker{dataprotection.AbsoluteMarker(absoluteCriteriaRaw)} + absoluteCriteria = []backuppolicies.AbsoluteMarker{backuppolicies.AbsoluteMarker(absoluteCriteriaRaw)} } - var daysOfWeek []dataprotection.DayOfWeek + var daysOfWeek []backuppolicies.DayOfWeek if v["days_of_week"].(*pluginsdk.Set).Len() > 0 { - daysOfWeek = make([]dataprotection.DayOfWeek, 0) + daysOfWeek = make([]backuppolicies.DayOfWeek, 0) for _, value := range v["days_of_week"].(*pluginsdk.Set).List() { - daysOfWeek = append(daysOfWeek, dataprotection.DayOfWeek(value.(string))) + daysOfWeek = append(daysOfWeek, backuppolicies.DayOfWeek(value.(string))) } } - var monthsOfYear []dataprotection.Month + var monthsOfYear []backuppolicies.Month if v["months_of_year"].(*pluginsdk.Set).Len() > 0 { - monthsOfYear = make([]dataprotection.Month, 0) + monthsOfYear = make([]backuppolicies.Month, 0) for _, value := range v["months_of_year"].(*pluginsdk.Set).List() { - monthsOfYear = append(monthsOfYear, dataprotection.Month(value.(string))) + monthsOfYear = append(monthsOfYear, backuppolicies.Month(value.(string))) } } - var weeksOfMonth []dataprotection.WeekNumber + var weeksOfMonth []backuppolicies.WeekNumber if v["weeks_of_month"].(*pluginsdk.Set).Len() > 0 { - weeksOfMonth = make([]dataprotection.WeekNumber, 0) + weeksOfMonth = make([]backuppolicies.WeekNumber, 0) for _, value := range v["weeks_of_month"].(*pluginsdk.Set).List() { - weeksOfMonth = append(weeksOfMonth, dataprotection.WeekNumber(value.(string))) + weeksOfMonth = append(weeksOfMonth, backuppolicies.WeekNumber(value.(string))) } } - var scheduleTimes []date.Time + var scheduleTimes *[]string if v["scheduled_backup_times"].(*pluginsdk.Set).Len() > 0 { - scheduleTimes = make([]date.Time, 0) - for _, value := range v["scheduled_backup_times"].(*pluginsdk.Set).List() { - t, _ := time.Parse(time.RFC3339, value.(string)) - scheduleTimes = append(scheduleTimes, date.Time{Time: t}) - } + scheduleTimes = utils.ExpandStringSlice(v["scheduled_backup_times"].(*pluginsdk.Set).List()) } - results = append(results, dataprotection.ScheduleBasedBackupCriteria{ + results = append(results, backuppolicies.ScheduleBasedBackupCriteria{ AbsoluteCriteria: &absoluteCriteria, DaysOfMonth: nil, DaysOfTheWeek: &daysOfWeek, MonthsOfYear: &monthsOfYear, - ScheduleTimes: &scheduleTimes, + ScheduleTimes: scheduleTimes, WeeksOfTheMonth: &weeksOfMonth, - ObjectType: dataprotection.ObjectTypeBasicBackupCriteriaObjectTypeScheduleBasedBackupCriteria, }) } - return &results + return &results, nil } -func flattenBackupPolicyPostgreSQLBackupRuleArray(input *[]dataprotection.BasicBasePolicyRule) []interface{} { +func flattenBackupPolicyPostgreSQLBackupRuleArray(input *[]backuppolicies.BasePolicyRule) []interface{} { if input == nil { return make([]interface{}, 0) } for _, item := range *input { - if backupRule, ok := item.AsAzureBackupRule(); ok { + if backupRule, ok := item.(backuppolicies.AzureBackupRule); ok { if backupRule.Trigger != nil { - if scheduleBasedTrigger, ok := backupRule.Trigger.AsScheduleBasedTriggerContext(); ok { - if scheduleBasedTrigger.Schedule != nil { - return utils.FlattenStringSlice(scheduleBasedTrigger.Schedule.RepeatingTimeIntervals) - } + if scheduleBasedTrigger, ok := backupRule.Trigger.(backuppolicies.ScheduleBasedTriggerContext); ok { + return utils.FlattenStringSlice(&scheduleBasedTrigger.Schedule.RepeatingTimeIntervals) } } } @@ -450,16 +453,16 @@ func flattenBackupPolicyPostgreSQLBackupRuleArray(input *[]dataprotection.BasicB return make([]interface{}, 0) } -func flattenBackupPolicyPostgreSQLDefaultRetentionRuleDuration(input *[]dataprotection.BasicBasePolicyRule) interface{} { +func flattenBackupPolicyPostgreSQLDefaultRetentionRuleDuration(input *[]backuppolicies.BasePolicyRule) interface{} { if input == nil { return nil } for _, item := range *input { - if retentionRule, ok := item.AsAzureRetentionRule(); ok && retentionRule.IsDefault != nil && *retentionRule.IsDefault { - if retentionRule.Lifecycles != nil && len(*retentionRule.Lifecycles) > 0 { - if deleteOption, ok := (*retentionRule.Lifecycles)[0].DeleteAfter.AsAbsoluteDeleteOption(); ok { - return *deleteOption.Duration + if retentionRule, ok := item.(backuppolicies.AzureRetentionRule); ok && retentionRule.IsDefault != nil && *retentionRule.IsDefault { + if retentionRule.Lifecycles != nil && len(retentionRule.Lifecycles) > 0 { + if deleteOption, ok := (retentionRule.Lifecycles)[0].DeleteAfter.(backuppolicies.AbsoluteDeleteOption); ok { + return deleteOption.Duration } } } @@ -467,41 +470,38 @@ func flattenBackupPolicyPostgreSQLDefaultRetentionRuleDuration(input *[]dataprot return nil } -func flattenBackupPolicyPostgreSQLRetentionRuleArray(input *[]dataprotection.BasicBasePolicyRule) []interface{} { +func flattenBackupPolicyPostgreSQLRetentionRuleArray(input *[]backuppolicies.BasePolicyRule) []interface{} { results := make([]interface{}, 0) if input == nil { return results } - var taggingCriterias []dataprotection.TaggingCriteria + var taggingCriterias []backuppolicies.TaggingCriteria for _, item := range *input { - if backupRule, ok := item.AsAzureBackupRule(); ok { - if trigger, ok := backupRule.Trigger.AsScheduleBasedTriggerContext(); ok { + if backupRule, ok := item.(backuppolicies.AzureBackupRule); ok { + if trigger, ok := backupRule.Trigger.(backuppolicies.ScheduleBasedTriggerContext); ok { if trigger.TaggingCriteria != nil { - taggingCriterias = *trigger.TaggingCriteria + taggingCriterias = trigger.TaggingCriteria } } } } for _, item := range *input { - if retentionRule, ok := item.AsAzureRetentionRule(); ok && (retentionRule.IsDefault == nil || !*retentionRule.IsDefault) { - var name string - if retentionRule.Name != nil { - name = *retentionRule.Name - } + if retentionRule, ok := item.(backuppolicies.AzureRetentionRule); ok && (retentionRule.IsDefault == nil || !*retentionRule.IsDefault) { + name := retentionRule.Name var taggingPriority int64 var taggingCriteria []interface{} for _, criteria := range taggingCriterias { - if criteria.TagInfo != nil && criteria.TagInfo.TagName != nil && strings.EqualFold(*criteria.TagInfo.TagName, name) { - taggingPriority = *criteria.TaggingPriority + if strings.EqualFold(criteria.TagInfo.TagName, name) { + taggingPriority = criteria.TaggingPriority taggingCriteria = flattenBackupPolicyPostgreSQLBackupCriteriaArray(criteria.Criteria) } } var duration string - if retentionRule.Lifecycles != nil && len(*retentionRule.Lifecycles) > 0 { - if deleteOption, ok := (*retentionRule.Lifecycles)[0].DeleteAfter.AsAbsoluteDeleteOption(); ok { - duration = *deleteOption.Duration + if retentionRule.Lifecycles != nil && len(retentionRule.Lifecycles) > 0 { + if deleteOption, ok := (retentionRule.Lifecycles)[0].DeleteAfter.(backuppolicies.AbsoluteDeleteOption); ok { + duration = deleteOption.Duration } } results = append(results, map[string]interface{}{ @@ -515,14 +515,14 @@ func flattenBackupPolicyPostgreSQLRetentionRuleArray(input *[]dataprotection.Bas return results } -func flattenBackupPolicyPostgreSQLBackupCriteriaArray(input *[]dataprotection.BasicBackupCriteria) []interface{} { +func flattenBackupPolicyPostgreSQLBackupCriteriaArray(input *[]backuppolicies.BackupCriteria) []interface{} { results := make([]interface{}, 0) if input == nil { return results } for _, item := range *input { - if criteria, ok := item.AsScheduleBasedBackupCriteria(); ok { + if criteria, ok := item.(backuppolicies.ScheduleBasedBackupCriteria); ok { var absoluteCriteria string if criteria.AbsoluteCriteria != nil && len(*criteria.AbsoluteCriteria) > 0 { absoluteCriteria = string((*criteria.AbsoluteCriteria)[0]) @@ -552,7 +552,7 @@ func flattenBackupPolicyPostgreSQLBackupCriteriaArray(input *[]dataprotection.Ba if criteria.ScheduleTimes != nil { scheduleTimes = make([]string, 0) for _, item := range *criteria.ScheduleTimes { - scheduleTimes = append(scheduleTimes, item.String()) + scheduleTimes = append(scheduleTimes, item) } } diff --git a/internal/services/dataprotection/data_protection_backup_policy_postgresql_resource_test.go b/internal/services/dataprotection/data_protection_backup_policy_postgresql_resource_test.go index be3f79289d2d..8a4423757c44 100644 --- a/internal/services/dataprotection/data_protection_backup_policy_postgresql_resource_test.go +++ b/internal/services/dataprotection/data_protection_backup_policy_postgresql_resource_test.go @@ -5,10 +5,11 @@ import ( "fmt" "testing" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backuppolicies" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dataprotection/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -86,13 +87,13 @@ func TestAccDataProtectionBackupPolicyPostgreSQL_update(t *testing.T) { } func (r DataProtectionBackupPolicyPostgreSQLResource) Exists(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.BackupPolicyID(state.ID) + id, err := backuppolicies.ParseBackupPoliciesID(state.ID) if err != nil { return nil, err } - resp, err := client.DataProtection.BackupPolicyClient.Get(ctx, id.BackupVaultName, id.ResourceGroup, id.Name) + resp, err := client.DataProtection.BackupPolicyClient.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { return utils.Bool(false), nil } return nil, fmt.Errorf("retrieving DataProtection BackupPolicy (%q): %+v", id, err) diff --git a/internal/services/dataprotection/data_protection_backup_vault_data_source.go b/internal/services/dataprotection/data_protection_backup_vault_data_source.go index 9efe7a7a14b2..e64b9b9d848f 100644 --- a/internal/services/dataprotection/data_protection_backup_vault_data_source.go +++ b/internal/services/dataprotection/data_protection_backup_vault_data_source.go @@ -6,17 +6,16 @@ import ( "regexp" "time" + "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/identity" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupvaults" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dataprotection/legacysdk/dataprotection" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dataprotection/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" - "github.com/hashicorp/terraform-provider-azurerm/utils" ) func dataSourceDataProtectionBackupVault() *pluginsdk.Resource { @@ -28,7 +27,7 @@ func dataSourceDataProtectionBackupVault() *pluginsdk.Resource { }, Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - _, err := parse.BackupVaultID(id) + _, err := backupvaults.ParseBackupVaultID(id) return err }), @@ -72,11 +71,11 @@ func dataSourceDataProtectionBackupVaultRead(d *pluginsdk.ResourceData, meta int name := d.Get("name").(string) resourceGroup := d.Get("resource_group_name").(string) - id := parse.NewBackupVaultID(subscriptionId, resourceGroup, name) + id := backupvaults.NewBackupVaultID(subscriptionId, resourceGroup, name) - resp, err := client.Get(ctx, id.Name, id.ResourceGroup) + resp, err := client.Get(ctx, id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { log.Printf("[INFO] DataProtection BackupVault %q does not exist - removing from state", d.Id()) d.SetId("") return nil @@ -85,32 +84,40 @@ func dataSourceDataProtectionBackupVaultRead(d *pluginsdk.ResourceData, meta int } d.SetId(id.ID()) - d.Set("name", id.Name) - d.Set("resource_group_name", id.ResourceGroup) - d.Set("location", location.NormalizeNilable(resp.Location)) - if props := resp.Properties; props != nil { - if props.StorageSettings != nil && len(*props.StorageSettings) > 0 { - d.Set("datastore_type", (*props.StorageSettings)[0].DatastoreType) - d.Set("redundancy", (*props.StorageSettings)[0].Type) + d.Set("name", id.VaultName) + d.Set("resource_group_name", id.ResourceGroupName) + + if model := resp.Model; model != nil { + d.Set("location", location.NormalizeNilable(&model.Location)) + + props := model.Properties + if props.StorageSettings != nil && len(props.StorageSettings) > 0 { + d.Set("datastore_type", (props.StorageSettings)[0].DatastoreType) + d.Set("redundancy", (props.StorageSettings)[0].Type) + } + + if err = d.Set("identity", dataSourceFlattenBackupVaultDppIdentityDetails(model.Identity)); err != nil { + return fmt.Errorf("setting `identity`: %+v", err) + } + + if err = tags.FlattenAndSet(d, flattenTags(model.Tags)); err != nil { + return err } } - if err := d.Set("identity", dataSourceFlattenBackupVaultDppIdentityDetails(resp.Identity)); err != nil { - return fmt.Errorf("setting `identity`: %+v", err) - } - return tags.FlattenAndSet(d, resp.Tags) + return nil } -func dataSourceFlattenBackupVaultDppIdentityDetails(input *dataprotection.DppIdentityDetails) []interface{} { +func dataSourceFlattenBackupVaultDppIdentityDetails(input *backupvaults.DppIdentityDetails) []interface{} { var config *identity.SystemAssigned if input != nil { principalId := "" - if input.PrincipalID != nil { - principalId = *input.PrincipalID + if input.PrincipalId != nil { + principalId = *input.PrincipalId } tenantId := "" - if input.TenantID != nil { - tenantId = *input.TenantID + if input.TenantId != nil { + tenantId = *input.TenantId } config = &identity.SystemAssigned{ Type: identity.Type(*input.Type), diff --git a/internal/services/dataprotection/data_protection_backup_vault_data_source_test.go b/internal/services/dataprotection/data_protection_backup_vault_data_source_test.go index de7e0d635861..9fd27450053d 100644 --- a/internal/services/dataprotection/data_protection_backup_vault_data_source_test.go +++ b/internal/services/dataprotection/data_protection_backup_vault_data_source_test.go @@ -5,10 +5,11 @@ import ( "fmt" "testing" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupvaults" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dataprotection/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -36,13 +37,13 @@ func TestAccDataProtectionBackupVaultDataSource_complete(t *testing.T) { } func (r DataProtectionBackupVaultDataSource) Exists(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.BackupVaultID(state.ID) + id, err := backupvaults.ParseBackupVaultID(state.ID) if err != nil { return nil, err } - resp, err := client.DataProtection.BackupVaultClient.Get(ctx, id.Name, id.ResourceGroup) + resp, err := client.DataProtection.BackupVaultClient.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { return utils.Bool(false), nil } return nil, fmt.Errorf("retrieving DataProtection BackupVault (%q): %+v", id, err) diff --git a/internal/services/dataprotection/data_protection_backup_vault_resource.go b/internal/services/dataprotection/data_protection_backup_vault_resource.go index 67e5be458aac..96dfc7f637a1 100644 --- a/internal/services/dataprotection/data_protection_backup_vault_resource.go +++ b/internal/services/dataprotection/data_protection_backup_vault_resource.go @@ -6,14 +6,14 @@ import ( "regexp" "time" + "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/identity" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupvaults" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dataprotection/legacysdk/dataprotection" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dataprotection/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" @@ -36,7 +36,7 @@ func resourceDataProtectionBackupVault() *pluginsdk.Resource { }, Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - _, err := parse.BackupVaultID(id) + _, err := backupvaults.ParseBackupVaultIDInsensitively(id) return err }), @@ -60,9 +60,9 @@ func resourceDataProtectionBackupVault() *pluginsdk.Resource { Required: true, ForceNew: true, ValidateFunc: validation.StringInSlice([]string{ - string(dataprotection.StorageSettingStoreTypesArchiveStore), - string(dataprotection.StorageSettingStoreTypesSnapshotStore), - string(dataprotection.StorageSettingStoreTypesVaultStore), + string(backupvaults.StorageSettingStoreTypesArchiveStore), + string(backupvaults.StorageSettingStoreTypesSnapshotStore), + string(backupvaults.StorageSettingStoreTypesVaultStore), }, false), }, @@ -71,8 +71,8 @@ func resourceDataProtectionBackupVault() *pluginsdk.Resource { Required: true, ForceNew: true, ValidateFunc: validation.StringInSlice([]string{ - string(dataprotection.StorageSettingTypesGeoRedundant), - string(dataprotection.StorageSettingTypesLocallyRedundant), + string(backupvaults.StorageSettingTypesGeoRedundant), + string(backupvaults.StorageSettingTypesLocallyRedundant), }, false), }, @@ -92,16 +92,16 @@ func resourceDataProtectionBackupVaultCreateUpdate(d *pluginsdk.ResourceData, me name := d.Get("name").(string) resourceGroup := d.Get("resource_group_name").(string) - id := parse.NewBackupVaultID(subscriptionId, resourceGroup, name) + id := backupvaults.NewBackupVaultID(subscriptionId, resourceGroup, name) if d.IsNewResource() { - existing, err := client.Get(ctx, id.Name, id.ResourceGroup) + existing, err := client.Get(ctx, id) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return fmt.Errorf("checking for existing DataProtection BackupVault (%q): %+v", id, err) } } - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return tf.ImportAsExistsError("azurerm_data_protection_backup_vault", id.ID()) } } @@ -111,28 +111,27 @@ func resourceDataProtectionBackupVaultCreateUpdate(d *pluginsdk.ResourceData, me return fmt.Errorf("expanding `identity`: %+v", err) } - parameters := dataprotection.BackupVaultResource{ - Location: utils.String(location.Normalize(d.Get("location").(string))), - Properties: &dataprotection.BackupVault{ - StorageSettings: &[]dataprotection.StorageSetting{ + datastoreType := backupvaults.StorageSettingStoreTypes(d.Get("datastore_type").(string)) + storageSettingType := backupvaults.StorageSettingTypes(d.Get("redundancy").(string)) + + parameters := backupvaults.BackupVaultResource{ + Location: location.Normalize(d.Get("location").(string)), + Properties: backupvaults.BackupVault{ + StorageSettings: []backupvaults.StorageSetting{ { - DatastoreType: dataprotection.StorageSettingStoreTypes(d.Get("datastore_type").(string)), - Type: dataprotection.StorageSettingTypes(d.Get("redundancy").(string)), + DatastoreType: &datastoreType, + Type: &storageSettingType, }, }, }, Identity: expandedIdentity, - Tags: tags.Expand(d.Get("tags").(map[string]interface{})), + Tags: expandTags(d.Get("tags").(map[string]interface{})), } - future, err := client.CreateOrUpdate(ctx, id.Name, id.ResourceGroup, parameters) + err = client.CreateOrUpdateThenPoll(ctx, id, parameters) if err != nil { return fmt.Errorf("creating DataProtection BackupVault (%q): %+v", id, err) } - if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for creation of the DataProtection BackupVault (%q): %+v", id, err) - } - d.SetId(id.ID()) return resourceDataProtectionBackupVaultRead(d, meta) } @@ -142,33 +141,40 @@ func resourceDataProtectionBackupVaultRead(d *pluginsdk.ResourceData, meta inter ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.BackupVaultID(d.Id()) + id, err := backupvaults.ParseBackupVaultID(d.Id()) if err != nil { return err } - resp, err := client.Get(ctx, id.Name, id.ResourceGroup) + resp, err := client.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { log.Printf("[INFO] DataProtection BackupVault %q does not exist - removing from state", d.Id()) d.SetId("") return nil } return fmt.Errorf("retrieving DataProtection BackupVault (%q): %+v", id, err) } - d.Set("name", id.Name) - d.Set("resource_group_name", id.ResourceGroup) - d.Set("location", location.NormalizeNilable(resp.Location)) - if props := resp.Properties; props != nil { - if props.StorageSettings != nil && len(*props.StorageSettings) > 0 { - d.Set("datastore_type", (*props.StorageSettings)[0].DatastoreType) - d.Set("redundancy", (*props.StorageSettings)[0].Type) + d.Set("name", id.VaultName) + d.Set("resource_group_name", id.ResourceGroupName) + + if model := resp.Model; model != nil { + d.Set("location", location.NormalizeNilable(&model.Location)) + props := model.Properties + if props.StorageSettings != nil && len(props.StorageSettings) > 0 { + d.Set("datastore_type", (props.StorageSettings)[0].DatastoreType) + d.Set("redundancy", (props.StorageSettings)[0].Type) + } + + if err = d.Set("identity", flattenBackupVaultDppIdentityDetails(model.Identity)); err != nil { + return fmt.Errorf("setting `identity`: %+v", err) + } + if err = tags.FlattenAndSet(d, flattenTags(model.Tags)); err != nil { + return err } } - if err := d.Set("identity", flattenBackupVaultDppIdentityDetails(resp.Identity)); err != nil { - return fmt.Errorf("setting `identity`: %+v", err) - } - return tags.FlattenAndSet(d, resp.Tags) + + return nil } func resourceDataProtectionBackupVaultDelete(d *pluginsdk.ResourceData, meta interface{}) error { @@ -176,13 +182,13 @@ func resourceDataProtectionBackupVaultDelete(d *pluginsdk.ResourceData, meta int ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.BackupVaultID(d.Id()) + id, err := backupvaults.ParseBackupVaultID(d.Id()) if err != nil { return err } - if resp, err := client.Delete(ctx, id.Name, id.ResourceGroup); err != nil { - if utils.ResponseWasNotFound(resp) { + if resp, err := client.Delete(ctx, *id); err != nil { + if response.WasNotFound(resp.HttpResponse) { return nil } return fmt.Errorf("deleting DataProtection BackupVault (%q): %+v", id, err) @@ -190,28 +196,28 @@ func resourceDataProtectionBackupVaultDelete(d *pluginsdk.ResourceData, meta int return nil } -func expandBackupVaultDppIdentityDetails(input []interface{}) (*dataprotection.DppIdentityDetails, error) { +func expandBackupVaultDppIdentityDetails(input []interface{}) (*backupvaults.DppIdentityDetails, error) { config, err := identity.ExpandSystemAssigned(input) if err != nil { return nil, err } - return &dataprotection.DppIdentityDetails{ + return &backupvaults.DppIdentityDetails{ Type: utils.String(string(config.Type)), }, nil } -func flattenBackupVaultDppIdentityDetails(input *dataprotection.DppIdentityDetails) []interface{} { +func flattenBackupVaultDppIdentityDetails(input *backupvaults.DppIdentityDetails) []interface{} { var config *identity.SystemAssigned if input != nil { principalId := "" - if input.PrincipalID != nil { - principalId = *input.PrincipalID + if input.PrincipalId != nil { + principalId = *input.PrincipalId } tenantId := "" - if input.TenantID != nil { - tenantId = *input.TenantID + if input.TenantId != nil { + tenantId = *input.TenantId } config = &identity.SystemAssigned{ Type: identity.Type(*input.Type), diff --git a/internal/services/dataprotection/data_protection_backup_vault_resource_test.go b/internal/services/dataprotection/data_protection_backup_vault_resource_test.go index 19688e1e7706..dcc57f542838 100644 --- a/internal/services/dataprotection/data_protection_backup_vault_resource_test.go +++ b/internal/services/dataprotection/data_protection_backup_vault_resource_test.go @@ -5,10 +5,11 @@ import ( "fmt" "testing" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/dataprotection/2022-04-01/backupvaults" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dataprotection/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -111,13 +112,13 @@ func TestAccDataProtectionBackupVault_updateIdentity(t *testing.T) { } func (r DataProtectionBackupVaultResource) Exists(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.BackupVaultID(state.ID) + id, err := backupvaults.ParseBackupVaultID(state.ID) if err != nil { return nil, err } - resp, err := client.DataProtection.BackupVaultClient.Get(ctx, id.Name, id.ResourceGroup) + resp, err := client.DataProtection.BackupVaultClient.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { return utils.Bool(false), nil } return nil, fmt.Errorf("retrieving DataProtection BackupVault (%q): %+v", id, err) diff --git a/internal/services/dataprotection/legacysdk/dataprotection/backupinstances.go b/internal/services/dataprotection/legacysdk/dataprotection/backupinstances.go deleted file mode 100644 index 20d27ac0997d..000000000000 --- a/internal/services/dataprotection/legacysdk/dataprotection/backupinstances.go +++ /dev/null @@ -1,927 +0,0 @@ -package dataprotection - -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. -// -// Code generated by Microsoft (R) AutoRest Code Generator. -// Changes may cause incorrect behavior and will be lost if the code is regenerated. - -import ( - "context" - "net/http" - - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/azure" - "github.com/Azure/go-autorest/autorest/validation" - "github.com/Azure/go-autorest/tracing" -) - -// BackupInstancesClient is the open API 2.0 Specs for Azure Data Protection service -type BackupInstancesClient struct { - BaseClient -} - -// NewBackupInstancesClient creates an instance of the BackupInstancesClient client. -func NewBackupInstancesClient(subscriptionID string) BackupInstancesClient { - return NewBackupInstancesClientWithBaseURI(DefaultBaseURI, subscriptionID) -} - -// NewBackupInstancesClientWithBaseURI creates an instance of the BackupInstancesClient client using a custom endpoint. -// Use this when interacting with an Azure cloud that uses a non-standard base URI (sovereign clouds, Azure stack). -func NewBackupInstancesClientWithBaseURI(baseURI string, subscriptionID string) BackupInstancesClient { - return BackupInstancesClient{NewWithBaseURI(baseURI, subscriptionID)} -} - -// AdhocBackup trigger adhoc backup -// Parameters: -// vaultName - the name of the backup vault. -// resourceGroupName - the name of the resource group where the backup vault is present. -// backupInstanceName - the name of the backup instance -// parameters - request body for operation -func (client BackupInstancesClient) AdhocBackup(ctx context.Context, vaultName string, resourceGroupName string, backupInstanceName string, parameters TriggerBackupRequest) (result BackupInstancesAdhocBackupFuture, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/BackupInstancesClient.AdhocBackup") - defer func() { - sc := -1 - if result.FutureAPI != nil && result.FutureAPI.Response() != nil { - sc = result.FutureAPI.Response().StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - if err := validation.Validate([]validation.Validation{ - { - TargetValue: parameters, - Constraints: []validation.Constraint{{ - Target: "parameters.BackupRuleOptions", Name: validation.Null, Rule: true, - Chain: []validation.Constraint{ - {Target: "parameters.BackupRuleOptions.RuleName", Name: validation.Null, Rule: true, Chain: nil}, - {Target: "parameters.BackupRuleOptions.TriggerOption", Name: validation.Null, Rule: true, Chain: nil}, - }, - }}, - }, - }); err != nil { - return result, validation.NewError("dataprotection.BackupInstancesClient", "AdhocBackup", err.Error()) - } - - req, err := client.AdhocBackupPreparer(ctx, vaultName, resourceGroupName, backupInstanceName, parameters) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupInstancesClient", "AdhocBackup", nil, "Failure preparing request") - return - } - - result, err = client.AdhocBackupSender(req) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupInstancesClient", "AdhocBackup", nil, "Failure sending request") - return - } - - return -} - -// AdhocBackupPreparer prepares the AdhocBackup request. -func (client BackupInstancesClient) AdhocBackupPreparer(ctx context.Context, vaultName string, resourceGroupName string, backupInstanceName string, parameters TriggerBackupRequest) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "backupInstanceName": autorest.Encode("path", backupInstanceName), - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - "vaultName": autorest.Encode("path", vaultName), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsContentType("application/json; charset=utf-8"), - autorest.AsPost(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/backupVaults/{vaultName}/backupInstances/{backupInstanceName}/backup", pathParameters), - autorest.WithJSON(parameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// AdhocBackupSender sends the AdhocBackup request. The method will close the -// http.Response Body if it receives an error. -func (client BackupInstancesClient) AdhocBackupSender(req *http.Request) (future BackupInstancesAdhocBackupFuture, err error) { - var resp *http.Response - resp, err = client.Send(req, azure.DoRetryWithRegistration(client.Client)) - if err != nil { - return - } - var azf azure.Future - azf, err = azure.NewFutureFromResponse(resp) - future.FutureAPI = &azf - future.Result = future.result - return -} - -// AdhocBackupResponder handles the response to the AdhocBackup request. The method always -// closes the http.Response Body. -func (client BackupInstancesClient) AdhocBackupResponder(resp *http.Response) (result OperationJobExtendedInfo, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusAccepted), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// CreateOrUpdate create or update a backup instance in a backup vault -// Parameters: -// vaultName - the name of the backup vault. -// resourceGroupName - the name of the resource group where the backup vault is present. -// backupInstanceName - the name of the backup instance -// parameters - request body for operation -func (client BackupInstancesClient) CreateOrUpdate(ctx context.Context, vaultName string, resourceGroupName string, backupInstanceName string, parameters BackupInstanceResource) (result BackupInstancesCreateOrUpdateFuture, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/BackupInstancesClient.CreateOrUpdate") - defer func() { - sc := -1 - if result.FutureAPI != nil && result.FutureAPI.Response() != nil { - sc = result.FutureAPI.Response().StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - if err := validation.Validate([]validation.Validation{ - { - TargetValue: parameters, - Constraints: []validation.Constraint{{ - Target: "parameters.Properties", Name: validation.Null, Rule: false, - Chain: []validation.Constraint{ - { - Target: "parameters.Properties.DataSourceInfo", Name: validation.Null, Rule: true, - Chain: []validation.Constraint{{Target: "parameters.Properties.DataSourceInfo.ResourceID", Name: validation.Null, Rule: true, Chain: nil}}, - }, - { - Target: "parameters.Properties.DataSourceSetInfo", Name: validation.Null, Rule: false, - Chain: []validation.Constraint{{Target: "parameters.Properties.DataSourceSetInfo.ResourceID", Name: validation.Null, Rule: true, Chain: nil}}, - }, - { - Target: "parameters.Properties.PolicyInfo", Name: validation.Null, Rule: true, - Chain: []validation.Constraint{{Target: "parameters.Properties.PolicyInfo.PolicyID", Name: validation.Null, Rule: true, Chain: nil}}, - }, - { - Target: "parameters.Properties.ProtectionStatus", Name: validation.Null, Rule: false, - Chain: []validation.Constraint{ - { - Target: "parameters.Properties.ProtectionStatus.ErrorDetails", Name: validation.Null, Rule: false, - Chain: []validation.Constraint{ - { - Target: "parameters.Properties.ProtectionStatus.ErrorDetails.InnerError", Name: validation.Null, Rule: false, - Chain: []validation.Constraint{{Target: "parameters.Properties.ProtectionStatus.ErrorDetails.InnerError.EmbeddedInnerError", Name: validation.Null, Rule: false, Chain: nil}}, - }, - }, - }, - }, - }, - { - Target: "parameters.Properties.ProtectionErrorDetails", Name: validation.Null, Rule: false, - Chain: []validation.Constraint{ - { - Target: "parameters.Properties.ProtectionErrorDetails.InnerError", Name: validation.Null, Rule: false, - Chain: []validation.Constraint{{Target: "parameters.Properties.ProtectionErrorDetails.InnerError.EmbeddedInnerError", Name: validation.Null, Rule: false, Chain: nil}}, - }, - }, - }, - {Target: "parameters.Properties.ObjectType", Name: validation.Null, Rule: true, Chain: nil}, - }, - }}, - }, - }); err != nil { - return result, validation.NewError("dataprotection.BackupInstancesClient", "CreateOrUpdate", err.Error()) - } - - req, err := client.CreateOrUpdatePreparer(ctx, vaultName, resourceGroupName, backupInstanceName, parameters) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupInstancesClient", "CreateOrUpdate", nil, "Failure preparing request") - return - } - - result, err = client.CreateOrUpdateSender(req) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupInstancesClient", "CreateOrUpdate", nil, "Failure sending request") - return - } - - return -} - -// CreateOrUpdatePreparer prepares the CreateOrUpdate request. -func (client BackupInstancesClient) CreateOrUpdatePreparer(ctx context.Context, vaultName string, resourceGroupName string, backupInstanceName string, parameters BackupInstanceResource) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "backupInstanceName": autorest.Encode("path", backupInstanceName), - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - "vaultName": autorest.Encode("path", vaultName), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsContentType("application/json; charset=utf-8"), - autorest.AsPut(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/backupVaults/{vaultName}/backupInstances/{backupInstanceName}", pathParameters), - autorest.WithJSON(parameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// CreateOrUpdateSender sends the CreateOrUpdate request. The method will close the -// http.Response Body if it receives an error. -func (client BackupInstancesClient) CreateOrUpdateSender(req *http.Request) (future BackupInstancesCreateOrUpdateFuture, err error) { - var resp *http.Response - resp, err = client.Send(req, azure.DoRetryWithRegistration(client.Client)) - if err != nil { - return - } - var azf azure.Future - azf, err = azure.NewFutureFromResponse(resp) - future.FutureAPI = &azf - future.Result = future.result - return -} - -// CreateOrUpdateResponder handles the response to the CreateOrUpdate request. The method always -// closes the http.Response Body. -func (client BackupInstancesClient) CreateOrUpdateResponder(resp *http.Response) (result BackupInstanceResource, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusCreated), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// Delete delete a backup instance in a backup vault -// Parameters: -// vaultName - the name of the backup vault. -// resourceGroupName - the name of the resource group where the backup vault is present. -// backupInstanceName - the name of the backup instance -func (client BackupInstancesClient) Delete(ctx context.Context, vaultName string, resourceGroupName string, backupInstanceName string) (result BackupInstancesDeleteFuture, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/BackupInstancesClient.Delete") - defer func() { - sc := -1 - if result.FutureAPI != nil && result.FutureAPI.Response() != nil { - sc = result.FutureAPI.Response().StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - req, err := client.DeletePreparer(ctx, vaultName, resourceGroupName, backupInstanceName) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupInstancesClient", "Delete", nil, "Failure preparing request") - return - } - - result, err = client.DeleteSender(req) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupInstancesClient", "Delete", nil, "Failure sending request") - return - } - - return -} - -// DeletePreparer prepares the Delete request. -func (client BackupInstancesClient) DeletePreparer(ctx context.Context, vaultName string, resourceGroupName string, backupInstanceName string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "backupInstanceName": autorest.Encode("path", backupInstanceName), - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - "vaultName": autorest.Encode("path", vaultName), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsDelete(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/backupVaults/{vaultName}/backupInstances/{backupInstanceName}", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// DeleteSender sends the Delete request. The method will close the -// http.Response Body if it receives an error. -func (client BackupInstancesClient) DeleteSender(req *http.Request) (future BackupInstancesDeleteFuture, err error) { - var resp *http.Response - resp, err = client.Send(req, azure.DoRetryWithRegistration(client.Client)) - if err != nil { - return - } - var azf azure.Future - azf, err = azure.NewFutureFromResponse(resp) - future.FutureAPI = &azf - future.Result = future.result - return -} - -// DeleteResponder handles the response to the Delete request. The method always -// closes the http.Response Body. -func (client BackupInstancesClient) DeleteResponder(resp *http.Response) (result autorest.Response, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusAccepted, http.StatusNoContent), - autorest.ByClosing()) - result.Response = resp - return -} - -// Get gets a backup instance with name in a backup vault -// Parameters: -// vaultName - the name of the backup vault. -// resourceGroupName - the name of the resource group where the backup vault is present. -// backupInstanceName - the name of the backup instance -func (client BackupInstancesClient) Get(ctx context.Context, vaultName string, resourceGroupName string, backupInstanceName string) (result BackupInstanceResource, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/BackupInstancesClient.Get") - defer func() { - sc := -1 - if result.Response.Response != nil { - sc = result.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - req, err := client.GetPreparer(ctx, vaultName, resourceGroupName, backupInstanceName) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupInstancesClient", "Get", nil, "Failure preparing request") - return - } - - resp, err := client.GetSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.BackupInstancesClient", "Get", resp, "Failure sending request") - return - } - - result, err = client.GetResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupInstancesClient", "Get", resp, "Failure responding to request") - return - } - - return -} - -// GetPreparer prepares the Get request. -func (client BackupInstancesClient) GetPreparer(ctx context.Context, vaultName string, resourceGroupName string, backupInstanceName string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "backupInstanceName": autorest.Encode("path", backupInstanceName), - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - "vaultName": autorest.Encode("path", vaultName), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsGet(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/backupVaults/{vaultName}/backupInstances/{backupInstanceName}", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// GetSender sends the Get request. The method will close the -// http.Response Body if it receives an error. -func (client BackupInstancesClient) GetSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// GetResponder handles the response to the Get request. The method always -// closes the http.Response Body. -func (client BackupInstancesClient) GetResponder(resp *http.Response) (result BackupInstanceResource, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// List gets a backup instances belonging to a backup vault -// Parameters: -// vaultName - the name of the backup vault. -// resourceGroupName - the name of the resource group where the backup vault is present. -func (client BackupInstancesClient) List(ctx context.Context, vaultName string, resourceGroupName string) (result BackupInstanceResourceListPage, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/BackupInstancesClient.List") - defer func() { - sc := -1 - if result.birl.Response.Response != nil { - sc = result.birl.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - result.fn = client.listNextResults - req, err := client.ListPreparer(ctx, vaultName, resourceGroupName) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupInstancesClient", "List", nil, "Failure preparing request") - return - } - - resp, err := client.ListSender(req) - if err != nil { - result.birl.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.BackupInstancesClient", "List", resp, "Failure sending request") - return - } - - result.birl, err = client.ListResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupInstancesClient", "List", resp, "Failure responding to request") - return - } - if result.birl.hasNextLink() && result.birl.IsEmpty() { - err = result.NextWithContext(ctx) - return - } - - return -} - -// ListPreparer prepares the List request. -func (client BackupInstancesClient) ListPreparer(ctx context.Context, vaultName string, resourceGroupName string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - "vaultName": autorest.Encode("path", vaultName), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsGet(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/backupVaults/{vaultName}/backupInstances", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// ListSender sends the List request. The method will close the -// http.Response Body if it receives an error. -func (client BackupInstancesClient) ListSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// ListResponder handles the response to the List request. The method always -// closes the http.Response Body. -func (client BackupInstancesClient) ListResponder(resp *http.Response) (result BackupInstanceResourceList, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// listNextResults retrieves the next set of results, if any. -func (client BackupInstancesClient) listNextResults(ctx context.Context, lastResults BackupInstanceResourceList) (result BackupInstanceResourceList, err error) { - req, err := lastResults.backupInstanceResourceListPreparer(ctx) - if err != nil { - return result, autorest.NewErrorWithError(err, "dataprotection.BackupInstancesClient", "listNextResults", nil, "Failure preparing next results request") - } - if req == nil { - return - } - resp, err := client.ListSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - return result, autorest.NewErrorWithError(err, "dataprotection.BackupInstancesClient", "listNextResults", resp, "Failure sending next results request") - } - result, err = client.ListResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupInstancesClient", "listNextResults", resp, "Failure responding to next results request") - } - return -} - -// ListComplete enumerates all values, automatically crossing page boundaries as required. -func (client BackupInstancesClient) ListComplete(ctx context.Context, vaultName string, resourceGroupName string) (result BackupInstanceResourceListIterator, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/BackupInstancesClient.List") - defer func() { - sc := -1 - if result.Response().Response.Response != nil { - sc = result.page.Response().Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - result.page, err = client.List(ctx, vaultName, resourceGroupName) - return -} - -// TriggerRehydrate rehydrate recovery point for restore for a BackupInstance -// Parameters: -// resourceGroupName - the name of the resource group where the backup vault is present. -// vaultName - the name of the backup vault. -// parameters - request body for operation -func (client BackupInstancesClient) TriggerRehydrate(ctx context.Context, resourceGroupName string, vaultName string, parameters AzureBackupRehydrationRequest, backupInstanceName string) (result BackupInstancesTriggerRehydrateFuture, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/BackupInstancesClient.TriggerRehydrate") - defer func() { - sc := -1 - if result.FutureAPI != nil && result.FutureAPI.Response() != nil { - sc = result.FutureAPI.Response().StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - if err := validation.Validate([]validation.Validation{ - { - TargetValue: parameters, - Constraints: []validation.Constraint{ - {Target: "parameters.RecoveryPointID", Name: validation.Null, Rule: true, Chain: nil}, - {Target: "parameters.RehydrationRetentionDuration", Name: validation.Null, Rule: true, Chain: nil}, - }, - }, - }); err != nil { - return result, validation.NewError("dataprotection.BackupInstancesClient", "TriggerRehydrate", err.Error()) - } - - req, err := client.TriggerRehydratePreparer(ctx, resourceGroupName, vaultName, parameters, backupInstanceName) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupInstancesClient", "TriggerRehydrate", nil, "Failure preparing request") - return - } - - result, err = client.TriggerRehydrateSender(req) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupInstancesClient", "TriggerRehydrate", nil, "Failure sending request") - return - } - - return -} - -// TriggerRehydratePreparer prepares the TriggerRehydrate request. -func (client BackupInstancesClient) TriggerRehydratePreparer(ctx context.Context, resourceGroupName string, vaultName string, parameters AzureBackupRehydrationRequest, backupInstanceName string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "backupInstanceName": autorest.Encode("path", backupInstanceName), - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - "vaultName": autorest.Encode("path", vaultName), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsContentType("application/json; charset=utf-8"), - autorest.AsPost(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/backupVaults/{vaultName}/backupInstances/{backupInstanceName}/rehydrate", pathParameters), - autorest.WithJSON(parameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// TriggerRehydrateSender sends the TriggerRehydrate request. The method will close the -// http.Response Body if it receives an error. -func (client BackupInstancesClient) TriggerRehydrateSender(req *http.Request) (future BackupInstancesTriggerRehydrateFuture, err error) { - var resp *http.Response - resp, err = client.Send(req, azure.DoRetryWithRegistration(client.Client)) - if err != nil { - return - } - var azf azure.Future - azf, err = azure.NewFutureFromResponse(resp) - future.FutureAPI = &azf - future.Result = future.result - return -} - -// TriggerRehydrateResponder handles the response to the TriggerRehydrate request. The method always -// closes the http.Response Body. -func (client BackupInstancesClient) TriggerRehydrateResponder(resp *http.Response) (result autorest.Response, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusAccepted, http.StatusNoContent), - autorest.ByClosing()) - result.Response = resp - return -} - -// TriggerRestore triggers restore for a BackupInstance -// Parameters: -// vaultName - the name of the backup vault. -// resourceGroupName - the name of the resource group where the backup vault is present. -// backupInstanceName - the name of the backup instance -// parameters - request body for operation -func (client BackupInstancesClient) TriggerRestore(ctx context.Context, vaultName string, resourceGroupName string, backupInstanceName string, parameters BasicAzureBackupRestoreRequest) (result BackupInstancesTriggerRestoreFuture, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/BackupInstancesClient.TriggerRestore") - defer func() { - sc := -1 - if result.FutureAPI != nil && result.FutureAPI.Response() != nil { - sc = result.FutureAPI.Response().StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - req, err := client.TriggerRestorePreparer(ctx, vaultName, resourceGroupName, backupInstanceName, parameters) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupInstancesClient", "TriggerRestore", nil, "Failure preparing request") - return - } - - result, err = client.TriggerRestoreSender(req) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupInstancesClient", "TriggerRestore", nil, "Failure sending request") - return - } - - return -} - -// TriggerRestorePreparer prepares the TriggerRestore request. -func (client BackupInstancesClient) TriggerRestorePreparer(ctx context.Context, vaultName string, resourceGroupName string, backupInstanceName string, parameters BasicAzureBackupRestoreRequest) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "backupInstanceName": autorest.Encode("path", backupInstanceName), - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - "vaultName": autorest.Encode("path", vaultName), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsContentType("application/json; charset=utf-8"), - autorest.AsPost(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/backupVaults/{vaultName}/backupInstances/{backupInstanceName}/restore", pathParameters), - autorest.WithJSON(parameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// TriggerRestoreSender sends the TriggerRestore request. The method will close the -// http.Response Body if it receives an error. -func (client BackupInstancesClient) TriggerRestoreSender(req *http.Request) (future BackupInstancesTriggerRestoreFuture, err error) { - var resp *http.Response - resp, err = client.Send(req, azure.DoRetryWithRegistration(client.Client)) - if err != nil { - return - } - var azf azure.Future - azf, err = azure.NewFutureFromResponse(resp) - future.FutureAPI = &azf - future.Result = future.result - return -} - -// TriggerRestoreResponder handles the response to the TriggerRestore request. The method always -// closes the http.Response Body. -func (client BackupInstancesClient) TriggerRestoreResponder(resp *http.Response) (result OperationJobExtendedInfo, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusAccepted), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// ValidateForBackup validate whether adhoc backup will be successful or not -// Parameters: -// vaultName - the name of the backup vault. -// resourceGroupName - the name of the resource group where the backup vault is present. -// parameters - request body for operation -func (client BackupInstancesClient) ValidateForBackup(ctx context.Context, vaultName string, resourceGroupName string, parameters ValidateForBackupRequest) (result BackupInstancesValidateForBackupFuture, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/BackupInstancesClient.ValidateForBackup") - defer func() { - sc := -1 - if result.FutureAPI != nil && result.FutureAPI.Response() != nil { - sc = result.FutureAPI.Response().StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - if err := validation.Validate([]validation.Validation{ - { - TargetValue: parameters, - Constraints: []validation.Constraint{{ - Target: "parameters.BackupInstance", Name: validation.Null, Rule: true, - Chain: []validation.Constraint{ - { - Target: "parameters.BackupInstance.DataSourceInfo", Name: validation.Null, Rule: true, - Chain: []validation.Constraint{{Target: "parameters.BackupInstance.DataSourceInfo.ResourceID", Name: validation.Null, Rule: true, Chain: nil}}, - }, - { - Target: "parameters.BackupInstance.DataSourceSetInfo", Name: validation.Null, Rule: false, - Chain: []validation.Constraint{{Target: "parameters.BackupInstance.DataSourceSetInfo.ResourceID", Name: validation.Null, Rule: true, Chain: nil}}, - }, - { - Target: "parameters.BackupInstance.PolicyInfo", Name: validation.Null, Rule: true, - Chain: []validation.Constraint{{Target: "parameters.BackupInstance.PolicyInfo.PolicyID", Name: validation.Null, Rule: true, Chain: nil}}, - }, - { - Target: "parameters.BackupInstance.ProtectionStatus", Name: validation.Null, Rule: false, - Chain: []validation.Constraint{ - { - Target: "parameters.BackupInstance.ProtectionStatus.ErrorDetails", Name: validation.Null, Rule: false, - Chain: []validation.Constraint{ - { - Target: "parameters.BackupInstance.ProtectionStatus.ErrorDetails.InnerError", Name: validation.Null, Rule: false, - Chain: []validation.Constraint{{Target: "parameters.BackupInstance.ProtectionStatus.ErrorDetails.InnerError.EmbeddedInnerError", Name: validation.Null, Rule: false, Chain: nil}}, - }, - }, - }, - }, - }, - { - Target: "parameters.BackupInstance.ProtectionErrorDetails", Name: validation.Null, Rule: false, - Chain: []validation.Constraint{ - { - Target: "parameters.BackupInstance.ProtectionErrorDetails.InnerError", Name: validation.Null, Rule: false, - Chain: []validation.Constraint{{Target: "parameters.BackupInstance.ProtectionErrorDetails.InnerError.EmbeddedInnerError", Name: validation.Null, Rule: false, Chain: nil}}, - }, - }, - }, - {Target: "parameters.BackupInstance.ObjectType", Name: validation.Null, Rule: true, Chain: nil}, - }, - }}, - }, - }); err != nil { - return result, validation.NewError("dataprotection.BackupInstancesClient", "ValidateForBackup", err.Error()) - } - - req, err := client.ValidateForBackupPreparer(ctx, vaultName, resourceGroupName, parameters) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupInstancesClient", "ValidateForBackup", nil, "Failure preparing request") - return - } - - result, err = client.ValidateForBackupSender(req) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupInstancesClient", "ValidateForBackup", nil, "Failure sending request") - return - } - - return -} - -// ValidateForBackupPreparer prepares the ValidateForBackup request. -func (client BackupInstancesClient) ValidateForBackupPreparer(ctx context.Context, vaultName string, resourceGroupName string, parameters ValidateForBackupRequest) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - "vaultName": autorest.Encode("path", vaultName), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsContentType("application/json; charset=utf-8"), - autorest.AsPost(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/backupVaults/{vaultName}/validateForBackup", pathParameters), - autorest.WithJSON(parameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// ValidateForBackupSender sends the ValidateForBackup request. The method will close the -// http.Response Body if it receives an error. -func (client BackupInstancesClient) ValidateForBackupSender(req *http.Request) (future BackupInstancesValidateForBackupFuture, err error) { - var resp *http.Response - resp, err = client.Send(req, azure.DoRetryWithRegistration(client.Client)) - if err != nil { - return - } - var azf azure.Future - azf, err = azure.NewFutureFromResponse(resp) - future.FutureAPI = &azf - future.Result = future.result - return -} - -// ValidateForBackupResponder handles the response to the ValidateForBackup request. The method always -// closes the http.Response Body. -func (client BackupInstancesClient) ValidateForBackupResponder(resp *http.Response) (result OperationJobExtendedInfo, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusAccepted), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// ValidateForRestore validates if Restore can be triggered for a DataSource -// Parameters: -// vaultName - the name of the backup vault. -// resourceGroupName - the name of the resource group where the backup vault is present. -// backupInstanceName - the name of the backup instance -// parameters - request body for operation -func (client BackupInstancesClient) ValidateForRestore(ctx context.Context, vaultName string, resourceGroupName string, backupInstanceName string, parameters ValidateRestoreRequestObject) (result BackupInstancesValidateForRestoreFuture, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/BackupInstancesClient.ValidateForRestore") - defer func() { - sc := -1 - if result.FutureAPI != nil && result.FutureAPI.Response() != nil { - sc = result.FutureAPI.Response().StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - req, err := client.ValidateForRestorePreparer(ctx, vaultName, resourceGroupName, backupInstanceName, parameters) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupInstancesClient", "ValidateForRestore", nil, "Failure preparing request") - return - } - - result, err = client.ValidateForRestoreSender(req) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupInstancesClient", "ValidateForRestore", nil, "Failure sending request") - return - } - - return -} - -// ValidateForRestorePreparer prepares the ValidateForRestore request. -func (client BackupInstancesClient) ValidateForRestorePreparer(ctx context.Context, vaultName string, resourceGroupName string, backupInstanceName string, parameters ValidateRestoreRequestObject) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "backupInstanceName": autorest.Encode("path", backupInstanceName), - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - "vaultName": autorest.Encode("path", vaultName), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsContentType("application/json; charset=utf-8"), - autorest.AsPost(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/backupVaults/{vaultName}/backupInstances/{backupInstanceName}/validateRestore", pathParameters), - autorest.WithJSON(parameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// ValidateForRestoreSender sends the ValidateForRestore request. The method will close the -// http.Response Body if it receives an error. -func (client BackupInstancesClient) ValidateForRestoreSender(req *http.Request) (future BackupInstancesValidateForRestoreFuture, err error) { - var resp *http.Response - resp, err = client.Send(req, azure.DoRetryWithRegistration(client.Client)) - if err != nil { - return - } - var azf azure.Future - azf, err = azure.NewFutureFromResponse(resp) - future.FutureAPI = &azf - future.Result = future.result - return -} - -// ValidateForRestoreResponder handles the response to the ValidateForRestore request. The method always -// closes the http.Response Body. -func (client BackupInstancesClient) ValidateForRestoreResponder(resp *http.Response) (result OperationJobExtendedInfo, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusAccepted), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} diff --git a/internal/services/dataprotection/legacysdk/dataprotection/backuppolicies.go b/internal/services/dataprotection/legacysdk/dataprotection/backuppolicies.go deleted file mode 100644 index 4f730fb6f7ea..000000000000 --- a/internal/services/dataprotection/legacysdk/dataprotection/backuppolicies.go +++ /dev/null @@ -1,384 +0,0 @@ -package dataprotection - -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. -// -// Code generated by Microsoft (R) AutoRest Code Generator. -// Changes may cause incorrect behavior and will be lost if the code is regenerated. - -import ( - "context" - "net/http" - - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/azure" - "github.com/Azure/go-autorest/tracing" -) - -// BackupPoliciesClient is the open API 2.0 Specs for Azure Data Protection service -type BackupPoliciesClient struct { - BaseClient -} - -// NewBackupPoliciesClient creates an instance of the BackupPoliciesClient client. -func NewBackupPoliciesClient(subscriptionID string) BackupPoliciesClient { - return NewBackupPoliciesClientWithBaseURI(DefaultBaseURI, subscriptionID) -} - -// NewBackupPoliciesClientWithBaseURI creates an instance of the BackupPoliciesClient client using a custom endpoint. -// Use this when interacting with an Azure cloud that uses a non-standard base URI (sovereign clouds, Azure stack). -func NewBackupPoliciesClientWithBaseURI(baseURI string, subscriptionID string) BackupPoliciesClient { - return BackupPoliciesClient{NewWithBaseURI(baseURI, subscriptionID)} -} - -// CreateOrUpdate sends the create or update request. -// Parameters: -// vaultName - the name of the backup vault. -// resourceGroupName - the name of the resource group where the backup vault is present. -// backupPolicyName - name of the policy -// parameters - request body for operation -func (client BackupPoliciesClient) CreateOrUpdate(ctx context.Context, vaultName string, resourceGroupName string, backupPolicyName string, parameters BaseBackupPolicyResource) (result BaseBackupPolicyResource, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/BackupPoliciesClient.CreateOrUpdate") - defer func() { - sc := -1 - if result.Response.Response != nil { - sc = result.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - req, err := client.CreateOrUpdatePreparer(ctx, vaultName, resourceGroupName, backupPolicyName, parameters) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupPoliciesClient", "CreateOrUpdate", nil, "Failure preparing request") - return - } - - resp, err := client.CreateOrUpdateSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.BackupPoliciesClient", "CreateOrUpdate", resp, "Failure sending request") - return - } - - result, err = client.CreateOrUpdateResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupPoliciesClient", "CreateOrUpdate", resp, "Failure responding to request") - return - } - - return -} - -// CreateOrUpdatePreparer prepares the CreateOrUpdate request. -func (client BackupPoliciesClient) CreateOrUpdatePreparer(ctx context.Context, vaultName string, resourceGroupName string, backupPolicyName string, parameters BaseBackupPolicyResource) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "backupPolicyName": autorest.Encode("path", backupPolicyName), - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - "vaultName": autorest.Encode("path", vaultName), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsContentType("application/json; charset=utf-8"), - autorest.AsPut(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/backupVaults/{vaultName}/backupPolicies/{backupPolicyName}", pathParameters), - autorest.WithJSON(parameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// CreateOrUpdateSender sends the CreateOrUpdate request. The method will close the -// http.Response Body if it receives an error. -func (client BackupPoliciesClient) CreateOrUpdateSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// CreateOrUpdateResponder handles the response to the CreateOrUpdate request. The method always -// closes the http.Response Body. -func (client BackupPoliciesClient) CreateOrUpdateResponder(resp *http.Response) (result BaseBackupPolicyResource, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// Delete sends the delete request. -// Parameters: -// vaultName - the name of the backup vault. -// resourceGroupName - the name of the resource group where the backup vault is present. -func (client BackupPoliciesClient) Delete(ctx context.Context, vaultName string, resourceGroupName string, backupPolicyName string) (result autorest.Response, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/BackupPoliciesClient.Delete") - defer func() { - sc := -1 - if result.Response != nil { - sc = result.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - req, err := client.DeletePreparer(ctx, vaultName, resourceGroupName, backupPolicyName) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupPoliciesClient", "Delete", nil, "Failure preparing request") - return - } - - resp, err := client.DeleteSender(req) - if err != nil { - result.Response = resp - err = autorest.NewErrorWithError(err, "dataprotection.BackupPoliciesClient", "Delete", resp, "Failure sending request") - return - } - - result, err = client.DeleteResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupPoliciesClient", "Delete", resp, "Failure responding to request") - return - } - - return -} - -// DeletePreparer prepares the Delete request. -func (client BackupPoliciesClient) DeletePreparer(ctx context.Context, vaultName string, resourceGroupName string, backupPolicyName string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "backupPolicyName": autorest.Encode("path", backupPolicyName), - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - "vaultName": autorest.Encode("path", vaultName), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsDelete(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/backupVaults/{vaultName}/backupPolicies/{backupPolicyName}", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// DeleteSender sends the Delete request. The method will close the -// http.Response Body if it receives an error. -func (client BackupPoliciesClient) DeleteSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// DeleteResponder handles the response to the Delete request. The method always -// closes the http.Response Body. -func (client BackupPoliciesClient) DeleteResponder(resp *http.Response) (result autorest.Response, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusNoContent), - autorest.ByClosing()) - result.Response = resp - return -} - -// Get gets a backup policy belonging to a backup vault -// Parameters: -// vaultName - the name of the backup vault. -// resourceGroupName - the name of the resource group where the backup vault is present. -func (client BackupPoliciesClient) Get(ctx context.Context, vaultName string, resourceGroupName string, backupPolicyName string) (result BaseBackupPolicyResource, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/BackupPoliciesClient.Get") - defer func() { - sc := -1 - if result.Response.Response != nil { - sc = result.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - req, err := client.GetPreparer(ctx, vaultName, resourceGroupName, backupPolicyName) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupPoliciesClient", "Get", nil, "Failure preparing request") - return - } - - resp, err := client.GetSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.BackupPoliciesClient", "Get", resp, "Failure sending request") - return - } - - result, err = client.GetResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupPoliciesClient", "Get", resp, "Failure responding to request") - return - } - - return -} - -// GetPreparer prepares the Get request. -func (client BackupPoliciesClient) GetPreparer(ctx context.Context, vaultName string, resourceGroupName string, backupPolicyName string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "backupPolicyName": autorest.Encode("path", backupPolicyName), - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - "vaultName": autorest.Encode("path", vaultName), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsGet(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/backupVaults/{vaultName}/backupPolicies/{backupPolicyName}", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// GetSender sends the Get request. The method will close the -// http.Response Body if it receives an error. -func (client BackupPoliciesClient) GetSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// GetResponder handles the response to the Get request. The method always -// closes the http.Response Body. -func (client BackupPoliciesClient) GetResponder(resp *http.Response) (result BaseBackupPolicyResource, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// List returns list of backup policies belonging to a backup vault -// Parameters: -// vaultName - the name of the backup vault. -// resourceGroupName - the name of the resource group where the backup vault is present. -func (client BackupPoliciesClient) List(ctx context.Context, vaultName string, resourceGroupName string) (result BaseBackupPolicyResourceListPage, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/BackupPoliciesClient.List") - defer func() { - sc := -1 - if result.bbprl.Response.Response != nil { - sc = result.bbprl.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - result.fn = client.listNextResults - req, err := client.ListPreparer(ctx, vaultName, resourceGroupName) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupPoliciesClient", "List", nil, "Failure preparing request") - return - } - - resp, err := client.ListSender(req) - if err != nil { - result.bbprl.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.BackupPoliciesClient", "List", resp, "Failure sending request") - return - } - - result.bbprl, err = client.ListResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupPoliciesClient", "List", resp, "Failure responding to request") - return - } - if result.bbprl.hasNextLink() && result.bbprl.IsEmpty() { - err = result.NextWithContext(ctx) - return - } - - return -} - -// ListPreparer prepares the List request. -func (client BackupPoliciesClient) ListPreparer(ctx context.Context, vaultName string, resourceGroupName string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - "vaultName": autorest.Encode("path", vaultName), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsGet(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/backupVaults/{vaultName}/backupPolicies", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// ListSender sends the List request. The method will close the -// http.Response Body if it receives an error. -func (client BackupPoliciesClient) ListSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// ListResponder handles the response to the List request. The method always -// closes the http.Response Body. -func (client BackupPoliciesClient) ListResponder(resp *http.Response) (result BaseBackupPolicyResourceList, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// listNextResults retrieves the next set of results, if any. -func (client BackupPoliciesClient) listNextResults(ctx context.Context, lastResults BaseBackupPolicyResourceList) (result BaseBackupPolicyResourceList, err error) { - req, err := lastResults.baseBackupPolicyResourceListPreparer(ctx) - if err != nil { - return result, autorest.NewErrorWithError(err, "dataprotection.BackupPoliciesClient", "listNextResults", nil, "Failure preparing next results request") - } - if req == nil { - return - } - resp, err := client.ListSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - return result, autorest.NewErrorWithError(err, "dataprotection.BackupPoliciesClient", "listNextResults", resp, "Failure sending next results request") - } - result, err = client.ListResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupPoliciesClient", "listNextResults", resp, "Failure responding to next results request") - } - return -} - -// ListComplete enumerates all values, automatically crossing page boundaries as required. -func (client BackupPoliciesClient) ListComplete(ctx context.Context, vaultName string, resourceGroupName string) (result BaseBackupPolicyResourceListIterator, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/BackupPoliciesClient.List") - defer func() { - sc := -1 - if result.Response().Response.Response != nil { - sc = result.page.Response().Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - result.page, err = client.List(ctx, vaultName, resourceGroupName) - return -} diff --git a/internal/services/dataprotection/legacysdk/dataprotection/backupvaultoperationresults.go b/internal/services/dataprotection/legacysdk/dataprotection/backupvaultoperationresults.go deleted file mode 100644 index 7433a7399926..000000000000 --- a/internal/services/dataprotection/legacysdk/dataprotection/backupvaultoperationresults.go +++ /dev/null @@ -1,110 +0,0 @@ -package dataprotection - -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. -// -// Code generated by Microsoft (R) AutoRest Code Generator. -// Changes may cause incorrect behavior and will be lost if the code is regenerated. - -import ( - "context" - "net/http" - - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/azure" - "github.com/Azure/go-autorest/tracing" -) - -// BackupVaultOperationResultsClient is the open API 2.0 Specs for Azure Data Protection service -type BackupVaultOperationResultsClient struct { - BaseClient -} - -// NewBackupVaultOperationResultsClient creates an instance of the BackupVaultOperationResultsClient client. -func NewBackupVaultOperationResultsClient(subscriptionID string) BackupVaultOperationResultsClient { - return NewBackupVaultOperationResultsClientWithBaseURI(DefaultBaseURI, subscriptionID) -} - -// NewBackupVaultOperationResultsClientWithBaseURI creates an instance of the BackupVaultOperationResultsClient client -// using a custom endpoint. Use this when interacting with an Azure cloud that uses a non-standard base URI (sovereign -// clouds, Azure stack). -func NewBackupVaultOperationResultsClientWithBaseURI(baseURI string, subscriptionID string) BackupVaultOperationResultsClient { - return BackupVaultOperationResultsClient{NewWithBaseURI(baseURI, subscriptionID)} -} - -// Get sends the get request. -// Parameters: -// vaultName - the name of the backup vault. -// resourceGroupName - the name of the resource group where the backup vault is present. -func (client BackupVaultOperationResultsClient) Get(ctx context.Context, vaultName string, resourceGroupName string, operationID string) (result BackupVaultResource, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/BackupVaultOperationResultsClient.Get") - defer func() { - sc := -1 - if result.Response.Response != nil { - sc = result.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - req, err := client.GetPreparer(ctx, vaultName, resourceGroupName, operationID) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupVaultOperationResultsClient", "Get", nil, "Failure preparing request") - return - } - - resp, err := client.GetSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.BackupVaultOperationResultsClient", "Get", resp, "Failure sending request") - return - } - - result, err = client.GetResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupVaultOperationResultsClient", "Get", resp, "Failure responding to request") - return - } - - return -} - -// GetPreparer prepares the Get request. -func (client BackupVaultOperationResultsClient) GetPreparer(ctx context.Context, vaultName string, resourceGroupName string, operationID string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "operationId": autorest.Encode("path", operationID), - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - "vaultName": autorest.Encode("path", vaultName), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsGet(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/backupVaults/{vaultName}/operationResults/{operationId}", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// GetSender sends the Get request. The method will close the -// http.Response Body if it receives an error. -func (client BackupVaultOperationResultsClient) GetSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// GetResponder handles the response to the Get request. The method always -// closes the http.Response Body. -func (client BackupVaultOperationResultsClient) GetResponder(resp *http.Response) (result BackupVaultResource, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusAccepted), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} diff --git a/internal/services/dataprotection/legacysdk/dataprotection/backupvaults.go b/internal/services/dataprotection/legacysdk/dataprotection/backupvaults.go deleted file mode 100644 index 38a2ad1943e2..000000000000 --- a/internal/services/dataprotection/legacysdk/dataprotection/backupvaults.go +++ /dev/null @@ -1,666 +0,0 @@ -package dataprotection - -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. -// -// Code generated by Microsoft (R) AutoRest Code Generator. -// Changes may cause incorrect behavior and will be lost if the code is regenerated. - -import ( - "context" - "net/http" - - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/azure" - "github.com/Azure/go-autorest/autorest/validation" - "github.com/Azure/go-autorest/tracing" -) - -// BackupVaultsClient is the open API 2.0 Specs for Azure Data Protection service -type BackupVaultsClient struct { - BaseClient -} - -// NewBackupVaultsClient creates an instance of the BackupVaultsClient client. -func NewBackupVaultsClient(subscriptionID string) BackupVaultsClient { - return NewBackupVaultsClientWithBaseURI(DefaultBaseURI, subscriptionID) -} - -// NewBackupVaultsClientWithBaseURI creates an instance of the BackupVaultsClient client using a custom endpoint. Use -// this when interacting with an Azure cloud that uses a non-standard base URI (sovereign clouds, Azure stack). -func NewBackupVaultsClientWithBaseURI(baseURI string, subscriptionID string) BackupVaultsClient { - return BackupVaultsClient{NewWithBaseURI(baseURI, subscriptionID)} -} - -// CheckNameAvailability sends the check name availability request. -// Parameters: -// resourceGroupName - the name of the resource group where the backup vault is present. -// location - the location in which uniqueness will be verified. -// parameters - check name availability request -func (client BackupVaultsClient) CheckNameAvailability(ctx context.Context, resourceGroupName string, location string, parameters CheckNameAvailabilityRequest) (result CheckNameAvailabilityResult, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/BackupVaultsClient.CheckNameAvailability") - defer func() { - sc := -1 - if result.Response.Response != nil { - sc = result.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - req, err := client.CheckNameAvailabilityPreparer(ctx, resourceGroupName, location, parameters) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupVaultsClient", "CheckNameAvailability", nil, "Failure preparing request") - return - } - - resp, err := client.CheckNameAvailabilitySender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.BackupVaultsClient", "CheckNameAvailability", resp, "Failure sending request") - return - } - - result, err = client.CheckNameAvailabilityResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupVaultsClient", "CheckNameAvailability", resp, "Failure responding to request") - return - } - - return -} - -// CheckNameAvailabilityPreparer prepares the CheckNameAvailability request. -func (client BackupVaultsClient) CheckNameAvailabilityPreparer(ctx context.Context, resourceGroupName string, location string, parameters CheckNameAvailabilityRequest) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "location": autorest.Encode("path", location), - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsContentType("application/json; charset=utf-8"), - autorest.AsPost(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/locations/{location}/checkNameAvailability", pathParameters), - autorest.WithJSON(parameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// CheckNameAvailabilitySender sends the CheckNameAvailability request. The method will close the -// http.Response Body if it receives an error. -func (client BackupVaultsClient) CheckNameAvailabilitySender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// CheckNameAvailabilityResponder handles the response to the CheckNameAvailability request. The method always -// closes the http.Response Body. -func (client BackupVaultsClient) CheckNameAvailabilityResponder(resp *http.Response) (result CheckNameAvailabilityResult, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// CreateOrUpdate creates or updates a BackupVault resource belonging to a resource group. -// Parameters: -// vaultName - the name of the backup vault. -// resourceGroupName - the name of the resource group where the backup vault is present. -// parameters - request body for operation -func (client BackupVaultsClient) CreateOrUpdate(ctx context.Context, vaultName string, resourceGroupName string, parameters BackupVaultResource) (result BackupVaultsCreateOrUpdateFuture, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/BackupVaultsClient.CreateOrUpdate") - defer func() { - sc := -1 - if result.FutureAPI != nil && result.FutureAPI.Response() != nil { - sc = result.FutureAPI.Response().StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - if err := validation.Validate([]validation.Validation{ - { - TargetValue: parameters, - Constraints: []validation.Constraint{{ - Target: "parameters.Properties", Name: validation.Null, Rule: true, - Chain: []validation.Constraint{{Target: "parameters.Properties.StorageSettings", Name: validation.Null, Rule: true, Chain: nil}}, - }}, - }, - }); err != nil { - return result, validation.NewError("dataprotection.BackupVaultsClient", "CreateOrUpdate", err.Error()) - } - - req, err := client.CreateOrUpdatePreparer(ctx, vaultName, resourceGroupName, parameters) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupVaultsClient", "CreateOrUpdate", nil, "Failure preparing request") - return - } - - result, err = client.CreateOrUpdateSender(req) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupVaultsClient", "CreateOrUpdate", nil, "Failure sending request") - return - } - - return -} - -// CreateOrUpdatePreparer prepares the CreateOrUpdate request. -func (client BackupVaultsClient) CreateOrUpdatePreparer(ctx context.Context, vaultName string, resourceGroupName string, parameters BackupVaultResource) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - "vaultName": autorest.Encode("path", vaultName), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsContentType("application/json; charset=utf-8"), - autorest.AsPut(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/backupVaults/{vaultName}", pathParameters), - autorest.WithJSON(parameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// CreateOrUpdateSender sends the CreateOrUpdate request. The method will close the -// http.Response Body if it receives an error. -func (client BackupVaultsClient) CreateOrUpdateSender(req *http.Request) (future BackupVaultsCreateOrUpdateFuture, err error) { - var resp *http.Response - resp, err = client.Send(req, azure.DoRetryWithRegistration(client.Client)) - if err != nil { - return - } - var azf azure.Future - azf, err = azure.NewFutureFromResponse(resp) - future.FutureAPI = &azf - future.Result = future.result - return -} - -// CreateOrUpdateResponder handles the response to the CreateOrUpdate request. The method always -// closes the http.Response Body. -func (client BackupVaultsClient) CreateOrUpdateResponder(resp *http.Response) (result BackupVaultResource, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusCreated), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// Delete deletes a BackupVault resource from the resource group. -// Parameters: -// vaultName - the name of the backup vault. -// resourceGroupName - the name of the resource group where the backup vault is present. -func (client BackupVaultsClient) Delete(ctx context.Context, vaultName string, resourceGroupName string) (result autorest.Response, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/BackupVaultsClient.Delete") - defer func() { - sc := -1 - if result.Response != nil { - sc = result.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - req, err := client.DeletePreparer(ctx, vaultName, resourceGroupName) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupVaultsClient", "Delete", nil, "Failure preparing request") - return - } - - resp, err := client.DeleteSender(req) - if err != nil { - result.Response = resp - err = autorest.NewErrorWithError(err, "dataprotection.BackupVaultsClient", "Delete", resp, "Failure sending request") - return - } - - result, err = client.DeleteResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupVaultsClient", "Delete", resp, "Failure responding to request") - return - } - - return -} - -// DeletePreparer prepares the Delete request. -func (client BackupVaultsClient) DeletePreparer(ctx context.Context, vaultName string, resourceGroupName string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - "vaultName": autorest.Encode("path", vaultName), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsDelete(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/backupVaults/{vaultName}", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// DeleteSender sends the Delete request. The method will close the -// http.Response Body if it receives an error. -func (client BackupVaultsClient) DeleteSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// DeleteResponder handles the response to the Delete request. The method always -// closes the http.Response Body. -func (client BackupVaultsClient) DeleteResponder(resp *http.Response) (result autorest.Response, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusAccepted, http.StatusNoContent), - autorest.ByClosing()) - result.Response = resp - return -} - -// Get returns a resource belonging to a resource group. -// Parameters: -// vaultName - the name of the backup vault. -// resourceGroupName - the name of the resource group where the backup vault is present. -func (client BackupVaultsClient) Get(ctx context.Context, vaultName string, resourceGroupName string) (result BackupVaultResource, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/BackupVaultsClient.Get") - defer func() { - sc := -1 - if result.Response.Response != nil { - sc = result.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - req, err := client.GetPreparer(ctx, vaultName, resourceGroupName) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupVaultsClient", "Get", nil, "Failure preparing request") - return - } - - resp, err := client.GetSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.BackupVaultsClient", "Get", resp, "Failure sending request") - return - } - - result, err = client.GetResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupVaultsClient", "Get", resp, "Failure responding to request") - return - } - - return -} - -// GetPreparer prepares the Get request. -func (client BackupVaultsClient) GetPreparer(ctx context.Context, vaultName string, resourceGroupName string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - "vaultName": autorest.Encode("path", vaultName), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsGet(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/backupVaults/{vaultName}", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// GetSender sends the Get request. The method will close the -// http.Response Body if it receives an error. -func (client BackupVaultsClient) GetSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// GetResponder handles the response to the Get request. The method always -// closes the http.Response Body. -func (client BackupVaultsClient) GetResponder(resp *http.Response) (result BackupVaultResource, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// GetInResourceGroup returns resource collection belonging to a resource group. -// Parameters: -// resourceGroupName - the name of the resource group where the backup vault is present. -func (client BackupVaultsClient) GetInResourceGroup(ctx context.Context, resourceGroupName string) (result BackupVaultResourceListPage, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/BackupVaultsClient.GetInResourceGroup") - defer func() { - sc := -1 - if result.bvrl.Response.Response != nil { - sc = result.bvrl.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - result.fn = client.getInResourceGroupNextResults - req, err := client.GetInResourceGroupPreparer(ctx, resourceGroupName) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupVaultsClient", "GetInResourceGroup", nil, "Failure preparing request") - return - } - - resp, err := client.GetInResourceGroupSender(req) - if err != nil { - result.bvrl.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.BackupVaultsClient", "GetInResourceGroup", resp, "Failure sending request") - return - } - - result.bvrl, err = client.GetInResourceGroupResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupVaultsClient", "GetInResourceGroup", resp, "Failure responding to request") - return - } - if result.bvrl.hasNextLink() && result.bvrl.IsEmpty() { - err = result.NextWithContext(ctx) - return - } - - return -} - -// GetInResourceGroupPreparer prepares the GetInResourceGroup request. -func (client BackupVaultsClient) GetInResourceGroupPreparer(ctx context.Context, resourceGroupName string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsGet(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/backupVaults", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// GetInResourceGroupSender sends the GetInResourceGroup request. The method will close the -// http.Response Body if it receives an error. -func (client BackupVaultsClient) GetInResourceGroupSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// GetInResourceGroupResponder handles the response to the GetInResourceGroup request. The method always -// closes the http.Response Body. -func (client BackupVaultsClient) GetInResourceGroupResponder(resp *http.Response) (result BackupVaultResourceList, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// getInResourceGroupNextResults retrieves the next set of results, if any. -func (client BackupVaultsClient) getInResourceGroupNextResults(ctx context.Context, lastResults BackupVaultResourceList) (result BackupVaultResourceList, err error) { - req, err := lastResults.backupVaultResourceListPreparer(ctx) - if err != nil { - return result, autorest.NewErrorWithError(err, "dataprotection.BackupVaultsClient", "getInResourceGroupNextResults", nil, "Failure preparing next results request") - } - if req == nil { - return - } - resp, err := client.GetInResourceGroupSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - return result, autorest.NewErrorWithError(err, "dataprotection.BackupVaultsClient", "getInResourceGroupNextResults", resp, "Failure sending next results request") - } - result, err = client.GetInResourceGroupResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupVaultsClient", "getInResourceGroupNextResults", resp, "Failure responding to next results request") - } - return -} - -// GetInResourceGroupComplete enumerates all values, automatically crossing page boundaries as required. -func (client BackupVaultsClient) GetInResourceGroupComplete(ctx context.Context, resourceGroupName string) (result BackupVaultResourceListIterator, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/BackupVaultsClient.GetInResourceGroup") - defer func() { - sc := -1 - if result.Response().Response.Response != nil { - sc = result.page.Response().Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - result.page, err = client.GetInResourceGroup(ctx, resourceGroupName) - return -} - -// GetInSubscription returns resource collection belonging to a subscription. -func (client BackupVaultsClient) GetInSubscription(ctx context.Context) (result BackupVaultResourceListPage, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/BackupVaultsClient.GetInSubscription") - defer func() { - sc := -1 - if result.bvrl.Response.Response != nil { - sc = result.bvrl.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - result.fn = client.getInSubscriptionNextResults - req, err := client.GetInSubscriptionPreparer(ctx) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupVaultsClient", "GetInSubscription", nil, "Failure preparing request") - return - } - - resp, err := client.GetInSubscriptionSender(req) - if err != nil { - result.bvrl.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.BackupVaultsClient", "GetInSubscription", resp, "Failure sending request") - return - } - - result.bvrl, err = client.GetInSubscriptionResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupVaultsClient", "GetInSubscription", resp, "Failure responding to request") - return - } - if result.bvrl.hasNextLink() && result.bvrl.IsEmpty() { - err = result.NextWithContext(ctx) - return - } - - return -} - -// GetInSubscriptionPreparer prepares the GetInSubscription request. -func (client BackupVaultsClient) GetInSubscriptionPreparer(ctx context.Context) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsGet(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/providers/Microsoft.DataProtection/backupVaults", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// GetInSubscriptionSender sends the GetInSubscription request. The method will close the -// http.Response Body if it receives an error. -func (client BackupVaultsClient) GetInSubscriptionSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// GetInSubscriptionResponder handles the response to the GetInSubscription request. The method always -// closes the http.Response Body. -func (client BackupVaultsClient) GetInSubscriptionResponder(resp *http.Response) (result BackupVaultResourceList, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// getInSubscriptionNextResults retrieves the next set of results, if any. -func (client BackupVaultsClient) getInSubscriptionNextResults(ctx context.Context, lastResults BackupVaultResourceList) (result BackupVaultResourceList, err error) { - req, err := lastResults.backupVaultResourceListPreparer(ctx) - if err != nil { - return result, autorest.NewErrorWithError(err, "dataprotection.BackupVaultsClient", "getInSubscriptionNextResults", nil, "Failure preparing next results request") - } - if req == nil { - return - } - resp, err := client.GetInSubscriptionSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - return result, autorest.NewErrorWithError(err, "dataprotection.BackupVaultsClient", "getInSubscriptionNextResults", resp, "Failure sending next results request") - } - result, err = client.GetInSubscriptionResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupVaultsClient", "getInSubscriptionNextResults", resp, "Failure responding to next results request") - } - return -} - -// GetInSubscriptionComplete enumerates all values, automatically crossing page boundaries as required. -func (client BackupVaultsClient) GetInSubscriptionComplete(ctx context.Context) (result BackupVaultResourceListIterator, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/BackupVaultsClient.GetInSubscription") - defer func() { - sc := -1 - if result.Response().Response.Response != nil { - sc = result.page.Response().Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - result.page, err = client.GetInSubscription(ctx) - return -} - -// Update updates a BackupVault resource belonging to a resource group. For example, updating tags for a resource. -// Parameters: -// vaultName - the name of the backup vault. -// resourceGroupName - the name of the resource group where the backup vault is present. -// parameters - request body for operation -func (client BackupVaultsClient) Update(ctx context.Context, vaultName string, resourceGroupName string, parameters PatchResourceRequestInput) (result BackupVaultsUpdateFuture, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/BackupVaultsClient.Update") - defer func() { - sc := -1 - if result.FutureAPI != nil && result.FutureAPI.Response() != nil { - sc = result.FutureAPI.Response().StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - req, err := client.UpdatePreparer(ctx, vaultName, resourceGroupName, parameters) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupVaultsClient", "Update", nil, "Failure preparing request") - return - } - - result, err = client.UpdateSender(req) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupVaultsClient", "Update", nil, "Failure sending request") - return - } - - return -} - -// UpdatePreparer prepares the Update request. -func (client BackupVaultsClient) UpdatePreparer(ctx context.Context, vaultName string, resourceGroupName string, parameters PatchResourceRequestInput) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - "vaultName": autorest.Encode("path", vaultName), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsContentType("application/json; charset=utf-8"), - autorest.AsPatch(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/backupVaults/{vaultName}", pathParameters), - autorest.WithJSON(parameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// UpdateSender sends the Update request. The method will close the -// http.Response Body if it receives an error. -func (client BackupVaultsClient) UpdateSender(req *http.Request) (future BackupVaultsUpdateFuture, err error) { - var resp *http.Response - resp, err = client.Send(req, azure.DoRetryWithRegistration(client.Client)) - if err != nil { - return - } - var azf azure.Future - azf, err = azure.NewFutureFromResponse(resp) - future.FutureAPI = &azf - future.Result = future.result - return -} - -// UpdateResponder handles the response to the Update request. The method always -// closes the http.Response Body. -func (client BackupVaultsClient) UpdateResponder(resp *http.Response) (result BackupVaultResource, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusAccepted), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} diff --git a/internal/services/dataprotection/legacysdk/dataprotection/client.go b/internal/services/dataprotection/legacysdk/dataprotection/client.go deleted file mode 100644 index 64d725f2bae8..000000000000 --- a/internal/services/dataprotection/legacysdk/dataprotection/client.go +++ /dev/null @@ -1,41 +0,0 @@ -// Package dataprotection implements the Azure ARM Dataprotection service API version 2021-07-01. -// -// Open API 2.0 Specs for Azure Data Protection service -package dataprotection - -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. -// -// Code generated by Microsoft (R) AutoRest Code Generator. -// Changes may cause incorrect behavior and will be lost if the code is regenerated. - -import ( - "github.com/Azure/go-autorest/autorest" -) - -const ( - // DefaultBaseURI is the default URI used for the service Dataprotection - DefaultBaseURI = "https://management.azure.com" -) - -// BaseClient is the base client for Dataprotection. -type BaseClient struct { - autorest.Client - BaseURI string - SubscriptionID string -} - -// New creates an instance of the BaseClient client. -func New(subscriptionID string) BaseClient { - return NewWithBaseURI(DefaultBaseURI, subscriptionID) -} - -// NewWithBaseURI creates an instance of the BaseClient client using a custom endpoint. Use this when interacting with -// an Azure cloud that uses a non-standard base URI (sovereign clouds, Azure stack). -func NewWithBaseURI(baseURI string, subscriptionID string) BaseClient { - return BaseClient{ - Client: autorest.NewClientWithUserAgent(UserAgent()), - BaseURI: baseURI, - SubscriptionID: subscriptionID, - } -} diff --git a/internal/services/dataprotection/legacysdk/dataprotection/dataprotection.go b/internal/services/dataprotection/legacysdk/dataprotection/dataprotection.go deleted file mode 100644 index 57e523220de8..000000000000 --- a/internal/services/dataprotection/legacysdk/dataprotection/dataprotection.go +++ /dev/null @@ -1,108 +0,0 @@ -package dataprotection - -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. -// -// Code generated by Microsoft (R) AutoRest Code Generator. -// Changes may cause incorrect behavior and will be lost if the code is regenerated. - -import ( - "context" - "net/http" - - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/azure" - "github.com/Azure/go-autorest/tracing" -) - -// Client is the open API 2.0 Specs for Azure Data Protection service -type Client struct { - BaseClient -} - -// NewClient creates an instance of the Client client. -func NewClient(subscriptionID string) Client { - return NewClientWithBaseURI(DefaultBaseURI, subscriptionID) -} - -// NewClientWithBaseURI creates an instance of the Client client using a custom endpoint. Use this when interacting -// with an Azure cloud that uses a non-standard base URI (sovereign clouds, Azure stack). -func NewClientWithBaseURI(baseURI string, subscriptionID string) Client { - return Client{NewWithBaseURI(baseURI, subscriptionID)} -} - -// CheckFeatureSupport sends the check feature support request. -// Parameters: -// parameters - feature support request object -func (client Client) CheckFeatureSupport(ctx context.Context, location string, parameters BasicFeatureValidationRequestBase) (result FeatureValidationResponseBaseModel, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/Client.CheckFeatureSupport") - defer func() { - sc := -1 - if result.Response.Response != nil { - sc = result.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - req, err := client.CheckFeatureSupportPreparer(ctx, location, parameters) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.Client", "CheckFeatureSupport", nil, "Failure preparing request") - return - } - - resp, err := client.CheckFeatureSupportSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.Client", "CheckFeatureSupport", resp, "Failure sending request") - return - } - - result, err = client.CheckFeatureSupportResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.Client", "CheckFeatureSupport", resp, "Failure responding to request") - return - } - - return -} - -// CheckFeatureSupportPreparer prepares the CheckFeatureSupport request. -func (client Client) CheckFeatureSupportPreparer(ctx context.Context, location string, parameters BasicFeatureValidationRequestBase) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "location": autorest.Encode("path", location), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsContentType("application/json; charset=utf-8"), - autorest.AsPost(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/providers/Microsoft.DataProtection/locations/{location}/checkFeatureSupport", pathParameters), - autorest.WithJSON(parameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// CheckFeatureSupportSender sends the CheckFeatureSupport request. The method will close the -// http.Response Body if it receives an error. -func (client Client) CheckFeatureSupportSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// CheckFeatureSupportResponder handles the response to the CheckFeatureSupport request. The method always -// closes the http.Response Body. -func (client Client) CheckFeatureSupportResponder(resp *http.Response) (result FeatureValidationResponseBaseModel, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} diff --git a/internal/services/dataprotection/legacysdk/dataprotection/enums.go b/internal/services/dataprotection/legacysdk/dataprotection/enums.go deleted file mode 100644 index 9da554a4ddd0..000000000000 --- a/internal/services/dataprotection/legacysdk/dataprotection/enums.go +++ /dev/null @@ -1,690 +0,0 @@ -package dataprotection - -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. -// -// Code generated by Microsoft (R) AutoRest Code Generator. -// Changes may cause incorrect behavior and will be lost if the code is regenerated. - -// AbsoluteMarker enumerates the values for absolute marker. -type AbsoluteMarker string - -const ( - // AbsoluteMarkerAllBackup ... - AbsoluteMarkerAllBackup AbsoluteMarker = "AllBackup" - // AbsoluteMarkerFirstOfDay ... - AbsoluteMarkerFirstOfDay AbsoluteMarker = "FirstOfDay" - // AbsoluteMarkerFirstOfMonth ... - AbsoluteMarkerFirstOfMonth AbsoluteMarker = "FirstOfMonth" - // AbsoluteMarkerFirstOfWeek ... - AbsoluteMarkerFirstOfWeek AbsoluteMarker = "FirstOfWeek" - // AbsoluteMarkerFirstOfYear ... - AbsoluteMarkerFirstOfYear AbsoluteMarker = "FirstOfYear" -) - -// PossibleAbsoluteMarkerValues returns an array of possible values for the AbsoluteMarker const type. -func PossibleAbsoluteMarkerValues() []AbsoluteMarker { - return []AbsoluteMarker{AbsoluteMarkerAllBackup, AbsoluteMarkerFirstOfDay, AbsoluteMarkerFirstOfMonth, AbsoluteMarkerFirstOfWeek, AbsoluteMarkerFirstOfYear} -} - -// CreatedByType enumerates the values for created by type. -type CreatedByType string - -const ( - // CreatedByTypeApplication ... - CreatedByTypeApplication CreatedByType = "Application" - // CreatedByTypeKey ... - CreatedByTypeKey CreatedByType = "Key" - // CreatedByTypeManagedIdentity ... - CreatedByTypeManagedIdentity CreatedByType = "ManagedIdentity" - // CreatedByTypeUser ... - CreatedByTypeUser CreatedByType = "User" -) - -// PossibleCreatedByTypeValues returns an array of possible values for the CreatedByType const type. -func PossibleCreatedByTypeValues() []CreatedByType { - return []CreatedByType{CreatedByTypeApplication, CreatedByTypeKey, CreatedByTypeManagedIdentity, CreatedByTypeUser} -} - -// CurrentProtectionState enumerates the values for current protection state. -type CurrentProtectionState string - -const ( - // CurrentProtectionStateBackupSchedulesSuspended ... - CurrentProtectionStateBackupSchedulesSuspended CurrentProtectionState = "BackupSchedulesSuspended" - // CurrentProtectionStateConfiguringProtection ... - CurrentProtectionStateConfiguringProtection CurrentProtectionState = "ConfiguringProtection" - // CurrentProtectionStateConfiguringProtectionFailed ... - CurrentProtectionStateConfiguringProtectionFailed CurrentProtectionState = "ConfiguringProtectionFailed" - // CurrentProtectionStateInvalid ... - CurrentProtectionStateInvalid CurrentProtectionState = "Invalid" - // CurrentProtectionStateNotProtected ... - CurrentProtectionStateNotProtected CurrentProtectionState = "NotProtected" - // CurrentProtectionStateProtectionConfigured ... - CurrentProtectionStateProtectionConfigured CurrentProtectionState = "ProtectionConfigured" - // CurrentProtectionStateProtectionError ... - CurrentProtectionStateProtectionError CurrentProtectionState = "ProtectionError" - // CurrentProtectionStateProtectionStopped ... - CurrentProtectionStateProtectionStopped CurrentProtectionState = "ProtectionStopped" - // CurrentProtectionStateRetentionSchedulesSuspended ... - CurrentProtectionStateRetentionSchedulesSuspended CurrentProtectionState = "RetentionSchedulesSuspended" - // CurrentProtectionStateSoftDeleted ... - CurrentProtectionStateSoftDeleted CurrentProtectionState = "SoftDeleted" - // CurrentProtectionStateSoftDeleting ... - CurrentProtectionStateSoftDeleting CurrentProtectionState = "SoftDeleting" - // CurrentProtectionStateUpdatingProtection ... - CurrentProtectionStateUpdatingProtection CurrentProtectionState = "UpdatingProtection" -) - -// PossibleCurrentProtectionStateValues returns an array of possible values for the CurrentProtectionState const type. -func PossibleCurrentProtectionStateValues() []CurrentProtectionState { - return []CurrentProtectionState{CurrentProtectionStateBackupSchedulesSuspended, CurrentProtectionStateConfiguringProtection, CurrentProtectionStateConfiguringProtectionFailed, CurrentProtectionStateInvalid, CurrentProtectionStateNotProtected, CurrentProtectionStateProtectionConfigured, CurrentProtectionStateProtectionError, CurrentProtectionStateProtectionStopped, CurrentProtectionStateRetentionSchedulesSuspended, CurrentProtectionStateSoftDeleted, CurrentProtectionStateSoftDeleting, CurrentProtectionStateUpdatingProtection} -} - -// DataStoreTypes enumerates the values for data store types. -type DataStoreTypes string - -const ( - // DataStoreTypesArchiveStore ... - DataStoreTypesArchiveStore DataStoreTypes = "ArchiveStore" - // DataStoreTypesOperationalStore ... - DataStoreTypesOperationalStore DataStoreTypes = "OperationalStore" - // DataStoreTypesVaultStore ... - DataStoreTypesVaultStore DataStoreTypes = "VaultStore" -) - -// PossibleDataStoreTypesValues returns an array of possible values for the DataStoreTypes const type. -func PossibleDataStoreTypesValues() []DataStoreTypes { - return []DataStoreTypes{DataStoreTypesArchiveStore, DataStoreTypesOperationalStore, DataStoreTypesVaultStore} -} - -// DayOfWeek enumerates the values for day of week. -type DayOfWeek string - -const ( - // DayOfWeekFriday ... - DayOfWeekFriday DayOfWeek = "Friday" - // DayOfWeekMonday ... - DayOfWeekMonday DayOfWeek = "Monday" - // DayOfWeekSaturday ... - DayOfWeekSaturday DayOfWeek = "Saturday" - // DayOfWeekSunday ... - DayOfWeekSunday DayOfWeek = "Sunday" - // DayOfWeekThursday ... - DayOfWeekThursday DayOfWeek = "Thursday" - // DayOfWeekTuesday ... - DayOfWeekTuesday DayOfWeek = "Tuesday" - // DayOfWeekWednesday ... - DayOfWeekWednesday DayOfWeek = "Wednesday" -) - -// PossibleDayOfWeekValues returns an array of possible values for the DayOfWeek const type. -func PossibleDayOfWeekValues() []DayOfWeek { - return []DayOfWeek{DayOfWeekFriday, DayOfWeekMonday, DayOfWeekSaturday, DayOfWeekSunday, DayOfWeekThursday, DayOfWeekTuesday, DayOfWeekWednesday} -} - -// FeatureSupportStatus enumerates the values for feature support status. -type FeatureSupportStatus string - -const ( - // FeatureSupportStatusAlphaPreview ... - FeatureSupportStatusAlphaPreview FeatureSupportStatus = "AlphaPreview" - // FeatureSupportStatusGenerallyAvailable ... - FeatureSupportStatusGenerallyAvailable FeatureSupportStatus = "GenerallyAvailable" - // FeatureSupportStatusInvalid ... - FeatureSupportStatusInvalid FeatureSupportStatus = "Invalid" - // FeatureSupportStatusNotSupported ... - FeatureSupportStatusNotSupported FeatureSupportStatus = "NotSupported" - // FeatureSupportStatusPrivatePreview ... - FeatureSupportStatusPrivatePreview FeatureSupportStatus = "PrivatePreview" - // FeatureSupportStatusPublicPreview ... - FeatureSupportStatusPublicPreview FeatureSupportStatus = "PublicPreview" -) - -// PossibleFeatureSupportStatusValues returns an array of possible values for the FeatureSupportStatus const type. -func PossibleFeatureSupportStatusValues() []FeatureSupportStatus { - return []FeatureSupportStatus{FeatureSupportStatusAlphaPreview, FeatureSupportStatusGenerallyAvailable, FeatureSupportStatusInvalid, FeatureSupportStatusNotSupported, FeatureSupportStatusPrivatePreview, FeatureSupportStatusPublicPreview} -} - -// FeatureType enumerates the values for feature type. -type FeatureType string - -const ( - // FeatureTypeDataSourceType ... - FeatureTypeDataSourceType FeatureType = "DataSourceType" - // FeatureTypeInvalid ... - FeatureTypeInvalid FeatureType = "Invalid" -) - -// PossibleFeatureTypeValues returns an array of possible values for the FeatureType const type. -func PossibleFeatureTypeValues() []FeatureType { - return []FeatureType{FeatureTypeDataSourceType, FeatureTypeInvalid} -} - -// Month enumerates the values for month. -type Month string - -const ( - // MonthApril ... - MonthApril Month = "April" - // MonthAugust ... - MonthAugust Month = "August" - // MonthDecember ... - MonthDecember Month = "December" - // MonthFebruary ... - MonthFebruary Month = "February" - // MonthJanuary ... - MonthJanuary Month = "January" - // MonthJuly ... - MonthJuly Month = "July" - // MonthJune ... - MonthJune Month = "June" - // MonthMarch ... - MonthMarch Month = "March" - // MonthMay ... - MonthMay Month = "May" - // MonthNovember ... - MonthNovember Month = "November" - // MonthOctober ... - MonthOctober Month = "October" - // MonthSeptember ... - MonthSeptember Month = "September" -) - -// PossibleMonthValues returns an array of possible values for the Month const type. -func PossibleMonthValues() []Month { - return []Month{MonthApril, MonthAugust, MonthDecember, MonthFebruary, MonthJanuary, MonthJuly, MonthJune, MonthMarch, MonthMay, MonthNovember, MonthOctober, MonthSeptember} -} - -// ObjectType enumerates the values for object type. -type ObjectType string - -const ( - // ObjectTypeAuthCredentials ... - ObjectTypeAuthCredentials ObjectType = "AuthCredentials" - // ObjectTypeSecretStoreBasedAuthCredentials ... - ObjectTypeSecretStoreBasedAuthCredentials ObjectType = "SecretStoreBasedAuthCredentials" -) - -// PossibleObjectTypeValues returns an array of possible values for the ObjectType const type. -func PossibleObjectTypeValues() []ObjectType { - return []ObjectType{ObjectTypeAuthCredentials, ObjectTypeSecretStoreBasedAuthCredentials} -} - -// ObjectTypeBasicAzureBackupRecoveryPoint enumerates the values for object type basic azure backup recovery -// point. -type ObjectTypeBasicAzureBackupRecoveryPoint string - -const ( - // ObjectTypeBasicAzureBackupRecoveryPointObjectTypeAzureBackupDiscreteRecoveryPoint ... - ObjectTypeBasicAzureBackupRecoveryPointObjectTypeAzureBackupDiscreteRecoveryPoint ObjectTypeBasicAzureBackupRecoveryPoint = "AzureBackupDiscreteRecoveryPoint" - // ObjectTypeBasicAzureBackupRecoveryPointObjectTypeAzureBackupRecoveryPoint ... - ObjectTypeBasicAzureBackupRecoveryPointObjectTypeAzureBackupRecoveryPoint ObjectTypeBasicAzureBackupRecoveryPoint = "AzureBackupRecoveryPoint" -) - -// PossibleObjectTypeBasicAzureBackupRecoveryPointValues returns an array of possible values for the ObjectTypeBasicAzureBackupRecoveryPoint const type. -func PossibleObjectTypeBasicAzureBackupRecoveryPointValues() []ObjectTypeBasicAzureBackupRecoveryPoint { - return []ObjectTypeBasicAzureBackupRecoveryPoint{ObjectTypeBasicAzureBackupRecoveryPointObjectTypeAzureBackupDiscreteRecoveryPoint, ObjectTypeBasicAzureBackupRecoveryPointObjectTypeAzureBackupRecoveryPoint} -} - -// ObjectTypeBasicAzureBackupRestoreRequest enumerates the values for object type basic azure backup restore -// request. -type ObjectTypeBasicAzureBackupRestoreRequest string - -const ( - // ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRecoveryPointBasedRestoreRequest ... - ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRecoveryPointBasedRestoreRequest ObjectTypeBasicAzureBackupRestoreRequest = "AzureBackupRecoveryPointBasedRestoreRequest" - // ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRecoveryTimeBasedRestoreRequest ... - ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRecoveryTimeBasedRestoreRequest ObjectTypeBasicAzureBackupRestoreRequest = "AzureBackupRecoveryTimeBasedRestoreRequest" - // ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRestoreRequest ... - ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRestoreRequest ObjectTypeBasicAzureBackupRestoreRequest = "AzureBackupRestoreRequest" - // ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRestoreWithRehydrationRequest ... - ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRestoreWithRehydrationRequest ObjectTypeBasicAzureBackupRestoreRequest = "AzureBackupRestoreWithRehydrationRequest" -) - -// PossibleObjectTypeBasicAzureBackupRestoreRequestValues returns an array of possible values for the ObjectTypeBasicAzureBackupRestoreRequest const type. -func PossibleObjectTypeBasicAzureBackupRestoreRequestValues() []ObjectTypeBasicAzureBackupRestoreRequest { - return []ObjectTypeBasicAzureBackupRestoreRequest{ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRecoveryPointBasedRestoreRequest, ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRecoveryTimeBasedRestoreRequest, ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRestoreRequest, ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRestoreWithRehydrationRequest} -} - -// ObjectTypeBasicBackupCriteria enumerates the values for object type basic backup criteria. -type ObjectTypeBasicBackupCriteria string - -const ( - // ObjectTypeBasicBackupCriteriaObjectTypeBackupCriteria ... - ObjectTypeBasicBackupCriteriaObjectTypeBackupCriteria ObjectTypeBasicBackupCriteria = "BackupCriteria" - // ObjectTypeBasicBackupCriteriaObjectTypeScheduleBasedBackupCriteria ... - ObjectTypeBasicBackupCriteriaObjectTypeScheduleBasedBackupCriteria ObjectTypeBasicBackupCriteria = "ScheduleBasedBackupCriteria" -) - -// PossibleObjectTypeBasicBackupCriteriaValues returns an array of possible values for the ObjectTypeBasicBackupCriteria const type. -func PossibleObjectTypeBasicBackupCriteriaValues() []ObjectTypeBasicBackupCriteria { - return []ObjectTypeBasicBackupCriteria{ObjectTypeBasicBackupCriteriaObjectTypeBackupCriteria, ObjectTypeBasicBackupCriteriaObjectTypeScheduleBasedBackupCriteria} -} - -// ObjectTypeBasicBackupParameters enumerates the values for object type basic backup parameters. -type ObjectTypeBasicBackupParameters string - -const ( - // ObjectTypeBasicBackupParametersObjectTypeAzureBackupParams ... - ObjectTypeBasicBackupParametersObjectTypeAzureBackupParams ObjectTypeBasicBackupParameters = "AzureBackupParams" - // ObjectTypeBasicBackupParametersObjectTypeBackupParameters ... - ObjectTypeBasicBackupParametersObjectTypeBackupParameters ObjectTypeBasicBackupParameters = "BackupParameters" -) - -// PossibleObjectTypeBasicBackupParametersValues returns an array of possible values for the ObjectTypeBasicBackupParameters const type. -func PossibleObjectTypeBasicBackupParametersValues() []ObjectTypeBasicBackupParameters { - return []ObjectTypeBasicBackupParameters{ObjectTypeBasicBackupParametersObjectTypeAzureBackupParams, ObjectTypeBasicBackupParametersObjectTypeBackupParameters} -} - -// ObjectTypeBasicBaseBackupPolicy enumerates the values for object type basic base backup policy. -type ObjectTypeBasicBaseBackupPolicy string - -const ( - // ObjectTypeBasicBaseBackupPolicyObjectTypeBackupPolicy ... - ObjectTypeBasicBaseBackupPolicyObjectTypeBackupPolicy ObjectTypeBasicBaseBackupPolicy = "BackupPolicy" - // ObjectTypeBasicBaseBackupPolicyObjectTypeBaseBackupPolicy ... - ObjectTypeBasicBaseBackupPolicyObjectTypeBaseBackupPolicy ObjectTypeBasicBaseBackupPolicy = "BaseBackupPolicy" -) - -// PossibleObjectTypeBasicBaseBackupPolicyValues returns an array of possible values for the ObjectTypeBasicBaseBackupPolicy const type. -func PossibleObjectTypeBasicBaseBackupPolicyValues() []ObjectTypeBasicBaseBackupPolicy { - return []ObjectTypeBasicBaseBackupPolicy{ObjectTypeBasicBaseBackupPolicyObjectTypeBackupPolicy, ObjectTypeBasicBaseBackupPolicyObjectTypeBaseBackupPolicy} -} - -// ObjectTypeBasicBasePolicyRule enumerates the values for object type basic base policy rule. -type ObjectTypeBasicBasePolicyRule string - -const ( - // ObjectTypeBasicBasePolicyRuleObjectTypeAzureBackupRule ... - ObjectTypeBasicBasePolicyRuleObjectTypeAzureBackupRule ObjectTypeBasicBasePolicyRule = "AzureBackupRule" - // ObjectTypeBasicBasePolicyRuleObjectTypeAzureRetentionRule ... - ObjectTypeBasicBasePolicyRuleObjectTypeAzureRetentionRule ObjectTypeBasicBasePolicyRule = "AzureRetentionRule" - // ObjectTypeBasicBasePolicyRuleObjectTypeBasePolicyRule ... - ObjectTypeBasicBasePolicyRuleObjectTypeBasePolicyRule ObjectTypeBasicBasePolicyRule = "BasePolicyRule" -) - -// PossibleObjectTypeBasicBasePolicyRuleValues returns an array of possible values for the ObjectTypeBasicBasePolicyRule const type. -func PossibleObjectTypeBasicBasePolicyRuleValues() []ObjectTypeBasicBasePolicyRule { - return []ObjectTypeBasicBasePolicyRule{ObjectTypeBasicBasePolicyRuleObjectTypeAzureBackupRule, ObjectTypeBasicBasePolicyRuleObjectTypeAzureRetentionRule, ObjectTypeBasicBasePolicyRuleObjectTypeBasePolicyRule} -} - -// ObjectTypeBasicCopyOption enumerates the values for object type basic copy option. -type ObjectTypeBasicCopyOption string - -const ( - // ObjectTypeBasicCopyOptionObjectTypeCopyOnExpiryOption ... - ObjectTypeBasicCopyOptionObjectTypeCopyOnExpiryOption ObjectTypeBasicCopyOption = "CopyOnExpiryOption" - // ObjectTypeBasicCopyOptionObjectTypeCopyOption ... - ObjectTypeBasicCopyOptionObjectTypeCopyOption ObjectTypeBasicCopyOption = "CopyOption" - // ObjectTypeBasicCopyOptionObjectTypeCustomCopyOption ... - ObjectTypeBasicCopyOptionObjectTypeCustomCopyOption ObjectTypeBasicCopyOption = "CustomCopyOption" - // ObjectTypeBasicCopyOptionObjectTypeImmediateCopyOption ... - ObjectTypeBasicCopyOptionObjectTypeImmediateCopyOption ObjectTypeBasicCopyOption = "ImmediateCopyOption" -) - -// PossibleObjectTypeBasicCopyOptionValues returns an array of possible values for the ObjectTypeBasicCopyOption const type. -func PossibleObjectTypeBasicCopyOptionValues() []ObjectTypeBasicCopyOption { - return []ObjectTypeBasicCopyOption{ObjectTypeBasicCopyOptionObjectTypeCopyOnExpiryOption, ObjectTypeBasicCopyOptionObjectTypeCopyOption, ObjectTypeBasicCopyOptionObjectTypeCustomCopyOption, ObjectTypeBasicCopyOptionObjectTypeImmediateCopyOption} -} - -// ObjectTypeBasicDataStoreParameters enumerates the values for object type basic data store parameters. -type ObjectTypeBasicDataStoreParameters string - -const ( - // ObjectTypeBasicDataStoreParametersObjectTypeAzureOperationalStoreParameters ... - ObjectTypeBasicDataStoreParametersObjectTypeAzureOperationalStoreParameters ObjectTypeBasicDataStoreParameters = "AzureOperationalStoreParameters" - // ObjectTypeBasicDataStoreParametersObjectTypeDataStoreParameters ... - ObjectTypeBasicDataStoreParametersObjectTypeDataStoreParameters ObjectTypeBasicDataStoreParameters = "DataStoreParameters" -) - -// PossibleObjectTypeBasicDataStoreParametersValues returns an array of possible values for the ObjectTypeBasicDataStoreParameters const type. -func PossibleObjectTypeBasicDataStoreParametersValues() []ObjectTypeBasicDataStoreParameters { - return []ObjectTypeBasicDataStoreParameters{ObjectTypeBasicDataStoreParametersObjectTypeAzureOperationalStoreParameters, ObjectTypeBasicDataStoreParametersObjectTypeDataStoreParameters} -} - -// ObjectTypeBasicDeleteOption enumerates the values for object type basic delete option. -type ObjectTypeBasicDeleteOption string - -const ( - // ObjectTypeBasicDeleteOptionObjectTypeAbsoluteDeleteOption ... - ObjectTypeBasicDeleteOptionObjectTypeAbsoluteDeleteOption ObjectTypeBasicDeleteOption = "AbsoluteDeleteOption" - // ObjectTypeBasicDeleteOptionObjectTypeDeleteOption ... - ObjectTypeBasicDeleteOptionObjectTypeDeleteOption ObjectTypeBasicDeleteOption = "DeleteOption" -) - -// PossibleObjectTypeBasicDeleteOptionValues returns an array of possible values for the ObjectTypeBasicDeleteOption const type. -func PossibleObjectTypeBasicDeleteOptionValues() []ObjectTypeBasicDeleteOption { - return []ObjectTypeBasicDeleteOption{ObjectTypeBasicDeleteOptionObjectTypeAbsoluteDeleteOption, ObjectTypeBasicDeleteOptionObjectTypeDeleteOption} -} - -// ObjectTypeBasicFeatureValidationRequestBase enumerates the values for object type basic feature validation -// request base. -type ObjectTypeBasicFeatureValidationRequestBase string - -const ( - // ObjectTypeBasicFeatureValidationRequestBaseObjectTypeFeatureValidationRequest ... - ObjectTypeBasicFeatureValidationRequestBaseObjectTypeFeatureValidationRequest ObjectTypeBasicFeatureValidationRequestBase = "FeatureValidationRequest" - // ObjectTypeBasicFeatureValidationRequestBaseObjectTypeFeatureValidationRequestBase ... - ObjectTypeBasicFeatureValidationRequestBaseObjectTypeFeatureValidationRequestBase ObjectTypeBasicFeatureValidationRequestBase = "FeatureValidationRequestBase" -) - -// PossibleObjectTypeBasicFeatureValidationRequestBaseValues returns an array of possible values for the ObjectTypeBasicFeatureValidationRequestBase const type. -func PossibleObjectTypeBasicFeatureValidationRequestBaseValues() []ObjectTypeBasicFeatureValidationRequestBase { - return []ObjectTypeBasicFeatureValidationRequestBase{ObjectTypeBasicFeatureValidationRequestBaseObjectTypeFeatureValidationRequest, ObjectTypeBasicFeatureValidationRequestBaseObjectTypeFeatureValidationRequestBase} -} - -// ObjectTypeBasicFeatureValidationResponseBase enumerates the values for object type basic feature validation -// response base. -type ObjectTypeBasicFeatureValidationResponseBase string - -const ( - // ObjectTypeBasicFeatureValidationResponseBaseObjectTypeFeatureValidationResponse ... - ObjectTypeBasicFeatureValidationResponseBaseObjectTypeFeatureValidationResponse ObjectTypeBasicFeatureValidationResponseBase = "FeatureValidationResponse" - // ObjectTypeBasicFeatureValidationResponseBaseObjectTypeFeatureValidationResponseBase ... - ObjectTypeBasicFeatureValidationResponseBaseObjectTypeFeatureValidationResponseBase ObjectTypeBasicFeatureValidationResponseBase = "FeatureValidationResponseBase" -) - -// PossibleObjectTypeBasicFeatureValidationResponseBaseValues returns an array of possible values for the ObjectTypeBasicFeatureValidationResponseBase const type. -func PossibleObjectTypeBasicFeatureValidationResponseBaseValues() []ObjectTypeBasicFeatureValidationResponseBase { - return []ObjectTypeBasicFeatureValidationResponseBase{ObjectTypeBasicFeatureValidationResponseBaseObjectTypeFeatureValidationResponse, ObjectTypeBasicFeatureValidationResponseBaseObjectTypeFeatureValidationResponseBase} -} - -// ObjectTypeBasicItemLevelRestoreCriteria enumerates the values for object type basic item level restore -// criteria. -type ObjectTypeBasicItemLevelRestoreCriteria string - -const ( - // ObjectTypeBasicItemLevelRestoreCriteriaObjectTypeItemLevelRestoreCriteria ... - ObjectTypeBasicItemLevelRestoreCriteriaObjectTypeItemLevelRestoreCriteria ObjectTypeBasicItemLevelRestoreCriteria = "ItemLevelRestoreCriteria" - // ObjectTypeBasicItemLevelRestoreCriteriaObjectTypeRangeBasedItemLevelRestoreCriteria ... - ObjectTypeBasicItemLevelRestoreCriteriaObjectTypeRangeBasedItemLevelRestoreCriteria ObjectTypeBasicItemLevelRestoreCriteria = "RangeBasedItemLevelRestoreCriteria" -) - -// PossibleObjectTypeBasicItemLevelRestoreCriteriaValues returns an array of possible values for the ObjectTypeBasicItemLevelRestoreCriteria const type. -func PossibleObjectTypeBasicItemLevelRestoreCriteriaValues() []ObjectTypeBasicItemLevelRestoreCriteria { - return []ObjectTypeBasicItemLevelRestoreCriteria{ObjectTypeBasicItemLevelRestoreCriteriaObjectTypeItemLevelRestoreCriteria, ObjectTypeBasicItemLevelRestoreCriteriaObjectTypeRangeBasedItemLevelRestoreCriteria} -} - -// ObjectTypeBasicOperationExtendedInfo enumerates the values for object type basic operation extended info. -type ObjectTypeBasicOperationExtendedInfo string - -const ( - // ObjectTypeBasicOperationExtendedInfoObjectTypeOperationExtendedInfo ... - ObjectTypeBasicOperationExtendedInfoObjectTypeOperationExtendedInfo ObjectTypeBasicOperationExtendedInfo = "OperationExtendedInfo" - // ObjectTypeBasicOperationExtendedInfoObjectTypeOperationJobExtendedInfo ... - ObjectTypeBasicOperationExtendedInfoObjectTypeOperationJobExtendedInfo ObjectTypeBasicOperationExtendedInfo = "OperationJobExtendedInfo" -) - -// PossibleObjectTypeBasicOperationExtendedInfoValues returns an array of possible values for the ObjectTypeBasicOperationExtendedInfo const type. -func PossibleObjectTypeBasicOperationExtendedInfoValues() []ObjectTypeBasicOperationExtendedInfo { - return []ObjectTypeBasicOperationExtendedInfo{ObjectTypeBasicOperationExtendedInfoObjectTypeOperationExtendedInfo, ObjectTypeBasicOperationExtendedInfoObjectTypeOperationJobExtendedInfo} -} - -// ObjectTypeBasicRestoreTargetInfoBase enumerates the values for object type basic restore target info base. -type ObjectTypeBasicRestoreTargetInfoBase string - -const ( - // ObjectTypeBasicRestoreTargetInfoBaseObjectTypeItemLevelRestoreTargetInfo ... - ObjectTypeBasicRestoreTargetInfoBaseObjectTypeItemLevelRestoreTargetInfo ObjectTypeBasicRestoreTargetInfoBase = "ItemLevelRestoreTargetInfo" - // ObjectTypeBasicRestoreTargetInfoBaseObjectTypeRestoreFilesTargetInfo ... - ObjectTypeBasicRestoreTargetInfoBaseObjectTypeRestoreFilesTargetInfo ObjectTypeBasicRestoreTargetInfoBase = "RestoreFilesTargetInfo" - // ObjectTypeBasicRestoreTargetInfoBaseObjectTypeRestoreTargetInfo ... - ObjectTypeBasicRestoreTargetInfoBaseObjectTypeRestoreTargetInfo ObjectTypeBasicRestoreTargetInfoBase = "RestoreTargetInfo" - // ObjectTypeBasicRestoreTargetInfoBaseObjectTypeRestoreTargetInfoBase ... - ObjectTypeBasicRestoreTargetInfoBaseObjectTypeRestoreTargetInfoBase ObjectTypeBasicRestoreTargetInfoBase = "RestoreTargetInfoBase" -) - -// PossibleObjectTypeBasicRestoreTargetInfoBaseValues returns an array of possible values for the ObjectTypeBasicRestoreTargetInfoBase const type. -func PossibleObjectTypeBasicRestoreTargetInfoBaseValues() []ObjectTypeBasicRestoreTargetInfoBase { - return []ObjectTypeBasicRestoreTargetInfoBase{ObjectTypeBasicRestoreTargetInfoBaseObjectTypeItemLevelRestoreTargetInfo, ObjectTypeBasicRestoreTargetInfoBaseObjectTypeRestoreFilesTargetInfo, ObjectTypeBasicRestoreTargetInfoBaseObjectTypeRestoreTargetInfo, ObjectTypeBasicRestoreTargetInfoBaseObjectTypeRestoreTargetInfoBase} -} - -// ObjectTypeBasicTriggerContext enumerates the values for object type basic trigger context. -type ObjectTypeBasicTriggerContext string - -const ( - // ObjectTypeBasicTriggerContextObjectTypeAdhocBasedTriggerContext ... - ObjectTypeBasicTriggerContextObjectTypeAdhocBasedTriggerContext ObjectTypeBasicTriggerContext = "AdhocBasedTriggerContext" - // ObjectTypeBasicTriggerContextObjectTypeScheduleBasedTriggerContext ... - ObjectTypeBasicTriggerContextObjectTypeScheduleBasedTriggerContext ObjectTypeBasicTriggerContext = "ScheduleBasedTriggerContext" - // ObjectTypeBasicTriggerContextObjectTypeTriggerContext ... - ObjectTypeBasicTriggerContextObjectTypeTriggerContext ObjectTypeBasicTriggerContext = "TriggerContext" -) - -// PossibleObjectTypeBasicTriggerContextValues returns an array of possible values for the ObjectTypeBasicTriggerContext const type. -func PossibleObjectTypeBasicTriggerContextValues() []ObjectTypeBasicTriggerContext { - return []ObjectTypeBasicTriggerContext{ObjectTypeBasicTriggerContextObjectTypeAdhocBasedTriggerContext, ObjectTypeBasicTriggerContextObjectTypeScheduleBasedTriggerContext, ObjectTypeBasicTriggerContextObjectTypeTriggerContext} -} - -// ProvisioningState enumerates the values for provisioning state. -type ProvisioningState string - -const ( - // ProvisioningStateFailed ... - ProvisioningStateFailed ProvisioningState = "Failed" - // ProvisioningStateProvisioning ... - ProvisioningStateProvisioning ProvisioningState = "Provisioning" - // ProvisioningStateSucceeded ... - ProvisioningStateSucceeded ProvisioningState = "Succeeded" - // ProvisioningStateUnknown ... - ProvisioningStateUnknown ProvisioningState = "Unknown" - // ProvisioningStateUpdating ... - ProvisioningStateUpdating ProvisioningState = "Updating" -) - -// PossibleProvisioningStateValues returns an array of possible values for the ProvisioningState const type. -func PossibleProvisioningStateValues() []ProvisioningState { - return []ProvisioningState{ProvisioningStateFailed, ProvisioningStateProvisioning, ProvisioningStateSucceeded, ProvisioningStateUnknown, ProvisioningStateUpdating} -} - -// RehydrationPriority enumerates the values for rehydration priority. -type RehydrationPriority string - -const ( - // RehydrationPriorityHigh ... - RehydrationPriorityHigh RehydrationPriority = "High" - // RehydrationPriorityInvalid ... - RehydrationPriorityInvalid RehydrationPriority = "Invalid" - // RehydrationPriorityStandard ... - RehydrationPriorityStandard RehydrationPriority = "Standard" -) - -// PossibleRehydrationPriorityValues returns an array of possible values for the RehydrationPriority const type. -func PossibleRehydrationPriorityValues() []RehydrationPriority { - return []RehydrationPriority{RehydrationPriorityHigh, RehydrationPriorityInvalid, RehydrationPriorityStandard} -} - -// RehydrationStatus enumerates the values for rehydration status. -type RehydrationStatus string - -const ( - // RehydrationStatusCOMPLETED ... - RehydrationStatusCOMPLETED RehydrationStatus = "COMPLETED" - // RehydrationStatusCREATEINPROGRESS ... - RehydrationStatusCREATEINPROGRESS RehydrationStatus = "CREATE_IN_PROGRESS" - // RehydrationStatusDELETED ... - RehydrationStatusDELETED RehydrationStatus = "DELETED" - // RehydrationStatusDELETEINPROGRESS ... - RehydrationStatusDELETEINPROGRESS RehydrationStatus = "DELETE_IN_PROGRESS" - // RehydrationStatusFAILED ... - RehydrationStatusFAILED RehydrationStatus = "FAILED" -) - -// PossibleRehydrationStatusValues returns an array of possible values for the RehydrationStatus const type. -func PossibleRehydrationStatusValues() []RehydrationStatus { - return []RehydrationStatus{RehydrationStatusCOMPLETED, RehydrationStatusCREATEINPROGRESS, RehydrationStatusDELETED, RehydrationStatusDELETEINPROGRESS, RehydrationStatusFAILED} -} - -// ResourceMoveState enumerates the values for resource move state. -type ResourceMoveState string - -const ( - // ResourceMoveStateCommitFailed ... - ResourceMoveStateCommitFailed ResourceMoveState = "CommitFailed" - // ResourceMoveStateCommitTimedout ... - ResourceMoveStateCommitTimedout ResourceMoveState = "CommitTimedout" - // ResourceMoveStateCriticalFailure ... - ResourceMoveStateCriticalFailure ResourceMoveState = "CriticalFailure" - // ResourceMoveStateFailed ... - ResourceMoveStateFailed ResourceMoveState = "Failed" - // ResourceMoveStateInProgress ... - ResourceMoveStateInProgress ResourceMoveState = "InProgress" - // ResourceMoveStateMoveSucceeded ... - ResourceMoveStateMoveSucceeded ResourceMoveState = "MoveSucceeded" - // ResourceMoveStatePartialSuccess ... - ResourceMoveStatePartialSuccess ResourceMoveState = "PartialSuccess" - // ResourceMoveStatePrepareFailed ... - ResourceMoveStatePrepareFailed ResourceMoveState = "PrepareFailed" - // ResourceMoveStatePrepareTimedout ... - ResourceMoveStatePrepareTimedout ResourceMoveState = "PrepareTimedout" - // ResourceMoveStateUnknown ... - ResourceMoveStateUnknown ResourceMoveState = "Unknown" -) - -// PossibleResourceMoveStateValues returns an array of possible values for the ResourceMoveState const type. -func PossibleResourceMoveStateValues() []ResourceMoveState { - return []ResourceMoveState{ResourceMoveStateCommitFailed, ResourceMoveStateCommitTimedout, ResourceMoveStateCriticalFailure, ResourceMoveStateFailed, ResourceMoveStateInProgress, ResourceMoveStateMoveSucceeded, ResourceMoveStatePartialSuccess, ResourceMoveStatePrepareFailed, ResourceMoveStatePrepareTimedout, ResourceMoveStateUnknown} -} - -// RestoreSourceDataStoreType enumerates the values for restore source data store type. -type RestoreSourceDataStoreType string - -const ( - // RestoreSourceDataStoreTypeArchiveStore ... - RestoreSourceDataStoreTypeArchiveStore RestoreSourceDataStoreType = "ArchiveStore" - // RestoreSourceDataStoreTypeOperationalStore ... - RestoreSourceDataStoreTypeOperationalStore RestoreSourceDataStoreType = "OperationalStore" - // RestoreSourceDataStoreTypeVaultStore ... - RestoreSourceDataStoreTypeVaultStore RestoreSourceDataStoreType = "VaultStore" -) - -// PossibleRestoreSourceDataStoreTypeValues returns an array of possible values for the RestoreSourceDataStoreType const type. -func PossibleRestoreSourceDataStoreTypeValues() []RestoreSourceDataStoreType { - return []RestoreSourceDataStoreType{RestoreSourceDataStoreTypeArchiveStore, RestoreSourceDataStoreTypeOperationalStore, RestoreSourceDataStoreTypeVaultStore} -} - -// RestoreTargetLocationType enumerates the values for restore target location type. -type RestoreTargetLocationType string - -const ( - // RestoreTargetLocationTypeAzureBlobs ... - RestoreTargetLocationTypeAzureBlobs RestoreTargetLocationType = "AzureBlobs" - // RestoreTargetLocationTypeAzureFiles ... - RestoreTargetLocationTypeAzureFiles RestoreTargetLocationType = "AzureFiles" - // RestoreTargetLocationTypeInvalid ... - RestoreTargetLocationTypeInvalid RestoreTargetLocationType = "Invalid" -) - -// PossibleRestoreTargetLocationTypeValues returns an array of possible values for the RestoreTargetLocationType const type. -func PossibleRestoreTargetLocationTypeValues() []RestoreTargetLocationType { - return []RestoreTargetLocationType{RestoreTargetLocationTypeAzureBlobs, RestoreTargetLocationTypeAzureFiles, RestoreTargetLocationTypeInvalid} -} - -// SecretStoreType enumerates the values for secret store type. -type SecretStoreType string - -const ( - // SecretStoreTypeAzureKeyVault ... - SecretStoreTypeAzureKeyVault SecretStoreType = "AzureKeyVault" - // SecretStoreTypeInvalid ... - SecretStoreTypeInvalid SecretStoreType = "Invalid" -) - -// PossibleSecretStoreTypeValues returns an array of possible values for the SecretStoreType const type. -func PossibleSecretStoreTypeValues() []SecretStoreType { - return []SecretStoreType{SecretStoreTypeAzureKeyVault, SecretStoreTypeInvalid} -} - -// SourceDataStoreType enumerates the values for source data store type. -type SourceDataStoreType string - -const ( - // SourceDataStoreTypeArchiveStore ... - SourceDataStoreTypeArchiveStore SourceDataStoreType = "ArchiveStore" - // SourceDataStoreTypeSnapshotStore ... - SourceDataStoreTypeSnapshotStore SourceDataStoreType = "SnapshotStore" - // SourceDataStoreTypeVaultStore ... - SourceDataStoreTypeVaultStore SourceDataStoreType = "VaultStore" -) - -// PossibleSourceDataStoreTypeValues returns an array of possible values for the SourceDataStoreType const type. -func PossibleSourceDataStoreTypeValues() []SourceDataStoreType { - return []SourceDataStoreType{SourceDataStoreTypeArchiveStore, SourceDataStoreTypeSnapshotStore, SourceDataStoreTypeVaultStore} -} - -// Status enumerates the values for status. -type Status string - -const ( - // StatusConfiguringProtection ... - StatusConfiguringProtection Status = "ConfiguringProtection" - // StatusConfiguringProtectionFailed ... - StatusConfiguringProtectionFailed Status = "ConfiguringProtectionFailed" - // StatusProtectionConfigured ... - StatusProtectionConfigured Status = "ProtectionConfigured" - // StatusProtectionStopped ... - StatusProtectionStopped Status = "ProtectionStopped" - // StatusSoftDeleted ... - StatusSoftDeleted Status = "SoftDeleted" - // StatusSoftDeleting ... - StatusSoftDeleting Status = "SoftDeleting" -) - -// PossibleStatusValues returns an array of possible values for the Status const type. -func PossibleStatusValues() []Status { - return []Status{StatusConfiguringProtection, StatusConfiguringProtectionFailed, StatusProtectionConfigured, StatusProtectionStopped, StatusSoftDeleted, StatusSoftDeleting} -} - -// StorageSettingStoreTypes enumerates the values for storage setting store types. -type StorageSettingStoreTypes string - -const ( - // StorageSettingStoreTypesArchiveStore ... - StorageSettingStoreTypesArchiveStore StorageSettingStoreTypes = "ArchiveStore" - // StorageSettingStoreTypesSnapshotStore ... - StorageSettingStoreTypesSnapshotStore StorageSettingStoreTypes = "SnapshotStore" - // StorageSettingStoreTypesVaultStore ... - StorageSettingStoreTypesVaultStore StorageSettingStoreTypes = "VaultStore" -) - -// PossibleStorageSettingStoreTypesValues returns an array of possible values for the StorageSettingStoreTypes const type. -func PossibleStorageSettingStoreTypesValues() []StorageSettingStoreTypes { - return []StorageSettingStoreTypes{StorageSettingStoreTypesArchiveStore, StorageSettingStoreTypesSnapshotStore, StorageSettingStoreTypesVaultStore} -} - -// StorageSettingTypes enumerates the values for storage setting types. -type StorageSettingTypes string - -const ( - // StorageSettingTypesGeoRedundant ... - StorageSettingTypesGeoRedundant StorageSettingTypes = "GeoRedundant" - // StorageSettingTypesLocallyRedundant ... - StorageSettingTypesLocallyRedundant StorageSettingTypes = "LocallyRedundant" -) - -// PossibleStorageSettingTypesValues returns an array of possible values for the StorageSettingTypes const type. -func PossibleStorageSettingTypesValues() []StorageSettingTypes { - return []StorageSettingTypes{StorageSettingTypesGeoRedundant, StorageSettingTypesLocallyRedundant} -} - -// WeekNumber enumerates the values for week number. -type WeekNumber string - -const ( - // WeekNumberFirst ... - WeekNumberFirst WeekNumber = "First" - // WeekNumberFourth ... - WeekNumberFourth WeekNumber = "Fourth" - // WeekNumberLast ... - WeekNumberLast WeekNumber = "Last" - // WeekNumberSecond ... - WeekNumberSecond WeekNumber = "Second" - // WeekNumberThird ... - WeekNumberThird WeekNumber = "Third" -) - -// PossibleWeekNumberValues returns an array of possible values for the WeekNumber const type. -func PossibleWeekNumberValues() []WeekNumber { - return []WeekNumber{WeekNumberFirst, WeekNumberFourth, WeekNumberLast, WeekNumberSecond, WeekNumberThird} -} diff --git a/internal/services/dataprotection/legacysdk/dataprotection/exportjobs.go b/internal/services/dataprotection/legacysdk/dataprotection/exportjobs.go deleted file mode 100644 index c99af74ac9d3..000000000000 --- a/internal/services/dataprotection/legacysdk/dataprotection/exportjobs.go +++ /dev/null @@ -1,109 +0,0 @@ -package dataprotection - -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. -// -// Code generated by Microsoft (R) AutoRest Code Generator. -// Changes may cause incorrect behavior and will be lost if the code is regenerated. - -import ( - "context" - "net/http" - - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/azure" - "github.com/Azure/go-autorest/tracing" -) - -// ExportJobsClient is the open API 2.0 Specs for Azure Data Protection service -type ExportJobsClient struct { - BaseClient -} - -// NewExportJobsClient creates an instance of the ExportJobsClient client. -func NewExportJobsClient(subscriptionID string) ExportJobsClient { - return NewExportJobsClientWithBaseURI(DefaultBaseURI, subscriptionID) -} - -// NewExportJobsClientWithBaseURI creates an instance of the ExportJobsClient client using a custom endpoint. Use this -// when interacting with an Azure cloud that uses a non-standard base URI (sovereign clouds, Azure stack). -func NewExportJobsClientWithBaseURI(baseURI string, subscriptionID string) ExportJobsClient { - return ExportJobsClient{NewWithBaseURI(baseURI, subscriptionID)} -} - -// Trigger triggers export of jobs and returns an OperationID to track. -// Parameters: -// resourceGroupName - the name of the resource group where the backup vault is present. -// vaultName - the name of the backup vault. -func (client ExportJobsClient) Trigger(ctx context.Context, resourceGroupName string, vaultName string) (result ExportJobsTriggerFuture, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/ExportJobsClient.Trigger") - defer func() { - sc := -1 - if result.FutureAPI != nil && result.FutureAPI.Response() != nil { - sc = result.FutureAPI.Response().StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - req, err := client.TriggerPreparer(ctx, resourceGroupName, vaultName) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ExportJobsClient", "Trigger", nil, "Failure preparing request") - return - } - - result, err = client.TriggerSender(req) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ExportJobsClient", "Trigger", nil, "Failure sending request") - return - } - - return -} - -// TriggerPreparer prepares the Trigger request. -func (client ExportJobsClient) TriggerPreparer(ctx context.Context, resourceGroupName string, vaultName string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - "vaultName": autorest.Encode("path", vaultName), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsPost(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/backupVaults/{vaultName}/exportBackupJobs", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// TriggerSender sends the Trigger request. The method will close the -// http.Response Body if it receives an error. -func (client ExportJobsClient) TriggerSender(req *http.Request) (future ExportJobsTriggerFuture, err error) { - var resp *http.Response - resp, err = client.Send(req, azure.DoRetryWithRegistration(client.Client)) - if err != nil { - return - } - var azf azure.Future - azf, err = azure.NewFutureFromResponse(resp) - future.FutureAPI = &azf - future.Result = future.result - return -} - -// TriggerResponder handles the response to the Trigger request. The method always -// closes the http.Response Body. -func (client ExportJobsClient) TriggerResponder(resp *http.Response) (result autorest.Response, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusAccepted, http.StatusNoContent), - autorest.ByClosing()) - result.Response = resp - return -} diff --git a/internal/services/dataprotection/legacysdk/dataprotection/exportjobsoperationresult.go b/internal/services/dataprotection/legacysdk/dataprotection/exportjobsoperationresult.go deleted file mode 100644 index 03e70773d694..000000000000 --- a/internal/services/dataprotection/legacysdk/dataprotection/exportjobsoperationresult.go +++ /dev/null @@ -1,113 +0,0 @@ -package dataprotection - -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. -// -// Code generated by Microsoft (R) AutoRest Code Generator. -// Changes may cause incorrect behavior and will be lost if the code is regenerated. - -import ( - "context" - "net/http" - - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/azure" - "github.com/Azure/go-autorest/tracing" -) - -// ExportJobsOperationResultClient is the open API 2.0 Specs for Azure Data Protection service -type ExportJobsOperationResultClient struct { - BaseClient -} - -// NewExportJobsOperationResultClient creates an instance of the ExportJobsOperationResultClient client. -func NewExportJobsOperationResultClient(subscriptionID string) ExportJobsOperationResultClient { - return NewExportJobsOperationResultClientWithBaseURI(DefaultBaseURI, subscriptionID) -} - -// NewExportJobsOperationResultClientWithBaseURI creates an instance of the ExportJobsOperationResultClient client -// using a custom endpoint. Use this when interacting with an Azure cloud that uses a non-standard base URI (sovereign -// clouds, Azure stack). -func NewExportJobsOperationResultClientWithBaseURI(baseURI string, subscriptionID string) ExportJobsOperationResultClient { - return ExportJobsOperationResultClient{NewWithBaseURI(baseURI, subscriptionID)} -} - -// Get gets the operation result of operation triggered by Export Jobs API. If the operation is successful, then it -// also contains URL of a Blob and a SAS key to access the same. The blob contains exported jobs in JSON serialized -// format. -// Parameters: -// resourceGroupName - the name of the resource group where the backup vault is present. -// vaultName - the name of the backup vault. -// operationID - operationID which represents the export job. -func (client ExportJobsOperationResultClient) Get(ctx context.Context, resourceGroupName string, vaultName string, operationID string) (result ExportJobsResult, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/ExportJobsOperationResultClient.Get") - defer func() { - sc := -1 - if result.Response.Response != nil { - sc = result.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - req, err := client.GetPreparer(ctx, resourceGroupName, vaultName, operationID) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ExportJobsOperationResultClient", "Get", nil, "Failure preparing request") - return - } - - resp, err := client.GetSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.ExportJobsOperationResultClient", "Get", resp, "Failure sending request") - return - } - - result, err = client.GetResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ExportJobsOperationResultClient", "Get", resp, "Failure responding to request") - return - } - - return -} - -// GetPreparer prepares the Get request. -func (client ExportJobsOperationResultClient) GetPreparer(ctx context.Context, resourceGroupName string, vaultName string, operationID string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "operationId": autorest.Encode("path", operationID), - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - "vaultName": autorest.Encode("path", vaultName), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsGet(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/backupVaults/{vaultName}/backupJobs/operations/{operationId}", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// GetSender sends the Get request. The method will close the -// http.Response Body if it receives an error. -func (client ExportJobsOperationResultClient) GetSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// GetResponder handles the response to the Get request. The method always -// closes the http.Response Body. -func (client ExportJobsOperationResultClient) GetResponder(resp *http.Response) (result ExportJobsResult, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusAccepted), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} diff --git a/internal/services/dataprotection/legacysdk/dataprotection/jobs.go b/internal/services/dataprotection/legacysdk/dataprotection/jobs.go deleted file mode 100644 index e35e5a3f8966..000000000000 --- a/internal/services/dataprotection/legacysdk/dataprotection/jobs.go +++ /dev/null @@ -1,228 +0,0 @@ -package dataprotection - -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. -// -// Code generated by Microsoft (R) AutoRest Code Generator. -// Changes may cause incorrect behavior and will be lost if the code is regenerated. - -import ( - "context" - "net/http" - - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/azure" - "github.com/Azure/go-autorest/tracing" -) - -// JobsClient is the open API 2.0 Specs for Azure Data Protection service -type JobsClient struct { - BaseClient -} - -// NewJobsClient creates an instance of the JobsClient client. -func NewJobsClient(subscriptionID string) JobsClient { - return NewJobsClientWithBaseURI(DefaultBaseURI, subscriptionID) -} - -// NewJobsClientWithBaseURI creates an instance of the JobsClient client using a custom endpoint. Use this when -// interacting with an Azure cloud that uses a non-standard base URI (sovereign clouds, Azure stack). -func NewJobsClientWithBaseURI(baseURI string, subscriptionID string) JobsClient { - return JobsClient{NewWithBaseURI(baseURI, subscriptionID)} -} - -// Get gets a job with id in a backup vault -// Parameters: -// resourceGroupName - the name of the resource group where the backup vault is present. -// vaultName - the name of the backup vault. -// jobID - the Job ID. This is a GUID-formatted string (e.g. 00000000-0000-0000-0000-000000000000). -func (client JobsClient) Get(ctx context.Context, resourceGroupName string, vaultName string, jobID string) (result AzureBackupJobResource, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/JobsClient.Get") - defer func() { - sc := -1 - if result.Response.Response != nil { - sc = result.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - req, err := client.GetPreparer(ctx, resourceGroupName, vaultName, jobID) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.JobsClient", "Get", nil, "Failure preparing request") - return - } - - resp, err := client.GetSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.JobsClient", "Get", resp, "Failure sending request") - return - } - - result, err = client.GetResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.JobsClient", "Get", resp, "Failure responding to request") - return - } - - return -} - -// GetPreparer prepares the Get request. -func (client JobsClient) GetPreparer(ctx context.Context, resourceGroupName string, vaultName string, jobID string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "jobId": autorest.Encode("path", jobID), - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - "vaultName": autorest.Encode("path", vaultName), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsGet(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/backupVaults/{vaultName}/backupJobs/{jobId}", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// GetSender sends the Get request. The method will close the -// http.Response Body if it receives an error. -func (client JobsClient) GetSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// GetResponder handles the response to the Get request. The method always -// closes the http.Response Body. -func (client JobsClient) GetResponder(resp *http.Response) (result AzureBackupJobResource, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// List returns list of jobs belonging to a backup vault -// Parameters: -// resourceGroupName - the name of the resource group where the backup vault is present. -// vaultName - the name of the backup vault. -func (client JobsClient) List(ctx context.Context, resourceGroupName string, vaultName string) (result AzureBackupJobResourceListPage, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/JobsClient.List") - defer func() { - sc := -1 - if result.abjrl.Response.Response != nil { - sc = result.abjrl.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - result.fn = client.listNextResults - req, err := client.ListPreparer(ctx, resourceGroupName, vaultName) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.JobsClient", "List", nil, "Failure preparing request") - return - } - - resp, err := client.ListSender(req) - if err != nil { - result.abjrl.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.JobsClient", "List", resp, "Failure sending request") - return - } - - result.abjrl, err = client.ListResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.JobsClient", "List", resp, "Failure responding to request") - return - } - if result.abjrl.hasNextLink() && result.abjrl.IsEmpty() { - err = result.NextWithContext(ctx) - return - } - - return -} - -// ListPreparer prepares the List request. -func (client JobsClient) ListPreparer(ctx context.Context, resourceGroupName string, vaultName string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - "vaultName": autorest.Encode("path", vaultName), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsGet(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/backupVaults/{vaultName}/backupJobs", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// ListSender sends the List request. The method will close the -// http.Response Body if it receives an error. -func (client JobsClient) ListSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// ListResponder handles the response to the List request. The method always -// closes the http.Response Body. -func (client JobsClient) ListResponder(resp *http.Response) (result AzureBackupJobResourceList, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// listNextResults retrieves the next set of results, if any. -func (client JobsClient) listNextResults(ctx context.Context, lastResults AzureBackupJobResourceList) (result AzureBackupJobResourceList, err error) { - req, err := lastResults.azureBackupJobResourceListPreparer(ctx) - if err != nil { - return result, autorest.NewErrorWithError(err, "dataprotection.JobsClient", "listNextResults", nil, "Failure preparing next results request") - } - if req == nil { - return - } - resp, err := client.ListSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - return result, autorest.NewErrorWithError(err, "dataprotection.JobsClient", "listNextResults", resp, "Failure sending next results request") - } - result, err = client.ListResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.JobsClient", "listNextResults", resp, "Failure responding to next results request") - } - return -} - -// ListComplete enumerates all values, automatically crossing page boundaries as required. -func (client JobsClient) ListComplete(ctx context.Context, resourceGroupName string, vaultName string) (result AzureBackupJobResourceListIterator, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/JobsClient.List") - defer func() { - sc := -1 - if result.Response().Response.Response != nil { - sc = result.page.Response().Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - result.page, err = client.List(ctx, resourceGroupName, vaultName) - return -} diff --git a/internal/services/dataprotection/legacysdk/dataprotection/models.go b/internal/services/dataprotection/legacysdk/dataprotection/models.go deleted file mode 100644 index b42f46007610..000000000000 --- a/internal/services/dataprotection/legacysdk/dataprotection/models.go +++ /dev/null @@ -1,6462 +0,0 @@ -package dataprotection - -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. -// -// Code generated by Microsoft (R) AutoRest Code Generator. -// Changes may cause incorrect behavior and will be lost if the code is regenerated. - -import ( - "context" - "encoding/json" - "net/http" - - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/azure" - "github.com/Azure/go-autorest/autorest/date" - "github.com/Azure/go-autorest/autorest/to" - "github.com/Azure/go-autorest/tracing" -) - -// The package's fully qualified name. -const fqdn = "github.com/Azure/azure-sdk-for-go/services/dataprotection/mgmt/2021-07-01/dataprotection" - -// AbsoluteDeleteOption delete option with duration -type AbsoluteDeleteOption struct { - // Duration - Duration of deletion after given timespan - Duration *string `json:"duration,omitempty"` - // ObjectType - Possible values include: 'ObjectTypeBasicDeleteOptionObjectTypeDeleteOption', 'ObjectTypeBasicDeleteOptionObjectTypeAbsoluteDeleteOption' - ObjectType ObjectTypeBasicDeleteOption `json:"objectType,omitempty"` -} - -// MarshalJSON is the custom marshaler for AbsoluteDeleteOption. -func (ado AbsoluteDeleteOption) MarshalJSON() ([]byte, error) { - ado.ObjectType = ObjectTypeBasicDeleteOptionObjectTypeAbsoluteDeleteOption - objectMap := make(map[string]interface{}) - if ado.Duration != nil { - objectMap["duration"] = ado.Duration - } - if ado.ObjectType != "" { - objectMap["objectType"] = ado.ObjectType - } - return json.Marshal(objectMap) -} - -// AsAbsoluteDeleteOption is the BasicDeleteOption implementation for AbsoluteDeleteOption. -func (ado AbsoluteDeleteOption) AsAbsoluteDeleteOption() (*AbsoluteDeleteOption, bool) { - return &ado, true -} - -// AsDeleteOption is the BasicDeleteOption implementation for AbsoluteDeleteOption. -func (ado AbsoluteDeleteOption) AsDeleteOption() (*DeleteOption, bool) { - return nil, false -} - -// AsBasicDeleteOption is the BasicDeleteOption implementation for AbsoluteDeleteOption. -func (ado AbsoluteDeleteOption) AsBasicDeleteOption() (BasicDeleteOption, bool) { - return &ado, true -} - -// AdHocBackupRuleOptions adhoc backup rules -type AdHocBackupRuleOptions struct { - RuleName *string `json:"ruleName,omitempty"` - TriggerOption *AdhocBackupTriggerOption `json:"triggerOption,omitempty"` -} - -// AdhocBackupTriggerOption adhoc backup trigger option -type AdhocBackupTriggerOption struct { - RetentionTagOverride *string `json:"retentionTagOverride,omitempty"` -} - -// AdhocBasedTaggingCriteria adhoc backup tagging criteria -type AdhocBasedTaggingCriteria struct { - // TagInfo - Retention tag information - TagInfo *RetentionTag `json:"tagInfo,omitempty"` -} - -// AdhocBasedTriggerContext adhoc trigger context -type AdhocBasedTriggerContext struct { - // TaggingCriteria - Tagging Criteria containing retention tag for adhoc backup. - TaggingCriteria *AdhocBasedTaggingCriteria `json:"taggingCriteria,omitempty"` - // ObjectType - Possible values include: 'ObjectTypeBasicTriggerContextObjectTypeTriggerContext', 'ObjectTypeBasicTriggerContextObjectTypeAdhocBasedTriggerContext', 'ObjectTypeBasicTriggerContextObjectTypeScheduleBasedTriggerContext' - ObjectType ObjectTypeBasicTriggerContext `json:"objectType,omitempty"` -} - -// MarshalJSON is the custom marshaler for AdhocBasedTriggerContext. -func (abtc AdhocBasedTriggerContext) MarshalJSON() ([]byte, error) { - abtc.ObjectType = ObjectTypeBasicTriggerContextObjectTypeAdhocBasedTriggerContext - objectMap := make(map[string]interface{}) - if abtc.TaggingCriteria != nil { - objectMap["taggingCriteria"] = abtc.TaggingCriteria - } - if abtc.ObjectType != "" { - objectMap["objectType"] = abtc.ObjectType - } - return json.Marshal(objectMap) -} - -// AsAdhocBasedTriggerContext is the BasicTriggerContext implementation for AdhocBasedTriggerContext. -func (abtc AdhocBasedTriggerContext) AsAdhocBasedTriggerContext() (*AdhocBasedTriggerContext, bool) { - return &abtc, true -} - -// AsScheduleBasedTriggerContext is the BasicTriggerContext implementation for AdhocBasedTriggerContext. -func (abtc AdhocBasedTriggerContext) AsScheduleBasedTriggerContext() (*ScheduleBasedTriggerContext, bool) { - return nil, false -} - -// AsTriggerContext is the BasicTriggerContext implementation for AdhocBasedTriggerContext. -func (abtc AdhocBasedTriggerContext) AsTriggerContext() (*TriggerContext, bool) { - return nil, false -} - -// AsBasicTriggerContext is the BasicTriggerContext implementation for AdhocBasedTriggerContext. -func (abtc AdhocBasedTriggerContext) AsBasicTriggerContext() (BasicTriggerContext, bool) { - return &abtc, true -} - -// BasicAuthCredentials base class for different types of authentication credentials. -type BasicAuthCredentials interface { - AsSecretStoreBasedAuthCredentials() (*SecretStoreBasedAuthCredentials, bool) - AsAuthCredentials() (*AuthCredentials, bool) -} - -// AuthCredentials base class for different types of authentication credentials. -type AuthCredentials struct { - // ObjectType - Possible values include: 'ObjectTypeAuthCredentials', 'ObjectTypeSecretStoreBasedAuthCredentials' - ObjectType ObjectType `json:"objectType,omitempty"` -} - -func unmarshalBasicAuthCredentials(body []byte) (BasicAuthCredentials, error) { - var m map[string]interface{} - err := json.Unmarshal(body, &m) - if err != nil { - return nil, err - } - - switch m["objectType"] { - case string(ObjectTypeSecretStoreBasedAuthCredentials): - var ssbac SecretStoreBasedAuthCredentials - err := json.Unmarshal(body, &ssbac) - return ssbac, err - default: - var ac AuthCredentials - err := json.Unmarshal(body, &ac) - return ac, err - } -} - -func unmarshalBasicAuthCredentialsArray(body []byte) ([]BasicAuthCredentials, error) { - var rawMessages []*json.RawMessage - err := json.Unmarshal(body, &rawMessages) - if err != nil { - return nil, err - } - - acArray := make([]BasicAuthCredentials, len(rawMessages)) - - for index, rawMessage := range rawMessages { - ac, err := unmarshalBasicAuthCredentials(*rawMessage) - if err != nil { - return nil, err - } - acArray[index] = ac - } - return acArray, nil -} - -// MarshalJSON is the custom marshaler for AuthCredentials. -func (ac AuthCredentials) MarshalJSON() ([]byte, error) { - ac.ObjectType = ObjectTypeAuthCredentials - objectMap := make(map[string]interface{}) - if ac.ObjectType != "" { - objectMap["objectType"] = ac.ObjectType - } - return json.Marshal(objectMap) -} - -// AsSecretStoreBasedAuthCredentials is the BasicAuthCredentials implementation for AuthCredentials. -func (ac AuthCredentials) AsSecretStoreBasedAuthCredentials() (*SecretStoreBasedAuthCredentials, bool) { - return nil, false -} - -// AsAuthCredentials is the BasicAuthCredentials implementation for AuthCredentials. -func (ac AuthCredentials) AsAuthCredentials() (*AuthCredentials, bool) { - return &ac, true -} - -// AsBasicAuthCredentials is the BasicAuthCredentials implementation for AuthCredentials. -func (ac AuthCredentials) AsBasicAuthCredentials() (BasicAuthCredentials, bool) { - return &ac, true -} - -// AzureBackupDiscreteRecoveryPoint azure backup discrete RecoveryPoint -type AzureBackupDiscreteRecoveryPoint struct { - FriendlyName *string `json:"friendlyName,omitempty"` - RecoveryPointDataStoresDetails *[]RecoveryPointDataStoreDetails `json:"recoveryPointDataStoresDetails,omitempty"` - RecoveryPointTime *date.Time `json:"recoveryPointTime,omitempty"` - PolicyName *string `json:"policyName,omitempty"` - PolicyVersion *string `json:"policyVersion,omitempty"` - RecoveryPointID *string `json:"recoveryPointId,omitempty"` - RecoveryPointType *string `json:"recoveryPointType,omitempty"` - RetentionTagName *string `json:"retentionTagName,omitempty"` - RetentionTagVersion *string `json:"retentionTagVersion,omitempty"` - // ObjectType - Possible values include: 'ObjectTypeBasicAzureBackupRecoveryPointObjectTypeAzureBackupRecoveryPoint', 'ObjectTypeBasicAzureBackupRecoveryPointObjectTypeAzureBackupDiscreteRecoveryPoint' - ObjectType ObjectTypeBasicAzureBackupRecoveryPoint `json:"objectType,omitempty"` -} - -// MarshalJSON is the custom marshaler for AzureBackupDiscreteRecoveryPoint. -func (abdrp AzureBackupDiscreteRecoveryPoint) MarshalJSON() ([]byte, error) { - abdrp.ObjectType = ObjectTypeBasicAzureBackupRecoveryPointObjectTypeAzureBackupDiscreteRecoveryPoint - objectMap := make(map[string]interface{}) - if abdrp.FriendlyName != nil { - objectMap["friendlyName"] = abdrp.FriendlyName - } - if abdrp.RecoveryPointDataStoresDetails != nil { - objectMap["recoveryPointDataStoresDetails"] = abdrp.RecoveryPointDataStoresDetails - } - if abdrp.RecoveryPointTime != nil { - objectMap["recoveryPointTime"] = abdrp.RecoveryPointTime - } - if abdrp.PolicyName != nil { - objectMap["policyName"] = abdrp.PolicyName - } - if abdrp.PolicyVersion != nil { - objectMap["policyVersion"] = abdrp.PolicyVersion - } - if abdrp.RecoveryPointID != nil { - objectMap["recoveryPointId"] = abdrp.RecoveryPointID - } - if abdrp.RecoveryPointType != nil { - objectMap["recoveryPointType"] = abdrp.RecoveryPointType - } - if abdrp.RetentionTagName != nil { - objectMap["retentionTagName"] = abdrp.RetentionTagName - } - if abdrp.RetentionTagVersion != nil { - objectMap["retentionTagVersion"] = abdrp.RetentionTagVersion - } - if abdrp.ObjectType != "" { - objectMap["objectType"] = abdrp.ObjectType - } - return json.Marshal(objectMap) -} - -// AsAzureBackupDiscreteRecoveryPoint is the BasicAzureBackupRecoveryPoint implementation for AzureBackupDiscreteRecoveryPoint. -func (abdrp AzureBackupDiscreteRecoveryPoint) AsAzureBackupDiscreteRecoveryPoint() (*AzureBackupDiscreteRecoveryPoint, bool) { - return &abdrp, true -} - -// AsAzureBackupRecoveryPoint is the BasicAzureBackupRecoveryPoint implementation for AzureBackupDiscreteRecoveryPoint. -func (abdrp AzureBackupDiscreteRecoveryPoint) AsAzureBackupRecoveryPoint() (*AzureBackupRecoveryPoint, bool) { - return nil, false -} - -// AsBasicAzureBackupRecoveryPoint is the BasicAzureBackupRecoveryPoint implementation for AzureBackupDiscreteRecoveryPoint. -func (abdrp AzureBackupDiscreteRecoveryPoint) AsBasicAzureBackupRecoveryPoint() (BasicAzureBackupRecoveryPoint, bool) { - return &abdrp, true -} - -// AzureBackupFindRestorableTimeRangesRequest list Restore Ranges Request -type AzureBackupFindRestorableTimeRangesRequest struct { - // SourceDataStoreType - Gets or sets the type of the source data store. Possible values include: 'RestoreSourceDataStoreTypeOperationalStore', 'RestoreSourceDataStoreTypeVaultStore', 'RestoreSourceDataStoreTypeArchiveStore' - SourceDataStoreType RestoreSourceDataStoreType `json:"sourceDataStoreType,omitempty"` - // StartTime - Start time for the List Restore Ranges request. ISO 8601 format. - StartTime *string `json:"startTime,omitempty"` - // EndTime - End time for the List Restore Ranges request. ISO 8601 format. - EndTime *string `json:"endTime,omitempty"` -} - -// AzureBackupFindRestorableTimeRangesRequestResource list Restore Ranges Request -type AzureBackupFindRestorableTimeRangesRequestResource struct { - // Content - AzureBackupFindRestorableTimeRangesRequestResource content - Content *AzureBackupFindRestorableTimeRangesRequest `json:"content,omitempty"` - SubscriptionID *string `json:"subscriptionId,omitempty"` - URI *string `json:"uri,omitempty"` - Headers map[string][]string `json:"headers"` - SupportedGroupVersions *[]string `json:"supportedGroupVersions,omitempty"` - CultureInfo *string `json:"cultureInfo,omitempty"` - Parameters map[string]*string `json:"parameters"` - HTTPMethod *string `json:"httpMethod,omitempty"` -} - -// MarshalJSON is the custom marshaler for AzureBackupFindRestorableTimeRangesRequestResource. -func (abfrtrrr AzureBackupFindRestorableTimeRangesRequestResource) MarshalJSON() ([]byte, error) { - objectMap := make(map[string]interface{}) - if abfrtrrr.Content != nil { - objectMap["content"] = abfrtrrr.Content - } - if abfrtrrr.SubscriptionID != nil { - objectMap["subscriptionId"] = abfrtrrr.SubscriptionID - } - if abfrtrrr.URI != nil { - objectMap["uri"] = abfrtrrr.URI - } - if abfrtrrr.Headers != nil { - objectMap["headers"] = abfrtrrr.Headers - } - if abfrtrrr.SupportedGroupVersions != nil { - objectMap["supportedGroupVersions"] = abfrtrrr.SupportedGroupVersions - } - if abfrtrrr.CultureInfo != nil { - objectMap["cultureInfo"] = abfrtrrr.CultureInfo - } - if abfrtrrr.Parameters != nil { - objectMap["parameters"] = abfrtrrr.Parameters - } - if abfrtrrr.HTTPMethod != nil { - objectMap["httpMethod"] = abfrtrrr.HTTPMethod - } - return json.Marshal(objectMap) -} - -// AzureBackupFindRestorableTimeRangesResponse list Restore Ranges Response -type AzureBackupFindRestorableTimeRangesResponse struct { - // RestorableTimeRanges - Returns the Restore Ranges available on the Backup Instance. - RestorableTimeRanges *[]RestorableTimeRange `json:"restorableTimeRanges,omitempty"` - ObjectType *string `json:"objectType,omitempty"` -} - -// AzureBackupFindRestorableTimeRangesResponseResource list Restore Ranges Response -type AzureBackupFindRestorableTimeRangesResponseResource struct { - autorest.Response `json:"-"` - // Properties - AzureBackupFindRestorableTimeRangesResponseResource properties - Properties *AzureBackupFindRestorableTimeRangesResponse `json:"properties,omitempty"` - // ID - READ-ONLY; Resource Id represents the complete path to the resource. - ID *string `json:"id,omitempty"` - // Name - READ-ONLY; Resource name associated with the resource. - Name *string `json:"name,omitempty"` - // Type - READ-ONLY; Resource type represents the complete path of the form Namespace/ResourceType/ResourceType/... - Type *string `json:"type,omitempty"` - SystemData *SystemData `json:"systemData,omitempty"` -} - -// MarshalJSON is the custom marshaler for AzureBackupFindRestorableTimeRangesResponseResource. -func (abfrtrrr AzureBackupFindRestorableTimeRangesResponseResource) MarshalJSON() ([]byte, error) { - objectMap := make(map[string]interface{}) - if abfrtrrr.Properties != nil { - objectMap["properties"] = abfrtrrr.Properties - } - if abfrtrrr.SystemData != nil { - objectMap["systemData"] = abfrtrrr.SystemData - } - return json.Marshal(objectMap) -} - -// AzureBackupJob azureBackup Job Class -type AzureBackupJob struct { - // ActivityID - Job Activity Id - ActivityID *string `json:"activityID,omitempty"` - // BackupInstanceFriendlyName - Name of the Backup Instance - BackupInstanceFriendlyName *string `json:"backupInstanceFriendlyName,omitempty"` - // BackupInstanceID - READ-ONLY; ARM ID of the Backup Instance - BackupInstanceID *string `json:"backupInstanceId,omitempty"` - // DataSourceID - ARM ID of the DataSource - DataSourceID *string `json:"dataSourceId,omitempty"` - // DataSourceLocation - Location of the DataSource - DataSourceLocation *string `json:"dataSourceLocation,omitempty"` - // DataSourceName - User Friendly Name of the DataSource - DataSourceName *string `json:"dataSourceName,omitempty"` - // DataSourceSetName - Data Source Set Name of the DataSource - DataSourceSetName *string `json:"dataSourceSetName,omitempty"` - // DataSourceType - Type of DataSource - DataSourceType *string `json:"dataSourceType,omitempty"` - // Duration - Total run time of the job. ISO 8601 format. - Duration *string `json:"duration,omitempty"` - // EndTime - READ-ONLY; EndTime of the job(in UTC) - EndTime *date.Time `json:"endTime,omitempty"` - // ErrorDetails - READ-ONLY; A List, detailing the errors related to the job - ErrorDetails *[]UserFacingError `json:"errorDetails,omitempty"` - // ExtendedInfo - READ-ONLY; Extended Information about the job - ExtendedInfo *JobExtendedInfo `json:"extendedInfo,omitempty"` - // IsUserTriggered - Indicated that whether the job is adhoc(true) or scheduled(false) - IsUserTriggered *bool `json:"isUserTriggered,omitempty"` - // Operation - It indicates the type of Job i.e. Backup:full/log/diff ;Restore:ALR/OLR; Tiering:Backup/Archive ; Management:ConfigureProtection/UnConfigure - Operation *string `json:"operation,omitempty"` - // OperationCategory - It indicates the type of Job i.e. Backup/Restore/Tiering/Management - OperationCategory *string `json:"operationCategory,omitempty"` - // PolicyID - READ-ONLY; ARM ID of the policy - PolicyID *string `json:"policyId,omitempty"` - // PolicyName - READ-ONLY; Name of the policy - PolicyName *string `json:"policyName,omitempty"` - // ProgressEnabled - Indicated whether progress is enabled for the job - ProgressEnabled *bool `json:"progressEnabled,omitempty"` - // ProgressURL - READ-ONLY; Url which contains job's progress - ProgressURL *string `json:"progressUrl,omitempty"` - // RestoreType - READ-ONLY; It indicates the sub type of operation i.e. in case of Restore it can be ALR/OLR - RestoreType *string `json:"restoreType,omitempty"` - // SourceResourceGroup - Resource Group Name of the Datasource - SourceResourceGroup *string `json:"sourceResourceGroup,omitempty"` - // SourceSubscriptionID - SubscriptionId corresponding to the DataSource - SourceSubscriptionID *string `json:"sourceSubscriptionID,omitempty"` - // StartTime - StartTime of the job(in UTC) - StartTime *date.Time `json:"startTime,omitempty"` - // Status - Status of the job like InProgress/Success/Failed/Cancelled/SuccessWithWarning - Status *string `json:"status,omitempty"` - // SubscriptionID - Subscription Id of the corresponding backup vault - SubscriptionID *string `json:"subscriptionId,omitempty"` - // SupportedActions - List of supported actions - SupportedActions *[]string `json:"supportedActions,omitempty"` - // VaultName - Name of the vault - VaultName *string `json:"vaultName,omitempty"` - Etag *string `json:"etag,omitempty"` - SourceDataStoreName *string `json:"sourceDataStoreName,omitempty"` - DestinationDataStoreName *string `json:"destinationDataStoreName,omitempty"` -} - -// MarshalJSON is the custom marshaler for AzureBackupJob. -func (abj AzureBackupJob) MarshalJSON() ([]byte, error) { - objectMap := make(map[string]interface{}) - if abj.ActivityID != nil { - objectMap["activityID"] = abj.ActivityID - } - if abj.BackupInstanceFriendlyName != nil { - objectMap["backupInstanceFriendlyName"] = abj.BackupInstanceFriendlyName - } - if abj.DataSourceID != nil { - objectMap["dataSourceId"] = abj.DataSourceID - } - if abj.DataSourceLocation != nil { - objectMap["dataSourceLocation"] = abj.DataSourceLocation - } - if abj.DataSourceName != nil { - objectMap["dataSourceName"] = abj.DataSourceName - } - if abj.DataSourceSetName != nil { - objectMap["dataSourceSetName"] = abj.DataSourceSetName - } - if abj.DataSourceType != nil { - objectMap["dataSourceType"] = abj.DataSourceType - } - if abj.Duration != nil { - objectMap["duration"] = abj.Duration - } - if abj.IsUserTriggered != nil { - objectMap["isUserTriggered"] = abj.IsUserTriggered - } - if abj.Operation != nil { - objectMap["operation"] = abj.Operation - } - if abj.OperationCategory != nil { - objectMap["operationCategory"] = abj.OperationCategory - } - if abj.ProgressEnabled != nil { - objectMap["progressEnabled"] = abj.ProgressEnabled - } - if abj.SourceResourceGroup != nil { - objectMap["sourceResourceGroup"] = abj.SourceResourceGroup - } - if abj.SourceSubscriptionID != nil { - objectMap["sourceSubscriptionID"] = abj.SourceSubscriptionID - } - if abj.StartTime != nil { - objectMap["startTime"] = abj.StartTime - } - if abj.Status != nil { - objectMap["status"] = abj.Status - } - if abj.SubscriptionID != nil { - objectMap["subscriptionId"] = abj.SubscriptionID - } - if abj.SupportedActions != nil { - objectMap["supportedActions"] = abj.SupportedActions - } - if abj.VaultName != nil { - objectMap["vaultName"] = abj.VaultName - } - if abj.Etag != nil { - objectMap["etag"] = abj.Etag - } - if abj.SourceDataStoreName != nil { - objectMap["sourceDataStoreName"] = abj.SourceDataStoreName - } - if abj.DestinationDataStoreName != nil { - objectMap["destinationDataStoreName"] = abj.DestinationDataStoreName - } - return json.Marshal(objectMap) -} - -// AzureBackupJobResource azureBackup Job Resource Class -type AzureBackupJobResource struct { - autorest.Response `json:"-"` - // Properties - AzureBackupJobResource properties - Properties *AzureBackupJob `json:"properties,omitempty"` - // ID - READ-ONLY; Resource Id represents the complete path to the resource. - ID *string `json:"id,omitempty"` - // Name - READ-ONLY; Resource name associated with the resource. - Name *string `json:"name,omitempty"` - // Type - READ-ONLY; Resource type represents the complete path of the form Namespace/ResourceType/ResourceType/... - Type *string `json:"type,omitempty"` - SystemData *SystemData `json:"systemData,omitempty"` -} - -// MarshalJSON is the custom marshaler for AzureBackupJobResource. -func (abjr AzureBackupJobResource) MarshalJSON() ([]byte, error) { - objectMap := make(map[string]interface{}) - if abjr.Properties != nil { - objectMap["properties"] = abjr.Properties - } - if abjr.SystemData != nil { - objectMap["systemData"] = abjr.SystemData - } - return json.Marshal(objectMap) -} - -// AzureBackupJobResourceList list of AzureBackup Job resources -type AzureBackupJobResourceList struct { - autorest.Response `json:"-"` - // Value - List of resources. - Value *[]AzureBackupJobResource `json:"value,omitempty"` - // NextLink - The uri to fetch the next page of resources. Call ListNext() fetches next page of resources. - NextLink *string `json:"nextLink,omitempty"` -} - -// AzureBackupJobResourceListIterator provides access to a complete listing of AzureBackupJobResource -// values. -type AzureBackupJobResourceListIterator struct { - i int - page AzureBackupJobResourceListPage -} - -// NextWithContext advances to the next value. If there was an error making -// the request the iterator does not advance and the error is returned. -func (iter *AzureBackupJobResourceListIterator) NextWithContext(ctx context.Context) (err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/AzureBackupJobResourceListIterator.NextWithContext") - defer func() { - sc := -1 - if iter.Response().Response.Response != nil { - sc = iter.Response().Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - iter.i++ - if iter.i < len(iter.page.Values()) { - return nil - } - err = iter.page.NextWithContext(ctx) - if err != nil { - iter.i-- - return err - } - iter.i = 0 - return nil -} - -// Next advances to the next value. If there was an error making -// the request the iterator does not advance and the error is returned. -// Deprecated: Use NextWithContext() instead. -func (iter *AzureBackupJobResourceListIterator) Next() error { - return iter.NextWithContext(context.Background()) -} - -// NotDone returns true if the enumeration should be started or is not yet complete. -func (iter AzureBackupJobResourceListIterator) NotDone() bool { - return iter.page.NotDone() && iter.i < len(iter.page.Values()) -} - -// Response returns the raw server response from the last page request. -func (iter AzureBackupJobResourceListIterator) Response() AzureBackupJobResourceList { - return iter.page.Response() -} - -// Value returns the current value or a zero-initialized value if the -// iterator has advanced beyond the end of the collection. -func (iter AzureBackupJobResourceListIterator) Value() AzureBackupJobResource { - if !iter.page.NotDone() { - return AzureBackupJobResource{} - } - return iter.page.Values()[iter.i] -} - -// Creates a new instance of the AzureBackupJobResourceListIterator type. -func NewAzureBackupJobResourceListIterator(page AzureBackupJobResourceListPage) AzureBackupJobResourceListIterator { - return AzureBackupJobResourceListIterator{page: page} -} - -// IsEmpty returns true if the ListResult contains no values. -func (abjrl AzureBackupJobResourceList) IsEmpty() bool { - return abjrl.Value == nil || len(*abjrl.Value) == 0 -} - -// hasNextLink returns true if the NextLink is not empty. -func (abjrl AzureBackupJobResourceList) hasNextLink() bool { - return abjrl.NextLink != nil && len(*abjrl.NextLink) != 0 -} - -// azureBackupJobResourceListPreparer prepares a request to retrieve the next set of results. -// It returns nil if no more results exist. -func (abjrl AzureBackupJobResourceList) azureBackupJobResourceListPreparer(ctx context.Context) (*http.Request, error) { - if !abjrl.hasNextLink() { - return nil, nil - } - return autorest.Prepare((&http.Request{}).WithContext(ctx), - autorest.AsJSON(), - autorest.AsGet(), - autorest.WithBaseURL(to.String(abjrl.NextLink))) -} - -// AzureBackupJobResourceListPage contains a page of AzureBackupJobResource values. -type AzureBackupJobResourceListPage struct { - fn func(context.Context, AzureBackupJobResourceList) (AzureBackupJobResourceList, error) - abjrl AzureBackupJobResourceList -} - -// NextWithContext advances to the next page of values. If there was an error making -// the request the page does not advance and the error is returned. -func (page *AzureBackupJobResourceListPage) NextWithContext(ctx context.Context) (err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/AzureBackupJobResourceListPage.NextWithContext") - defer func() { - sc := -1 - if page.Response().Response.Response != nil { - sc = page.Response().Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - for { - next, err := page.fn(ctx, page.abjrl) - if err != nil { - return err - } - page.abjrl = next - if !next.hasNextLink() || !next.IsEmpty() { - break - } - } - return nil -} - -// Next advances to the next page of values. If there was an error making -// the request the page does not advance and the error is returned. -// Deprecated: Use NextWithContext() instead. -func (page *AzureBackupJobResourceListPage) Next() error { - return page.NextWithContext(context.Background()) -} - -// NotDone returns true if the page enumeration should be started or is not yet complete. -func (page AzureBackupJobResourceListPage) NotDone() bool { - return !page.abjrl.IsEmpty() -} - -// Response returns the raw server response from the last page request. -func (page AzureBackupJobResourceListPage) Response() AzureBackupJobResourceList { - return page.abjrl -} - -// Values returns the slice of values for the current page or nil if there are no values. -func (page AzureBackupJobResourceListPage) Values() []AzureBackupJobResource { - if page.abjrl.IsEmpty() { - return nil - } - return *page.abjrl.Value -} - -// Creates a new instance of the AzureBackupJobResourceListPage type. -func NewAzureBackupJobResourceListPage(cur AzureBackupJobResourceList, getNextPage func(context.Context, AzureBackupJobResourceList) (AzureBackupJobResourceList, error)) AzureBackupJobResourceListPage { - return AzureBackupJobResourceListPage{ - fn: getNextPage, - abjrl: cur, - } -} - -// AzureBackupParams azure backup parameters -type AzureBackupParams struct { - // BackupType - BackupType ; Full/Incremental etc - BackupType *string `json:"backupType,omitempty"` - // ObjectType - Possible values include: 'ObjectTypeBasicBackupParametersObjectTypeBackupParameters', 'ObjectTypeBasicBackupParametersObjectTypeAzureBackupParams' - ObjectType ObjectTypeBasicBackupParameters `json:"objectType,omitempty"` -} - -// MarshalJSON is the custom marshaler for AzureBackupParams. -func (abp AzureBackupParams) MarshalJSON() ([]byte, error) { - abp.ObjectType = ObjectTypeBasicBackupParametersObjectTypeAzureBackupParams - objectMap := make(map[string]interface{}) - if abp.BackupType != nil { - objectMap["backupType"] = abp.BackupType - } - if abp.ObjectType != "" { - objectMap["objectType"] = abp.ObjectType - } - return json.Marshal(objectMap) -} - -// AsAzureBackupParams is the BasicBackupParameters implementation for AzureBackupParams. -func (abp AzureBackupParams) AsAzureBackupParams() (*AzureBackupParams, bool) { - return &abp, true -} - -// AsBackupParameters is the BasicBackupParameters implementation for AzureBackupParams. -func (abp AzureBackupParams) AsBackupParameters() (*BackupParameters, bool) { - return nil, false -} - -// AsBasicBackupParameters is the BasicBackupParameters implementation for AzureBackupParams. -func (abp AzureBackupParams) AsBasicBackupParameters() (BasicBackupParameters, bool) { - return &abp, true -} - -// BasicAzureBackupRecoveryPoint azure backup recoveryPoint -type BasicAzureBackupRecoveryPoint interface { - AsAzureBackupDiscreteRecoveryPoint() (*AzureBackupDiscreteRecoveryPoint, bool) - AsAzureBackupRecoveryPoint() (*AzureBackupRecoveryPoint, bool) -} - -// AzureBackupRecoveryPoint azure backup recoveryPoint -type AzureBackupRecoveryPoint struct { - // ObjectType - Possible values include: 'ObjectTypeBasicAzureBackupRecoveryPointObjectTypeAzureBackupRecoveryPoint', 'ObjectTypeBasicAzureBackupRecoveryPointObjectTypeAzureBackupDiscreteRecoveryPoint' - ObjectType ObjectTypeBasicAzureBackupRecoveryPoint `json:"objectType,omitempty"` -} - -func unmarshalBasicAzureBackupRecoveryPoint(body []byte) (BasicAzureBackupRecoveryPoint, error) { - var m map[string]interface{} - err := json.Unmarshal(body, &m) - if err != nil { - return nil, err - } - - switch m["objectType"] { - case string(ObjectTypeBasicAzureBackupRecoveryPointObjectTypeAzureBackupDiscreteRecoveryPoint): - var abdrp AzureBackupDiscreteRecoveryPoint - err := json.Unmarshal(body, &abdrp) - return abdrp, err - default: - var abrp AzureBackupRecoveryPoint - err := json.Unmarshal(body, &abrp) - return abrp, err - } -} - -func unmarshalBasicAzureBackupRecoveryPointArray(body []byte) ([]BasicAzureBackupRecoveryPoint, error) { - var rawMessages []*json.RawMessage - err := json.Unmarshal(body, &rawMessages) - if err != nil { - return nil, err - } - - abrpArray := make([]BasicAzureBackupRecoveryPoint, len(rawMessages)) - - for index, rawMessage := range rawMessages { - abrp, err := unmarshalBasicAzureBackupRecoveryPoint(*rawMessage) - if err != nil { - return nil, err - } - abrpArray[index] = abrp - } - return abrpArray, nil -} - -// MarshalJSON is the custom marshaler for AzureBackupRecoveryPoint. -func (abrp AzureBackupRecoveryPoint) MarshalJSON() ([]byte, error) { - abrp.ObjectType = ObjectTypeBasicAzureBackupRecoveryPointObjectTypeAzureBackupRecoveryPoint - objectMap := make(map[string]interface{}) - if abrp.ObjectType != "" { - objectMap["objectType"] = abrp.ObjectType - } - return json.Marshal(objectMap) -} - -// AsAzureBackupDiscreteRecoveryPoint is the BasicAzureBackupRecoveryPoint implementation for AzureBackupRecoveryPoint. -func (abrp AzureBackupRecoveryPoint) AsAzureBackupDiscreteRecoveryPoint() (*AzureBackupDiscreteRecoveryPoint, bool) { - return nil, false -} - -// AsAzureBackupRecoveryPoint is the BasicAzureBackupRecoveryPoint implementation for AzureBackupRecoveryPoint. -func (abrp AzureBackupRecoveryPoint) AsAzureBackupRecoveryPoint() (*AzureBackupRecoveryPoint, bool) { - return &abrp, true -} - -// AsBasicAzureBackupRecoveryPoint is the BasicAzureBackupRecoveryPoint implementation for AzureBackupRecoveryPoint. -func (abrp AzureBackupRecoveryPoint) AsBasicAzureBackupRecoveryPoint() (BasicAzureBackupRecoveryPoint, bool) { - return &abrp, true -} - -// BasicAzureBackupRecoveryPointBasedRestoreRequest azure backup recoveryPoint based restore request -type BasicAzureBackupRecoveryPointBasedRestoreRequest interface { - AsAzureBackupRestoreWithRehydrationRequest() (*AzureBackupRestoreWithRehydrationRequest, bool) - AsAzureBackupRecoveryPointBasedRestoreRequest() (*AzureBackupRecoveryPointBasedRestoreRequest, bool) -} - -// AzureBackupRecoveryPointBasedRestoreRequest azure backup recoveryPoint based restore request -type AzureBackupRecoveryPointBasedRestoreRequest struct { - RecoveryPointID *string `json:"recoveryPointId,omitempty"` - // RestoreTargetInfo - Gets or sets the restore target information. - RestoreTargetInfo BasicRestoreTargetInfoBase `json:"restoreTargetInfo,omitempty"` - // SourceDataStoreType - Gets or sets the type of the source data store. Possible values include: 'SourceDataStoreTypeArchiveStore', 'SourceDataStoreTypeSnapshotStore', 'SourceDataStoreTypeVaultStore' - SourceDataStoreType SourceDataStoreType `json:"sourceDataStoreType,omitempty"` - // ObjectType - Possible values include: 'ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRestoreRequest', 'ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRecoveryPointBasedRestoreRequest', 'ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRestoreWithRehydrationRequest', 'ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRecoveryTimeBasedRestoreRequest' - ObjectType ObjectTypeBasicAzureBackupRestoreRequest `json:"objectType,omitempty"` -} - -func unmarshalBasicAzureBackupRecoveryPointBasedRestoreRequest(body []byte) (BasicAzureBackupRecoveryPointBasedRestoreRequest, error) { - var m map[string]interface{} - err := json.Unmarshal(body, &m) - if err != nil { - return nil, err - } - - switch m["objectType"] { - case string(ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRestoreWithRehydrationRequest): - var abrwrr AzureBackupRestoreWithRehydrationRequest - err := json.Unmarshal(body, &abrwrr) - return abrwrr, err - default: - var abrpbrr AzureBackupRecoveryPointBasedRestoreRequest - err := json.Unmarshal(body, &abrpbrr) - return abrpbrr, err - } -} - -func unmarshalBasicAzureBackupRecoveryPointBasedRestoreRequestArray(body []byte) ([]BasicAzureBackupRecoveryPointBasedRestoreRequest, error) { - var rawMessages []*json.RawMessage - err := json.Unmarshal(body, &rawMessages) - if err != nil { - return nil, err - } - - abrpbrrArray := make([]BasicAzureBackupRecoveryPointBasedRestoreRequest, len(rawMessages)) - - for index, rawMessage := range rawMessages { - abrpbrr, err := unmarshalBasicAzureBackupRecoveryPointBasedRestoreRequest(*rawMessage) - if err != nil { - return nil, err - } - abrpbrrArray[index] = abrpbrr - } - return abrpbrrArray, nil -} - -// MarshalJSON is the custom marshaler for AzureBackupRecoveryPointBasedRestoreRequest. -func (abrpbrr AzureBackupRecoveryPointBasedRestoreRequest) MarshalJSON() ([]byte, error) { - abrpbrr.ObjectType = ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRecoveryPointBasedRestoreRequest - objectMap := make(map[string]interface{}) - if abrpbrr.RecoveryPointID != nil { - objectMap["recoveryPointId"] = abrpbrr.RecoveryPointID - } - objectMap["restoreTargetInfo"] = abrpbrr.RestoreTargetInfo - if abrpbrr.SourceDataStoreType != "" { - objectMap["sourceDataStoreType"] = abrpbrr.SourceDataStoreType - } - if abrpbrr.ObjectType != "" { - objectMap["objectType"] = abrpbrr.ObjectType - } - return json.Marshal(objectMap) -} - -// AsAzureBackupRecoveryPointBasedRestoreRequest is the BasicAzureBackupRestoreRequest implementation for AzureBackupRecoveryPointBasedRestoreRequest. -func (abrpbrr AzureBackupRecoveryPointBasedRestoreRequest) AsAzureBackupRecoveryPointBasedRestoreRequest() (*AzureBackupRecoveryPointBasedRestoreRequest, bool) { - return &abrpbrr, true -} - -// AsBasicAzureBackupRecoveryPointBasedRestoreRequest is the BasicAzureBackupRestoreRequest implementation for AzureBackupRecoveryPointBasedRestoreRequest. -func (abrpbrr AzureBackupRecoveryPointBasedRestoreRequest) AsBasicAzureBackupRecoveryPointBasedRestoreRequest() (BasicAzureBackupRecoveryPointBasedRestoreRequest, bool) { - return &abrpbrr, true -} - -// AsAzureBackupRestoreWithRehydrationRequest is the BasicAzureBackupRestoreRequest implementation for AzureBackupRecoveryPointBasedRestoreRequest. -func (abrpbrr AzureBackupRecoveryPointBasedRestoreRequest) AsAzureBackupRestoreWithRehydrationRequest() (*AzureBackupRestoreWithRehydrationRequest, bool) { - return nil, false -} - -// AsAzureBackupRecoveryTimeBasedRestoreRequest is the BasicAzureBackupRestoreRequest implementation for AzureBackupRecoveryPointBasedRestoreRequest. -func (abrpbrr AzureBackupRecoveryPointBasedRestoreRequest) AsAzureBackupRecoveryTimeBasedRestoreRequest() (*AzureBackupRecoveryTimeBasedRestoreRequest, bool) { - return nil, false -} - -// AsAzureBackupRestoreRequest is the BasicAzureBackupRestoreRequest implementation for AzureBackupRecoveryPointBasedRestoreRequest. -func (abrpbrr AzureBackupRecoveryPointBasedRestoreRequest) AsAzureBackupRestoreRequest() (*AzureBackupRestoreRequest, bool) { - return nil, false -} - -// AsBasicAzureBackupRestoreRequest is the BasicAzureBackupRestoreRequest implementation for AzureBackupRecoveryPointBasedRestoreRequest. -func (abrpbrr AzureBackupRecoveryPointBasedRestoreRequest) AsBasicAzureBackupRestoreRequest() (BasicAzureBackupRestoreRequest, bool) { - return &abrpbrr, true -} - -// UnmarshalJSON is the custom unmarshaler for AzureBackupRecoveryPointBasedRestoreRequest struct. -func (abrpbrr *AzureBackupRecoveryPointBasedRestoreRequest) UnmarshalJSON(body []byte) error { - var m map[string]*json.RawMessage - err := json.Unmarshal(body, &m) - if err != nil { - return err - } - for k, v := range m { - switch k { - case "recoveryPointId": - if v != nil { - var recoveryPointID string - err = json.Unmarshal(*v, &recoveryPointID) - if err != nil { - return err - } - abrpbrr.RecoveryPointID = &recoveryPointID - } - case "restoreTargetInfo": - if v != nil { - restoreTargetInfo, err := unmarshalBasicRestoreTargetInfoBase(*v) - if err != nil { - return err - } - abrpbrr.RestoreTargetInfo = restoreTargetInfo - } - case "sourceDataStoreType": - if v != nil { - var sourceDataStoreType SourceDataStoreType - err = json.Unmarshal(*v, &sourceDataStoreType) - if err != nil { - return err - } - abrpbrr.SourceDataStoreType = sourceDataStoreType - } - case "objectType": - if v != nil { - var objectType ObjectTypeBasicAzureBackupRestoreRequest - err = json.Unmarshal(*v, &objectType) - if err != nil { - return err - } - abrpbrr.ObjectType = objectType - } - } - } - - return nil -} - -// AzureBackupRecoveryPointResource azure backup recoveryPoint resource -type AzureBackupRecoveryPointResource struct { - autorest.Response `json:"-"` - // Properties - AzureBackupRecoveryPointResource properties - Properties BasicAzureBackupRecoveryPoint `json:"properties,omitempty"` - // ID - READ-ONLY; Resource Id represents the complete path to the resource. - ID *string `json:"id,omitempty"` - // Name - READ-ONLY; Resource name associated with the resource. - Name *string `json:"name,omitempty"` - // Type - READ-ONLY; Resource type represents the complete path of the form Namespace/ResourceType/ResourceType/... - Type *string `json:"type,omitempty"` - SystemData *SystemData `json:"systemData,omitempty"` -} - -// MarshalJSON is the custom marshaler for AzureBackupRecoveryPointResource. -func (abrpr AzureBackupRecoveryPointResource) MarshalJSON() ([]byte, error) { - objectMap := make(map[string]interface{}) - objectMap["properties"] = abrpr.Properties - if abrpr.SystemData != nil { - objectMap["systemData"] = abrpr.SystemData - } - return json.Marshal(objectMap) -} - -// UnmarshalJSON is the custom unmarshaler for AzureBackupRecoveryPointResource struct. -func (abrpr *AzureBackupRecoveryPointResource) UnmarshalJSON(body []byte) error { - var m map[string]*json.RawMessage - err := json.Unmarshal(body, &m) - if err != nil { - return err - } - for k, v := range m { - switch k { - case "properties": - if v != nil { - properties, err := unmarshalBasicAzureBackupRecoveryPoint(*v) - if err != nil { - return err - } - abrpr.Properties = properties - } - case "id": - if v != nil { - var ID string - err = json.Unmarshal(*v, &ID) - if err != nil { - return err - } - abrpr.ID = &ID - } - case "name": - if v != nil { - var name string - err = json.Unmarshal(*v, &name) - if err != nil { - return err - } - abrpr.Name = &name - } - case "type": - if v != nil { - var typeVar string - err = json.Unmarshal(*v, &typeVar) - if err != nil { - return err - } - abrpr.Type = &typeVar - } - case "systemData": - if v != nil { - var systemData SystemData - err = json.Unmarshal(*v, &systemData) - if err != nil { - return err - } - abrpr.SystemData = &systemData - } - } - } - - return nil -} - -// AzureBackupRecoveryPointResourceList azure backup recoveryPoint resource list -type AzureBackupRecoveryPointResourceList struct { - autorest.Response `json:"-"` - // Value - List of resources. - Value *[]AzureBackupRecoveryPointResource `json:"value,omitempty"` - // NextLink - The uri to fetch the next page of resources. Call ListNext() fetches next page of resources. - NextLink *string `json:"nextLink,omitempty"` -} - -// AzureBackupRecoveryPointResourceListIterator provides access to a complete listing of -// AzureBackupRecoveryPointResource values. -type AzureBackupRecoveryPointResourceListIterator struct { - i int - page AzureBackupRecoveryPointResourceListPage -} - -// NextWithContext advances to the next value. If there was an error making -// the request the iterator does not advance and the error is returned. -func (iter *AzureBackupRecoveryPointResourceListIterator) NextWithContext(ctx context.Context) (err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/AzureBackupRecoveryPointResourceListIterator.NextWithContext") - defer func() { - sc := -1 - if iter.Response().Response.Response != nil { - sc = iter.Response().Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - iter.i++ - if iter.i < len(iter.page.Values()) { - return nil - } - err = iter.page.NextWithContext(ctx) - if err != nil { - iter.i-- - return err - } - iter.i = 0 - return nil -} - -// Next advances to the next value. If there was an error making -// the request the iterator does not advance and the error is returned. -// Deprecated: Use NextWithContext() instead. -func (iter *AzureBackupRecoveryPointResourceListIterator) Next() error { - return iter.NextWithContext(context.Background()) -} - -// NotDone returns true if the enumeration should be started or is not yet complete. -func (iter AzureBackupRecoveryPointResourceListIterator) NotDone() bool { - return iter.page.NotDone() && iter.i < len(iter.page.Values()) -} - -// Response returns the raw server response from the last page request. -func (iter AzureBackupRecoveryPointResourceListIterator) Response() AzureBackupRecoveryPointResourceList { - return iter.page.Response() -} - -// Value returns the current value or a zero-initialized value if the -// iterator has advanced beyond the end of the collection. -func (iter AzureBackupRecoveryPointResourceListIterator) Value() AzureBackupRecoveryPointResource { - if !iter.page.NotDone() { - return AzureBackupRecoveryPointResource{} - } - return iter.page.Values()[iter.i] -} - -// Creates a new instance of the AzureBackupRecoveryPointResourceListIterator type. -func NewAzureBackupRecoveryPointResourceListIterator(page AzureBackupRecoveryPointResourceListPage) AzureBackupRecoveryPointResourceListIterator { - return AzureBackupRecoveryPointResourceListIterator{page: page} -} - -// IsEmpty returns true if the ListResult contains no values. -func (abrprl AzureBackupRecoveryPointResourceList) IsEmpty() bool { - return abrprl.Value == nil || len(*abrprl.Value) == 0 -} - -// hasNextLink returns true if the NextLink is not empty. -func (abrprl AzureBackupRecoveryPointResourceList) hasNextLink() bool { - return abrprl.NextLink != nil && len(*abrprl.NextLink) != 0 -} - -// azureBackupRecoveryPointResourceListPreparer prepares a request to retrieve the next set of results. -// It returns nil if no more results exist. -func (abrprl AzureBackupRecoveryPointResourceList) azureBackupRecoveryPointResourceListPreparer(ctx context.Context) (*http.Request, error) { - if !abrprl.hasNextLink() { - return nil, nil - } - return autorest.Prepare((&http.Request{}).WithContext(ctx), - autorest.AsJSON(), - autorest.AsGet(), - autorest.WithBaseURL(to.String(abrprl.NextLink))) -} - -// AzureBackupRecoveryPointResourceListPage contains a page of AzureBackupRecoveryPointResource values. -type AzureBackupRecoveryPointResourceListPage struct { - fn func(context.Context, AzureBackupRecoveryPointResourceList) (AzureBackupRecoveryPointResourceList, error) - abrprl AzureBackupRecoveryPointResourceList -} - -// NextWithContext advances to the next page of values. If there was an error making -// the request the page does not advance and the error is returned. -func (page *AzureBackupRecoveryPointResourceListPage) NextWithContext(ctx context.Context) (err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/AzureBackupRecoveryPointResourceListPage.NextWithContext") - defer func() { - sc := -1 - if page.Response().Response.Response != nil { - sc = page.Response().Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - for { - next, err := page.fn(ctx, page.abrprl) - if err != nil { - return err - } - page.abrprl = next - if !next.hasNextLink() || !next.IsEmpty() { - break - } - } - return nil -} - -// Next advances to the next page of values. If there was an error making -// the request the page does not advance and the error is returned. -// Deprecated: Use NextWithContext() instead. -func (page *AzureBackupRecoveryPointResourceListPage) Next() error { - return page.NextWithContext(context.Background()) -} - -// NotDone returns true if the page enumeration should be started or is not yet complete. -func (page AzureBackupRecoveryPointResourceListPage) NotDone() bool { - return !page.abrprl.IsEmpty() -} - -// Response returns the raw server response from the last page request. -func (page AzureBackupRecoveryPointResourceListPage) Response() AzureBackupRecoveryPointResourceList { - return page.abrprl -} - -// Values returns the slice of values for the current page or nil if there are no values. -func (page AzureBackupRecoveryPointResourceListPage) Values() []AzureBackupRecoveryPointResource { - if page.abrprl.IsEmpty() { - return nil - } - return *page.abrprl.Value -} - -// Creates a new instance of the AzureBackupRecoveryPointResourceListPage type. -func NewAzureBackupRecoveryPointResourceListPage(cur AzureBackupRecoveryPointResourceList, getNextPage func(context.Context, AzureBackupRecoveryPointResourceList) (AzureBackupRecoveryPointResourceList, error)) AzureBackupRecoveryPointResourceListPage { - return AzureBackupRecoveryPointResourceListPage{ - fn: getNextPage, - abrprl: cur, - } -} - -// AzureBackupRecoveryTimeBasedRestoreRequest azureBackup RecoveryPointTime Based Restore Request -type AzureBackupRecoveryTimeBasedRestoreRequest struct { - // RecoveryPointTime - The recovery time in ISO 8601 format example - 2020-08-14T17:30:00.0000000Z. - RecoveryPointTime *string `json:"recoveryPointTime,omitempty"` - // RestoreTargetInfo - Gets or sets the restore target information. - RestoreTargetInfo BasicRestoreTargetInfoBase `json:"restoreTargetInfo,omitempty"` - // SourceDataStoreType - Gets or sets the type of the source data store. Possible values include: 'SourceDataStoreTypeArchiveStore', 'SourceDataStoreTypeSnapshotStore', 'SourceDataStoreTypeVaultStore' - SourceDataStoreType SourceDataStoreType `json:"sourceDataStoreType,omitempty"` - // ObjectType - Possible values include: 'ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRestoreRequest', 'ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRecoveryPointBasedRestoreRequest', 'ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRestoreWithRehydrationRequest', 'ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRecoveryTimeBasedRestoreRequest' - ObjectType ObjectTypeBasicAzureBackupRestoreRequest `json:"objectType,omitempty"` -} - -// MarshalJSON is the custom marshaler for AzureBackupRecoveryTimeBasedRestoreRequest. -func (abrtbrr AzureBackupRecoveryTimeBasedRestoreRequest) MarshalJSON() ([]byte, error) { - abrtbrr.ObjectType = ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRecoveryTimeBasedRestoreRequest - objectMap := make(map[string]interface{}) - if abrtbrr.RecoveryPointTime != nil { - objectMap["recoveryPointTime"] = abrtbrr.RecoveryPointTime - } - objectMap["restoreTargetInfo"] = abrtbrr.RestoreTargetInfo - if abrtbrr.SourceDataStoreType != "" { - objectMap["sourceDataStoreType"] = abrtbrr.SourceDataStoreType - } - if abrtbrr.ObjectType != "" { - objectMap["objectType"] = abrtbrr.ObjectType - } - return json.Marshal(objectMap) -} - -// AsAzureBackupRecoveryPointBasedRestoreRequest is the BasicAzureBackupRestoreRequest implementation for AzureBackupRecoveryTimeBasedRestoreRequest. -func (abrtbrr AzureBackupRecoveryTimeBasedRestoreRequest) AsAzureBackupRecoveryPointBasedRestoreRequest() (*AzureBackupRecoveryPointBasedRestoreRequest, bool) { - return nil, false -} - -// AsBasicAzureBackupRecoveryPointBasedRestoreRequest is the BasicAzureBackupRestoreRequest implementation for AzureBackupRecoveryTimeBasedRestoreRequest. -func (abrtbrr AzureBackupRecoveryTimeBasedRestoreRequest) AsBasicAzureBackupRecoveryPointBasedRestoreRequest() (BasicAzureBackupRecoveryPointBasedRestoreRequest, bool) { - return nil, false -} - -// AsAzureBackupRestoreWithRehydrationRequest is the BasicAzureBackupRestoreRequest implementation for AzureBackupRecoveryTimeBasedRestoreRequest. -func (abrtbrr AzureBackupRecoveryTimeBasedRestoreRequest) AsAzureBackupRestoreWithRehydrationRequest() (*AzureBackupRestoreWithRehydrationRequest, bool) { - return nil, false -} - -// AsAzureBackupRecoveryTimeBasedRestoreRequest is the BasicAzureBackupRestoreRequest implementation for AzureBackupRecoveryTimeBasedRestoreRequest. -func (abrtbrr AzureBackupRecoveryTimeBasedRestoreRequest) AsAzureBackupRecoveryTimeBasedRestoreRequest() (*AzureBackupRecoveryTimeBasedRestoreRequest, bool) { - return &abrtbrr, true -} - -// AsAzureBackupRestoreRequest is the BasicAzureBackupRestoreRequest implementation for AzureBackupRecoveryTimeBasedRestoreRequest. -func (abrtbrr AzureBackupRecoveryTimeBasedRestoreRequest) AsAzureBackupRestoreRequest() (*AzureBackupRestoreRequest, bool) { - return nil, false -} - -// AsBasicAzureBackupRestoreRequest is the BasicAzureBackupRestoreRequest implementation for AzureBackupRecoveryTimeBasedRestoreRequest. -func (abrtbrr AzureBackupRecoveryTimeBasedRestoreRequest) AsBasicAzureBackupRestoreRequest() (BasicAzureBackupRestoreRequest, bool) { - return &abrtbrr, true -} - -// UnmarshalJSON is the custom unmarshaler for AzureBackupRecoveryTimeBasedRestoreRequest struct. -func (abrtbrr *AzureBackupRecoveryTimeBasedRestoreRequest) UnmarshalJSON(body []byte) error { - var m map[string]*json.RawMessage - err := json.Unmarshal(body, &m) - if err != nil { - return err - } - for k, v := range m { - switch k { - case "recoveryPointTime": - if v != nil { - var recoveryPointTime string - err = json.Unmarshal(*v, &recoveryPointTime) - if err != nil { - return err - } - abrtbrr.RecoveryPointTime = &recoveryPointTime - } - case "restoreTargetInfo": - if v != nil { - restoreTargetInfo, err := unmarshalBasicRestoreTargetInfoBase(*v) - if err != nil { - return err - } - abrtbrr.RestoreTargetInfo = restoreTargetInfo - } - case "sourceDataStoreType": - if v != nil { - var sourceDataStoreType SourceDataStoreType - err = json.Unmarshal(*v, &sourceDataStoreType) - if err != nil { - return err - } - abrtbrr.SourceDataStoreType = sourceDataStoreType - } - case "objectType": - if v != nil { - var objectType ObjectTypeBasicAzureBackupRestoreRequest - err = json.Unmarshal(*v, &objectType) - if err != nil { - return err - } - abrtbrr.ObjectType = objectType - } - } - } - - return nil -} - -// AzureBackupRehydrationRequest azure Backup Rehydrate Request -type AzureBackupRehydrationRequest struct { - // RecoveryPointID - Id of the recovery point to be recovered - RecoveryPointID *string `json:"recoveryPointId,omitempty"` - // RehydrationPriority - Priority to be used for rehydration. Values High or Standard. Possible values include: 'RehydrationPriorityInvalid', 'RehydrationPriorityHigh', 'RehydrationPriorityStandard' - RehydrationPriority RehydrationPriority `json:"rehydrationPriority,omitempty"` - // RehydrationRetentionDuration - Retention duration in ISO 8601 format i.e P10D . - RehydrationRetentionDuration *string `json:"rehydrationRetentionDuration,omitempty"` -} - -// BasicAzureBackupRestoreRequest azure backup restore request -type BasicAzureBackupRestoreRequest interface { - AsAzureBackupRecoveryPointBasedRestoreRequest() (*AzureBackupRecoveryPointBasedRestoreRequest, bool) - AsBasicAzureBackupRecoveryPointBasedRestoreRequest() (BasicAzureBackupRecoveryPointBasedRestoreRequest, bool) - AsAzureBackupRestoreWithRehydrationRequest() (*AzureBackupRestoreWithRehydrationRequest, bool) - AsAzureBackupRecoveryTimeBasedRestoreRequest() (*AzureBackupRecoveryTimeBasedRestoreRequest, bool) - AsAzureBackupRestoreRequest() (*AzureBackupRestoreRequest, bool) -} - -// AzureBackupRestoreRequest azure backup restore request -type AzureBackupRestoreRequest struct { - // RestoreTargetInfo - Gets or sets the restore target information. - RestoreTargetInfo BasicRestoreTargetInfoBase `json:"restoreTargetInfo,omitempty"` - // SourceDataStoreType - Gets or sets the type of the source data store. Possible values include: 'SourceDataStoreTypeArchiveStore', 'SourceDataStoreTypeSnapshotStore', 'SourceDataStoreTypeVaultStore' - SourceDataStoreType SourceDataStoreType `json:"sourceDataStoreType,omitempty"` - // ObjectType - Possible values include: 'ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRestoreRequest', 'ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRecoveryPointBasedRestoreRequest', 'ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRestoreWithRehydrationRequest', 'ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRecoveryTimeBasedRestoreRequest' - ObjectType ObjectTypeBasicAzureBackupRestoreRequest `json:"objectType,omitempty"` -} - -func unmarshalBasicAzureBackupRestoreRequest(body []byte) (BasicAzureBackupRestoreRequest, error) { - var m map[string]interface{} - err := json.Unmarshal(body, &m) - if err != nil { - return nil, err - } - - switch m["objectType"] { - case string(ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRecoveryPointBasedRestoreRequest): - var abrpbrr AzureBackupRecoveryPointBasedRestoreRequest - err := json.Unmarshal(body, &abrpbrr) - return abrpbrr, err - case string(ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRestoreWithRehydrationRequest): - var abrwrr AzureBackupRestoreWithRehydrationRequest - err := json.Unmarshal(body, &abrwrr) - return abrwrr, err - case string(ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRecoveryTimeBasedRestoreRequest): - var abrtbrr AzureBackupRecoveryTimeBasedRestoreRequest - err := json.Unmarshal(body, &abrtbrr) - return abrtbrr, err - default: - var abrr AzureBackupRestoreRequest - err := json.Unmarshal(body, &abrr) - return abrr, err - } -} - -func unmarshalBasicAzureBackupRestoreRequestArray(body []byte) ([]BasicAzureBackupRestoreRequest, error) { - var rawMessages []*json.RawMessage - err := json.Unmarshal(body, &rawMessages) - if err != nil { - return nil, err - } - - abrrArray := make([]BasicAzureBackupRestoreRequest, len(rawMessages)) - - for index, rawMessage := range rawMessages { - abrr, err := unmarshalBasicAzureBackupRestoreRequest(*rawMessage) - if err != nil { - return nil, err - } - abrrArray[index] = abrr - } - return abrrArray, nil -} - -// MarshalJSON is the custom marshaler for AzureBackupRestoreRequest. -func (abrr AzureBackupRestoreRequest) MarshalJSON() ([]byte, error) { - abrr.ObjectType = ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRestoreRequest - objectMap := make(map[string]interface{}) - objectMap["restoreTargetInfo"] = abrr.RestoreTargetInfo - if abrr.SourceDataStoreType != "" { - objectMap["sourceDataStoreType"] = abrr.SourceDataStoreType - } - if abrr.ObjectType != "" { - objectMap["objectType"] = abrr.ObjectType - } - return json.Marshal(objectMap) -} - -// AsAzureBackupRecoveryPointBasedRestoreRequest is the BasicAzureBackupRestoreRequest implementation for AzureBackupRestoreRequest. -func (abrr AzureBackupRestoreRequest) AsAzureBackupRecoveryPointBasedRestoreRequest() (*AzureBackupRecoveryPointBasedRestoreRequest, bool) { - return nil, false -} - -// AsBasicAzureBackupRecoveryPointBasedRestoreRequest is the BasicAzureBackupRestoreRequest implementation for AzureBackupRestoreRequest. -func (abrr AzureBackupRestoreRequest) AsBasicAzureBackupRecoveryPointBasedRestoreRequest() (BasicAzureBackupRecoveryPointBasedRestoreRequest, bool) { - return nil, false -} - -// AsAzureBackupRestoreWithRehydrationRequest is the BasicAzureBackupRestoreRequest implementation for AzureBackupRestoreRequest. -func (abrr AzureBackupRestoreRequest) AsAzureBackupRestoreWithRehydrationRequest() (*AzureBackupRestoreWithRehydrationRequest, bool) { - return nil, false -} - -// AsAzureBackupRecoveryTimeBasedRestoreRequest is the BasicAzureBackupRestoreRequest implementation for AzureBackupRestoreRequest. -func (abrr AzureBackupRestoreRequest) AsAzureBackupRecoveryTimeBasedRestoreRequest() (*AzureBackupRecoveryTimeBasedRestoreRequest, bool) { - return nil, false -} - -// AsAzureBackupRestoreRequest is the BasicAzureBackupRestoreRequest implementation for AzureBackupRestoreRequest. -func (abrr AzureBackupRestoreRequest) AsAzureBackupRestoreRequest() (*AzureBackupRestoreRequest, bool) { - return &abrr, true -} - -// AsBasicAzureBackupRestoreRequest is the BasicAzureBackupRestoreRequest implementation for AzureBackupRestoreRequest. -func (abrr AzureBackupRestoreRequest) AsBasicAzureBackupRestoreRequest() (BasicAzureBackupRestoreRequest, bool) { - return &abrr, true -} - -// UnmarshalJSON is the custom unmarshaler for AzureBackupRestoreRequest struct. -func (abrr *AzureBackupRestoreRequest) UnmarshalJSON(body []byte) error { - var m map[string]*json.RawMessage - err := json.Unmarshal(body, &m) - if err != nil { - return err - } - for k, v := range m { - switch k { - case "restoreTargetInfo": - if v != nil { - restoreTargetInfo, err := unmarshalBasicRestoreTargetInfoBase(*v) - if err != nil { - return err - } - abrr.RestoreTargetInfo = restoreTargetInfo - } - case "sourceDataStoreType": - if v != nil { - var sourceDataStoreType SourceDataStoreType - err = json.Unmarshal(*v, &sourceDataStoreType) - if err != nil { - return err - } - abrr.SourceDataStoreType = sourceDataStoreType - } - case "objectType": - if v != nil { - var objectType ObjectTypeBasicAzureBackupRestoreRequest - err = json.Unmarshal(*v, &objectType) - if err != nil { - return err - } - abrr.ObjectType = objectType - } - } - } - - return nil -} - -// AzureBackupRestoreWithRehydrationRequest azureBackup Restore with Rehydration Request -type AzureBackupRestoreWithRehydrationRequest struct { - // RehydrationPriority - Priority to be used for rehydration. Values High or Standard. Possible values include: 'RehydrationPriorityInvalid', 'RehydrationPriorityHigh', 'RehydrationPriorityStandard' - RehydrationPriority RehydrationPriority `json:"rehydrationPriority,omitempty"` - // RehydrationRetentionDuration - Retention duration in ISO 8601 format i.e P10D . - RehydrationRetentionDuration *string `json:"rehydrationRetentionDuration,omitempty"` - RecoveryPointID *string `json:"recoveryPointId,omitempty"` - // RestoreTargetInfo - Gets or sets the restore target information. - RestoreTargetInfo BasicRestoreTargetInfoBase `json:"restoreTargetInfo,omitempty"` - // SourceDataStoreType - Gets or sets the type of the source data store. Possible values include: 'SourceDataStoreTypeArchiveStore', 'SourceDataStoreTypeSnapshotStore', 'SourceDataStoreTypeVaultStore' - SourceDataStoreType SourceDataStoreType `json:"sourceDataStoreType,omitempty"` - // ObjectType - Possible values include: 'ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRestoreRequest', 'ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRecoveryPointBasedRestoreRequest', 'ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRestoreWithRehydrationRequest', 'ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRecoveryTimeBasedRestoreRequest' - ObjectType ObjectTypeBasicAzureBackupRestoreRequest `json:"objectType,omitempty"` -} - -// MarshalJSON is the custom marshaler for AzureBackupRestoreWithRehydrationRequest. -func (abrwrr AzureBackupRestoreWithRehydrationRequest) MarshalJSON() ([]byte, error) { - abrwrr.ObjectType = ObjectTypeBasicAzureBackupRestoreRequestObjectTypeAzureBackupRestoreWithRehydrationRequest - objectMap := make(map[string]interface{}) - if abrwrr.RehydrationPriority != "" { - objectMap["rehydrationPriority"] = abrwrr.RehydrationPriority - } - if abrwrr.RehydrationRetentionDuration != nil { - objectMap["rehydrationRetentionDuration"] = abrwrr.RehydrationRetentionDuration - } - if abrwrr.RecoveryPointID != nil { - objectMap["recoveryPointId"] = abrwrr.RecoveryPointID - } - objectMap["restoreTargetInfo"] = abrwrr.RestoreTargetInfo - if abrwrr.SourceDataStoreType != "" { - objectMap["sourceDataStoreType"] = abrwrr.SourceDataStoreType - } - if abrwrr.ObjectType != "" { - objectMap["objectType"] = abrwrr.ObjectType - } - return json.Marshal(objectMap) -} - -// AsAzureBackupRecoveryPointBasedRestoreRequest is the BasicAzureBackupRestoreRequest implementation for AzureBackupRestoreWithRehydrationRequest. -func (abrwrr AzureBackupRestoreWithRehydrationRequest) AsAzureBackupRecoveryPointBasedRestoreRequest() (*AzureBackupRecoveryPointBasedRestoreRequest, bool) { - return nil, false -} - -// AsBasicAzureBackupRecoveryPointBasedRestoreRequest is the BasicAzureBackupRestoreRequest implementation for AzureBackupRestoreWithRehydrationRequest. -func (abrwrr AzureBackupRestoreWithRehydrationRequest) AsBasicAzureBackupRecoveryPointBasedRestoreRequest() (BasicAzureBackupRecoveryPointBasedRestoreRequest, bool) { - return &abrwrr, true -} - -// AsAzureBackupRestoreWithRehydrationRequest is the BasicAzureBackupRestoreRequest implementation for AzureBackupRestoreWithRehydrationRequest. -func (abrwrr AzureBackupRestoreWithRehydrationRequest) AsAzureBackupRestoreWithRehydrationRequest() (*AzureBackupRestoreWithRehydrationRequest, bool) { - return &abrwrr, true -} - -// AsAzureBackupRecoveryTimeBasedRestoreRequest is the BasicAzureBackupRestoreRequest implementation for AzureBackupRestoreWithRehydrationRequest. -func (abrwrr AzureBackupRestoreWithRehydrationRequest) AsAzureBackupRecoveryTimeBasedRestoreRequest() (*AzureBackupRecoveryTimeBasedRestoreRequest, bool) { - return nil, false -} - -// AsAzureBackupRestoreRequest is the BasicAzureBackupRestoreRequest implementation for AzureBackupRestoreWithRehydrationRequest. -func (abrwrr AzureBackupRestoreWithRehydrationRequest) AsAzureBackupRestoreRequest() (*AzureBackupRestoreRequest, bool) { - return nil, false -} - -// AsBasicAzureBackupRestoreRequest is the BasicAzureBackupRestoreRequest implementation for AzureBackupRestoreWithRehydrationRequest. -func (abrwrr AzureBackupRestoreWithRehydrationRequest) AsBasicAzureBackupRestoreRequest() (BasicAzureBackupRestoreRequest, bool) { - return &abrwrr, true -} - -// UnmarshalJSON is the custom unmarshaler for AzureBackupRestoreWithRehydrationRequest struct. -func (abrwrr *AzureBackupRestoreWithRehydrationRequest) UnmarshalJSON(body []byte) error { - var m map[string]*json.RawMessage - err := json.Unmarshal(body, &m) - if err != nil { - return err - } - for k, v := range m { - switch k { - case "rehydrationPriority": - if v != nil { - var rehydrationPriority RehydrationPriority - err = json.Unmarshal(*v, &rehydrationPriority) - if err != nil { - return err - } - abrwrr.RehydrationPriority = rehydrationPriority - } - case "rehydrationRetentionDuration": - if v != nil { - var rehydrationRetentionDuration string - err = json.Unmarshal(*v, &rehydrationRetentionDuration) - if err != nil { - return err - } - abrwrr.RehydrationRetentionDuration = &rehydrationRetentionDuration - } - case "recoveryPointId": - if v != nil { - var recoveryPointID string - err = json.Unmarshal(*v, &recoveryPointID) - if err != nil { - return err - } - abrwrr.RecoveryPointID = &recoveryPointID - } - case "restoreTargetInfo": - if v != nil { - restoreTargetInfo, err := unmarshalBasicRestoreTargetInfoBase(*v) - if err != nil { - return err - } - abrwrr.RestoreTargetInfo = restoreTargetInfo - } - case "sourceDataStoreType": - if v != nil { - var sourceDataStoreType SourceDataStoreType - err = json.Unmarshal(*v, &sourceDataStoreType) - if err != nil { - return err - } - abrwrr.SourceDataStoreType = sourceDataStoreType - } - case "objectType": - if v != nil { - var objectType ObjectTypeBasicAzureBackupRestoreRequest - err = json.Unmarshal(*v, &objectType) - if err != nil { - return err - } - abrwrr.ObjectType = objectType - } - } - } - - return nil -} - -// AzureBackupRule azure backup rule -type AzureBackupRule struct { - BackupParameters BasicBackupParameters `json:"backupParameters,omitempty"` - DataStore *DataStoreInfoBase `json:"dataStore,omitempty"` - Trigger BasicTriggerContext `json:"trigger,omitempty"` - Name *string `json:"name,omitempty"` - // ObjectType - Possible values include: 'ObjectTypeBasicBasePolicyRuleObjectTypeBasePolicyRule', 'ObjectTypeBasicBasePolicyRuleObjectTypeAzureBackupRule', 'ObjectTypeBasicBasePolicyRuleObjectTypeAzureRetentionRule' - ObjectType ObjectTypeBasicBasePolicyRule `json:"objectType,omitempty"` -} - -// MarshalJSON is the custom marshaler for AzureBackupRule. -func (abr AzureBackupRule) MarshalJSON() ([]byte, error) { - abr.ObjectType = ObjectTypeBasicBasePolicyRuleObjectTypeAzureBackupRule - objectMap := make(map[string]interface{}) - objectMap["backupParameters"] = abr.BackupParameters - if abr.DataStore != nil { - objectMap["dataStore"] = abr.DataStore - } - objectMap["trigger"] = abr.Trigger - if abr.Name != nil { - objectMap["name"] = abr.Name - } - if abr.ObjectType != "" { - objectMap["objectType"] = abr.ObjectType - } - return json.Marshal(objectMap) -} - -// AsAzureBackupRule is the BasicBasePolicyRule implementation for AzureBackupRule. -func (abr AzureBackupRule) AsAzureBackupRule() (*AzureBackupRule, bool) { - return &abr, true -} - -// AsAzureRetentionRule is the BasicBasePolicyRule implementation for AzureBackupRule. -func (abr AzureBackupRule) AsAzureRetentionRule() (*AzureRetentionRule, bool) { - return nil, false -} - -// AsBasePolicyRule is the BasicBasePolicyRule implementation for AzureBackupRule. -func (abr AzureBackupRule) AsBasePolicyRule() (*BasePolicyRule, bool) { - return nil, false -} - -// AsBasicBasePolicyRule is the BasicBasePolicyRule implementation for AzureBackupRule. -func (abr AzureBackupRule) AsBasicBasePolicyRule() (BasicBasePolicyRule, bool) { - return &abr, true -} - -// UnmarshalJSON is the custom unmarshaler for AzureBackupRule struct. -func (abr *AzureBackupRule) UnmarshalJSON(body []byte) error { - var m map[string]*json.RawMessage - err := json.Unmarshal(body, &m) - if err != nil { - return err - } - for k, v := range m { - switch k { - case "backupParameters": - if v != nil { - backupParameters, err := unmarshalBasicBackupParameters(*v) - if err != nil { - return err - } - abr.BackupParameters = backupParameters - } - case "dataStore": - if v != nil { - var dataStore DataStoreInfoBase - err = json.Unmarshal(*v, &dataStore) - if err != nil { - return err - } - abr.DataStore = &dataStore - } - case "trigger": - if v != nil { - trigger, err := unmarshalBasicTriggerContext(*v) - if err != nil { - return err - } - abr.Trigger = trigger - } - case "name": - if v != nil { - var name string - err = json.Unmarshal(*v, &name) - if err != nil { - return err - } - abr.Name = &name - } - case "objectType": - if v != nil { - var objectType ObjectTypeBasicBasePolicyRule - err = json.Unmarshal(*v, &objectType) - if err != nil { - return err - } - abr.ObjectType = objectType - } - } - } - - return nil -} - -// AzureOperationalStoreParameters parameters for Operational-Tier DataStore -type AzureOperationalStoreParameters struct { - // ResourceGroupID - Gets or sets the Snapshot Resource Group Uri. - ResourceGroupID *string `json:"resourceGroupId,omitempty"` - // DataStoreType - type of datastore; Operational/Vault/Archive. Possible values include: 'DataStoreTypesOperationalStore', 'DataStoreTypesVaultStore', 'DataStoreTypesArchiveStore' - DataStoreType DataStoreTypes `json:"dataStoreType,omitempty"` - // ObjectType - Possible values include: 'ObjectTypeBasicDataStoreParametersObjectTypeDataStoreParameters', 'ObjectTypeBasicDataStoreParametersObjectTypeAzureOperationalStoreParameters' - ObjectType ObjectTypeBasicDataStoreParameters `json:"objectType,omitempty"` -} - -// MarshalJSON is the custom marshaler for AzureOperationalStoreParameters. -func (aosp AzureOperationalStoreParameters) MarshalJSON() ([]byte, error) { - aosp.ObjectType = ObjectTypeBasicDataStoreParametersObjectTypeAzureOperationalStoreParameters - objectMap := make(map[string]interface{}) - if aosp.ResourceGroupID != nil { - objectMap["resourceGroupId"] = aosp.ResourceGroupID - } - if aosp.DataStoreType != "" { - objectMap["dataStoreType"] = aosp.DataStoreType - } - if aosp.ObjectType != "" { - objectMap["objectType"] = aosp.ObjectType - } - return json.Marshal(objectMap) -} - -// AsAzureOperationalStoreParameters is the BasicDataStoreParameters implementation for AzureOperationalStoreParameters. -func (aosp AzureOperationalStoreParameters) AsAzureOperationalStoreParameters() (*AzureOperationalStoreParameters, bool) { - return &aosp, true -} - -// AsDataStoreParameters is the BasicDataStoreParameters implementation for AzureOperationalStoreParameters. -func (aosp AzureOperationalStoreParameters) AsDataStoreParameters() (*DataStoreParameters, bool) { - return nil, false -} - -// AsBasicDataStoreParameters is the BasicDataStoreParameters implementation for AzureOperationalStoreParameters. -func (aosp AzureOperationalStoreParameters) AsBasicDataStoreParameters() (BasicDataStoreParameters, bool) { - return &aosp, true -} - -// AzureRetentionRule azure retention rule -type AzureRetentionRule struct { - IsDefault *bool `json:"isDefault,omitempty"` - Lifecycles *[]SourceLifeCycle `json:"lifecycles,omitempty"` - Name *string `json:"name,omitempty"` - // ObjectType - Possible values include: 'ObjectTypeBasicBasePolicyRuleObjectTypeBasePolicyRule', 'ObjectTypeBasicBasePolicyRuleObjectTypeAzureBackupRule', 'ObjectTypeBasicBasePolicyRuleObjectTypeAzureRetentionRule' - ObjectType ObjectTypeBasicBasePolicyRule `json:"objectType,omitempty"` -} - -// MarshalJSON is the custom marshaler for AzureRetentionRule. -func (arr AzureRetentionRule) MarshalJSON() ([]byte, error) { - arr.ObjectType = ObjectTypeBasicBasePolicyRuleObjectTypeAzureRetentionRule - objectMap := make(map[string]interface{}) - if arr.IsDefault != nil { - objectMap["isDefault"] = arr.IsDefault - } - if arr.Lifecycles != nil { - objectMap["lifecycles"] = arr.Lifecycles - } - if arr.Name != nil { - objectMap["name"] = arr.Name - } - if arr.ObjectType != "" { - objectMap["objectType"] = arr.ObjectType - } - return json.Marshal(objectMap) -} - -// AsAzureBackupRule is the BasicBasePolicyRule implementation for AzureRetentionRule. -func (arr AzureRetentionRule) AsAzureBackupRule() (*AzureBackupRule, bool) { - return nil, false -} - -// AsAzureRetentionRule is the BasicBasePolicyRule implementation for AzureRetentionRule. -func (arr AzureRetentionRule) AsAzureRetentionRule() (*AzureRetentionRule, bool) { - return &arr, true -} - -// AsBasePolicyRule is the BasicBasePolicyRule implementation for AzureRetentionRule. -func (arr AzureRetentionRule) AsBasePolicyRule() (*BasePolicyRule, bool) { - return nil, false -} - -// AsBasicBasePolicyRule is the BasicBasePolicyRule implementation for AzureRetentionRule. -func (arr AzureRetentionRule) AsBasicBasePolicyRule() (BasicBasePolicyRule, bool) { - return &arr, true -} - -// BasicBackupCriteria backupCriteria base class -type BasicBackupCriteria interface { - AsScheduleBasedBackupCriteria() (*ScheduleBasedBackupCriteria, bool) - AsBackupCriteria() (*BackupCriteria, bool) -} - -// BackupCriteria backupCriteria base class -type BackupCriteria struct { - // ObjectType - Possible values include: 'ObjectTypeBasicBackupCriteriaObjectTypeBackupCriteria', 'ObjectTypeBasicBackupCriteriaObjectTypeScheduleBasedBackupCriteria' - ObjectType ObjectTypeBasicBackupCriteria `json:"objectType,omitempty"` -} - -func unmarshalBasicBackupCriteria(body []byte) (BasicBackupCriteria, error) { - var m map[string]interface{} - err := json.Unmarshal(body, &m) - if err != nil { - return nil, err - } - - switch m["objectType"] { - case string(ObjectTypeBasicBackupCriteriaObjectTypeScheduleBasedBackupCriteria): - var sbbc ScheduleBasedBackupCriteria - err := json.Unmarshal(body, &sbbc) - return sbbc, err - default: - var bc BackupCriteria - err := json.Unmarshal(body, &bc) - return bc, err - } -} - -func unmarshalBasicBackupCriteriaArray(body []byte) ([]BasicBackupCriteria, error) { - var rawMessages []*json.RawMessage - err := json.Unmarshal(body, &rawMessages) - if err != nil { - return nil, err - } - - bcArray := make([]BasicBackupCriteria, len(rawMessages)) - - for index, rawMessage := range rawMessages { - bc, err := unmarshalBasicBackupCriteria(*rawMessage) - if err != nil { - return nil, err - } - bcArray[index] = bc - } - return bcArray, nil -} - -// MarshalJSON is the custom marshaler for BackupCriteria. -func (bc BackupCriteria) MarshalJSON() ([]byte, error) { - bc.ObjectType = ObjectTypeBasicBackupCriteriaObjectTypeBackupCriteria - objectMap := make(map[string]interface{}) - if bc.ObjectType != "" { - objectMap["objectType"] = bc.ObjectType - } - return json.Marshal(objectMap) -} - -// AsScheduleBasedBackupCriteria is the BasicBackupCriteria implementation for BackupCriteria. -func (bc BackupCriteria) AsScheduleBasedBackupCriteria() (*ScheduleBasedBackupCriteria, bool) { - return nil, false -} - -// AsBackupCriteria is the BasicBackupCriteria implementation for BackupCriteria. -func (bc BackupCriteria) AsBackupCriteria() (*BackupCriteria, bool) { - return &bc, true -} - -// AsBasicBackupCriteria is the BasicBackupCriteria implementation for BackupCriteria. -func (bc BackupCriteria) AsBasicBackupCriteria() (BasicBackupCriteria, bool) { - return &bc, true -} - -// BackupInstance backup Instance -type BackupInstance struct { - // FriendlyName - Gets or sets the Backup Instance friendly name. - FriendlyName *string `json:"friendlyName,omitempty"` - // DataSourceInfo - Gets or sets the data source information. - DataSourceInfo *Datasource `json:"dataSourceInfo,omitempty"` - // DataSourceSetInfo - Gets or sets the data source set information. - DataSourceSetInfo *DatasourceSet `json:"dataSourceSetInfo,omitempty"` - // PolicyInfo - Gets or sets the policy information. - PolicyInfo *PolicyInfo `json:"policyInfo,omitempty"` - // ProtectionStatus - READ-ONLY; Specifies the protection status of the resource - ProtectionStatus *ProtectionStatusDetails `json:"protectionStatus,omitempty"` - // CurrentProtectionState - READ-ONLY; Specifies the current protection state of the resource. Possible values include: 'CurrentProtectionStateInvalid', 'CurrentProtectionStateNotProtected', 'CurrentProtectionStateConfiguringProtection', 'CurrentProtectionStateProtectionConfigured', 'CurrentProtectionStateBackupSchedulesSuspended', 'CurrentProtectionStateRetentionSchedulesSuspended', 'CurrentProtectionStateProtectionStopped', 'CurrentProtectionStateProtectionError', 'CurrentProtectionStateConfiguringProtectionFailed', 'CurrentProtectionStateSoftDeleting', 'CurrentProtectionStateSoftDeleted', 'CurrentProtectionStateUpdatingProtection' - CurrentProtectionState CurrentProtectionState `json:"currentProtectionState,omitempty"` - // ProtectionErrorDetails - READ-ONLY; Specifies the protection error of the resource - ProtectionErrorDetails *UserFacingError `json:"protectionErrorDetails,omitempty"` - // ProvisioningState - READ-ONLY; Specifies the provisioning state of the resource i.e. provisioning/updating/Succeeded/Failed - ProvisioningState *string `json:"provisioningState,omitempty"` - // DatasourceAuthCredentials - Credentials to use to authenticate with data source provider. - DatasourceAuthCredentials BasicAuthCredentials `json:"datasourceAuthCredentials,omitempty"` - ObjectType *string `json:"objectType,omitempty"` -} - -// MarshalJSON is the custom marshaler for BackupInstance. -func (bi BackupInstance) MarshalJSON() ([]byte, error) { - objectMap := make(map[string]interface{}) - if bi.FriendlyName != nil { - objectMap["friendlyName"] = bi.FriendlyName - } - if bi.DataSourceInfo != nil { - objectMap["dataSourceInfo"] = bi.DataSourceInfo - } - if bi.DataSourceSetInfo != nil { - objectMap["dataSourceSetInfo"] = bi.DataSourceSetInfo - } - if bi.PolicyInfo != nil { - objectMap["policyInfo"] = bi.PolicyInfo - } - objectMap["datasourceAuthCredentials"] = bi.DatasourceAuthCredentials - if bi.ObjectType != nil { - objectMap["objectType"] = bi.ObjectType - } - return json.Marshal(objectMap) -} - -// UnmarshalJSON is the custom unmarshaler for BackupInstance struct. -func (bi *BackupInstance) UnmarshalJSON(body []byte) error { - var m map[string]*json.RawMessage - err := json.Unmarshal(body, &m) - if err != nil { - return err - } - for k, v := range m { - switch k { - case "friendlyName": - if v != nil { - var friendlyName string - err = json.Unmarshal(*v, &friendlyName) - if err != nil { - return err - } - bi.FriendlyName = &friendlyName - } - case "dataSourceInfo": - if v != nil { - var dataSourceInfo Datasource - err = json.Unmarshal(*v, &dataSourceInfo) - if err != nil { - return err - } - bi.DataSourceInfo = &dataSourceInfo - } - case "dataSourceSetInfo": - if v != nil { - var dataSourceSetInfo DatasourceSet - err = json.Unmarshal(*v, &dataSourceSetInfo) - if err != nil { - return err - } - bi.DataSourceSetInfo = &dataSourceSetInfo - } - case "policyInfo": - if v != nil { - var policyInfo PolicyInfo - err = json.Unmarshal(*v, &policyInfo) - if err != nil { - return err - } - bi.PolicyInfo = &policyInfo - } - case "protectionStatus": - if v != nil { - var protectionStatus ProtectionStatusDetails - err = json.Unmarshal(*v, &protectionStatus) - if err != nil { - return err - } - bi.ProtectionStatus = &protectionStatus - } - case "currentProtectionState": - if v != nil { - var currentProtectionState CurrentProtectionState - err = json.Unmarshal(*v, ¤tProtectionState) - if err != nil { - return err - } - bi.CurrentProtectionState = currentProtectionState - } - case "protectionErrorDetails": - if v != nil { - var protectionErrorDetails UserFacingError - err = json.Unmarshal(*v, &protectionErrorDetails) - if err != nil { - return err - } - bi.ProtectionErrorDetails = &protectionErrorDetails - } - case "provisioningState": - if v != nil { - var provisioningState string - err = json.Unmarshal(*v, &provisioningState) - if err != nil { - return err - } - bi.ProvisioningState = &provisioningState - } - case "datasourceAuthCredentials": - if v != nil { - datasourceAuthCredentials, err := unmarshalBasicAuthCredentials(*v) - if err != nil { - return err - } - bi.DatasourceAuthCredentials = datasourceAuthCredentials - } - case "objectType": - if v != nil { - var objectType string - err = json.Unmarshal(*v, &objectType) - if err != nil { - return err - } - bi.ObjectType = &objectType - } - } - } - - return nil -} - -// BackupInstanceResource backupInstance Resource -type BackupInstanceResource struct { - autorest.Response `json:"-"` - // Properties - BackupInstanceResource properties - Properties *BackupInstance `json:"properties,omitempty"` - // ID - READ-ONLY; Resource Id represents the complete path to the resource. - ID *string `json:"id,omitempty"` - // Name - READ-ONLY; Resource name associated with the resource. - Name *string `json:"name,omitempty"` - // Type - READ-ONLY; Resource type represents the complete path of the form Namespace/ResourceType/ResourceType/... - Type *string `json:"type,omitempty"` - SystemData *SystemData `json:"systemData,omitempty"` -} - -// MarshalJSON is the custom marshaler for BackupInstanceResource. -func (bir BackupInstanceResource) MarshalJSON() ([]byte, error) { - objectMap := make(map[string]interface{}) - if bir.Properties != nil { - objectMap["properties"] = bir.Properties - } - if bir.SystemData != nil { - objectMap["systemData"] = bir.SystemData - } - return json.Marshal(objectMap) -} - -// BackupInstanceResourceList backupInstance Resource list response -type BackupInstanceResourceList struct { - autorest.Response `json:"-"` - // Value - List of resources. - Value *[]BackupInstanceResource `json:"value,omitempty"` - // NextLink - The uri to fetch the next page of resources. Call ListNext() fetches next page of resources. - NextLink *string `json:"nextLink,omitempty"` -} - -// BackupInstanceResourceListIterator provides access to a complete listing of BackupInstanceResource -// values. -type BackupInstanceResourceListIterator struct { - i int - page BackupInstanceResourceListPage -} - -// NextWithContext advances to the next value. If there was an error making -// the request the iterator does not advance and the error is returned. -func (iter *BackupInstanceResourceListIterator) NextWithContext(ctx context.Context) (err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/BackupInstanceResourceListIterator.NextWithContext") - defer func() { - sc := -1 - if iter.Response().Response.Response != nil { - sc = iter.Response().Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - iter.i++ - if iter.i < len(iter.page.Values()) { - return nil - } - err = iter.page.NextWithContext(ctx) - if err != nil { - iter.i-- - return err - } - iter.i = 0 - return nil -} - -// Next advances to the next value. If there was an error making -// the request the iterator does not advance and the error is returned. -// Deprecated: Use NextWithContext() instead. -func (iter *BackupInstanceResourceListIterator) Next() error { - return iter.NextWithContext(context.Background()) -} - -// NotDone returns true if the enumeration should be started or is not yet complete. -func (iter BackupInstanceResourceListIterator) NotDone() bool { - return iter.page.NotDone() && iter.i < len(iter.page.Values()) -} - -// Response returns the raw server response from the last page request. -func (iter BackupInstanceResourceListIterator) Response() BackupInstanceResourceList { - return iter.page.Response() -} - -// Value returns the current value or a zero-initialized value if the -// iterator has advanced beyond the end of the collection. -func (iter BackupInstanceResourceListIterator) Value() BackupInstanceResource { - if !iter.page.NotDone() { - return BackupInstanceResource{} - } - return iter.page.Values()[iter.i] -} - -// Creates a new instance of the BackupInstanceResourceListIterator type. -func NewBackupInstanceResourceListIterator(page BackupInstanceResourceListPage) BackupInstanceResourceListIterator { - return BackupInstanceResourceListIterator{page: page} -} - -// IsEmpty returns true if the ListResult contains no values. -func (birl BackupInstanceResourceList) IsEmpty() bool { - return birl.Value == nil || len(*birl.Value) == 0 -} - -// hasNextLink returns true if the NextLink is not empty. -func (birl BackupInstanceResourceList) hasNextLink() bool { - return birl.NextLink != nil && len(*birl.NextLink) != 0 -} - -// backupInstanceResourceListPreparer prepares a request to retrieve the next set of results. -// It returns nil if no more results exist. -func (birl BackupInstanceResourceList) backupInstanceResourceListPreparer(ctx context.Context) (*http.Request, error) { - if !birl.hasNextLink() { - return nil, nil - } - return autorest.Prepare((&http.Request{}).WithContext(ctx), - autorest.AsJSON(), - autorest.AsGet(), - autorest.WithBaseURL(to.String(birl.NextLink))) -} - -// BackupInstanceResourceListPage contains a page of BackupInstanceResource values. -type BackupInstanceResourceListPage struct { - fn func(context.Context, BackupInstanceResourceList) (BackupInstanceResourceList, error) - birl BackupInstanceResourceList -} - -// NextWithContext advances to the next page of values. If there was an error making -// the request the page does not advance and the error is returned. -func (page *BackupInstanceResourceListPage) NextWithContext(ctx context.Context) (err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/BackupInstanceResourceListPage.NextWithContext") - defer func() { - sc := -1 - if page.Response().Response.Response != nil { - sc = page.Response().Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - for { - next, err := page.fn(ctx, page.birl) - if err != nil { - return err - } - page.birl = next - if !next.hasNextLink() || !next.IsEmpty() { - break - } - } - return nil -} - -// Next advances to the next page of values. If there was an error making -// the request the page does not advance and the error is returned. -// Deprecated: Use NextWithContext() instead. -func (page *BackupInstanceResourceListPage) Next() error { - return page.NextWithContext(context.Background()) -} - -// NotDone returns true if the page enumeration should be started or is not yet complete. -func (page BackupInstanceResourceListPage) NotDone() bool { - return !page.birl.IsEmpty() -} - -// Response returns the raw server response from the last page request. -func (page BackupInstanceResourceListPage) Response() BackupInstanceResourceList { - return page.birl -} - -// Values returns the slice of values for the current page or nil if there are no values. -func (page BackupInstanceResourceListPage) Values() []BackupInstanceResource { - if page.birl.IsEmpty() { - return nil - } - return *page.birl.Value -} - -// Creates a new instance of the BackupInstanceResourceListPage type. -func NewBackupInstanceResourceListPage(cur BackupInstanceResourceList, getNextPage func(context.Context, BackupInstanceResourceList) (BackupInstanceResourceList, error)) BackupInstanceResourceListPage { - return BackupInstanceResourceListPage{ - fn: getNextPage, - birl: cur, - } -} - -// BackupInstancesAdhocBackupFuture an abstraction for monitoring and retrieving the results of a -// long-running operation. -type BackupInstancesAdhocBackupFuture struct { - azure.FutureAPI - // Result returns the result of the asynchronous operation. - // If the operation has not completed it will return an error. - Result func(BackupInstancesClient) (OperationJobExtendedInfo, error) -} - -// UnmarshalJSON is the custom unmarshaller for CreateFuture. -func (future *BackupInstancesAdhocBackupFuture) UnmarshalJSON(body []byte) error { - var azFuture azure.Future - if err := json.Unmarshal(body, &azFuture); err != nil { - return err - } - future.FutureAPI = &azFuture - future.Result = future.result - return nil -} - -// result is the default implementation for BackupInstancesAdhocBackupFuture.Result. -func (future *BackupInstancesAdhocBackupFuture) result(client BackupInstancesClient) (ojei OperationJobExtendedInfo, err error) { - var done bool - done, err = future.DoneWithContext(context.Background(), client) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupInstancesAdhocBackupFuture", "Result", future.Response(), "Polling failure") - return - } - if !done { - ojei.Response.Response = future.Response() - err = azure.NewAsyncOpIncompleteError("dataprotection.BackupInstancesAdhocBackupFuture") - return - } - sender := autorest.DecorateSender(client, autorest.DoRetryForStatusCodes(client.RetryAttempts, client.RetryDuration, autorest.StatusCodesForRetry...)) - if ojei.Response.Response, err = future.GetResult(sender); err == nil && ojei.Response.Response.StatusCode != http.StatusNoContent { - ojei, err = client.AdhocBackupResponder(ojei.Response.Response) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupInstancesAdhocBackupFuture", "Result", ojei.Response.Response, "Failure responding to request") - } - } - return -} - -// BackupInstancesCreateOrUpdateFuture an abstraction for monitoring and retrieving the results of a -// long-running operation. -type BackupInstancesCreateOrUpdateFuture struct { - azure.FutureAPI - // Result returns the result of the asynchronous operation. - // If the operation has not completed it will return an error. - Result func(BackupInstancesClient) (BackupInstanceResource, error) -} - -// UnmarshalJSON is the custom unmarshaller for CreateFuture. -func (future *BackupInstancesCreateOrUpdateFuture) UnmarshalJSON(body []byte) error { - var azFuture azure.Future - if err := json.Unmarshal(body, &azFuture); err != nil { - return err - } - future.FutureAPI = &azFuture - future.Result = future.result - return nil -} - -// result is the default implementation for BackupInstancesCreateOrUpdateFuture.Result. -func (future *BackupInstancesCreateOrUpdateFuture) result(client BackupInstancesClient) (bir BackupInstanceResource, err error) { - var done bool - done, err = future.DoneWithContext(context.Background(), client) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupInstancesCreateOrUpdateFuture", "Result", future.Response(), "Polling failure") - return - } - if !done { - bir.Response.Response = future.Response() - err = azure.NewAsyncOpIncompleteError("dataprotection.BackupInstancesCreateOrUpdateFuture") - return - } - sender := autorest.DecorateSender(client, autorest.DoRetryForStatusCodes(client.RetryAttempts, client.RetryDuration, autorest.StatusCodesForRetry...)) - if bir.Response.Response, err = future.GetResult(sender); err == nil && bir.Response.Response.StatusCode != http.StatusNoContent { - bir, err = client.CreateOrUpdateResponder(bir.Response.Response) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupInstancesCreateOrUpdateFuture", "Result", bir.Response.Response, "Failure responding to request") - } - } - return -} - -// BackupInstancesDeleteFuture an abstraction for monitoring and retrieving the results of a long-running -// operation. -type BackupInstancesDeleteFuture struct { - azure.FutureAPI - // Result returns the result of the asynchronous operation. - // If the operation has not completed it will return an error. - Result func(BackupInstancesClient) (autorest.Response, error) -} - -// UnmarshalJSON is the custom unmarshaller for CreateFuture. -func (future *BackupInstancesDeleteFuture) UnmarshalJSON(body []byte) error { - var azFuture azure.Future - if err := json.Unmarshal(body, &azFuture); err != nil { - return err - } - future.FutureAPI = &azFuture - future.Result = future.result - return nil -} - -// result is the default implementation for BackupInstancesDeleteFuture.Result. -func (future *BackupInstancesDeleteFuture) result(client BackupInstancesClient) (ar autorest.Response, err error) { - var done bool - done, err = future.DoneWithContext(context.Background(), client) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupInstancesDeleteFuture", "Result", future.Response(), "Polling failure") - return - } - if !done { - ar.Response = future.Response() - err = azure.NewAsyncOpIncompleteError("dataprotection.BackupInstancesDeleteFuture") - return - } - ar.Response = future.Response() - return -} - -// BackupInstancesTriggerRehydrateFuture an abstraction for monitoring and retrieving the results of a -// long-running operation. -type BackupInstancesTriggerRehydrateFuture struct { - azure.FutureAPI - // Result returns the result of the asynchronous operation. - // If the operation has not completed it will return an error. - Result func(BackupInstancesClient) (autorest.Response, error) -} - -// UnmarshalJSON is the custom unmarshaller for CreateFuture. -func (future *BackupInstancesTriggerRehydrateFuture) UnmarshalJSON(body []byte) error { - var azFuture azure.Future - if err := json.Unmarshal(body, &azFuture); err != nil { - return err - } - future.FutureAPI = &azFuture - future.Result = future.result - return nil -} - -// result is the default implementation for BackupInstancesTriggerRehydrateFuture.Result. -func (future *BackupInstancesTriggerRehydrateFuture) result(client BackupInstancesClient) (ar autorest.Response, err error) { - var done bool - done, err = future.DoneWithContext(context.Background(), client) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupInstancesTriggerRehydrateFuture", "Result", future.Response(), "Polling failure") - return - } - if !done { - ar.Response = future.Response() - err = azure.NewAsyncOpIncompleteError("dataprotection.BackupInstancesTriggerRehydrateFuture") - return - } - ar.Response = future.Response() - return -} - -// BackupInstancesTriggerRestoreFuture an abstraction for monitoring and retrieving the results of a -// long-running operation. -type BackupInstancesTriggerRestoreFuture struct { - azure.FutureAPI - // Result returns the result of the asynchronous operation. - // If the operation has not completed it will return an error. - Result func(BackupInstancesClient) (OperationJobExtendedInfo, error) -} - -// UnmarshalJSON is the custom unmarshaller for CreateFuture. -func (future *BackupInstancesTriggerRestoreFuture) UnmarshalJSON(body []byte) error { - var azFuture azure.Future - if err := json.Unmarshal(body, &azFuture); err != nil { - return err - } - future.FutureAPI = &azFuture - future.Result = future.result - return nil -} - -// result is the default implementation for BackupInstancesTriggerRestoreFuture.Result. -func (future *BackupInstancesTriggerRestoreFuture) result(client BackupInstancesClient) (ojei OperationJobExtendedInfo, err error) { - var done bool - done, err = future.DoneWithContext(context.Background(), client) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupInstancesTriggerRestoreFuture", "Result", future.Response(), "Polling failure") - return - } - if !done { - ojei.Response.Response = future.Response() - err = azure.NewAsyncOpIncompleteError("dataprotection.BackupInstancesTriggerRestoreFuture") - return - } - sender := autorest.DecorateSender(client, autorest.DoRetryForStatusCodes(client.RetryAttempts, client.RetryDuration, autorest.StatusCodesForRetry...)) - if ojei.Response.Response, err = future.GetResult(sender); err == nil && ojei.Response.Response.StatusCode != http.StatusNoContent { - ojei, err = client.TriggerRestoreResponder(ojei.Response.Response) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupInstancesTriggerRestoreFuture", "Result", ojei.Response.Response, "Failure responding to request") - } - } - return -} - -// BackupInstancesValidateForBackupFuture an abstraction for monitoring and retrieving the results of a -// long-running operation. -type BackupInstancesValidateForBackupFuture struct { - azure.FutureAPI - // Result returns the result of the asynchronous operation. - // If the operation has not completed it will return an error. - Result func(BackupInstancesClient) (OperationJobExtendedInfo, error) -} - -// UnmarshalJSON is the custom unmarshaller for CreateFuture. -func (future *BackupInstancesValidateForBackupFuture) UnmarshalJSON(body []byte) error { - var azFuture azure.Future - if err := json.Unmarshal(body, &azFuture); err != nil { - return err - } - future.FutureAPI = &azFuture - future.Result = future.result - return nil -} - -// result is the default implementation for BackupInstancesValidateForBackupFuture.Result. -func (future *BackupInstancesValidateForBackupFuture) result(client BackupInstancesClient) (ojei OperationJobExtendedInfo, err error) { - var done bool - done, err = future.DoneWithContext(context.Background(), client) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupInstancesValidateForBackupFuture", "Result", future.Response(), "Polling failure") - return - } - if !done { - ojei.Response.Response = future.Response() - err = azure.NewAsyncOpIncompleteError("dataprotection.BackupInstancesValidateForBackupFuture") - return - } - sender := autorest.DecorateSender(client, autorest.DoRetryForStatusCodes(client.RetryAttempts, client.RetryDuration, autorest.StatusCodesForRetry...)) - if ojei.Response.Response, err = future.GetResult(sender); err == nil && ojei.Response.Response.StatusCode != http.StatusNoContent { - ojei, err = client.ValidateForBackupResponder(ojei.Response.Response) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupInstancesValidateForBackupFuture", "Result", ojei.Response.Response, "Failure responding to request") - } - } - return -} - -// BackupInstancesValidateForRestoreFuture an abstraction for monitoring and retrieving the results of a -// long-running operation. -type BackupInstancesValidateForRestoreFuture struct { - azure.FutureAPI - // Result returns the result of the asynchronous operation. - // If the operation has not completed it will return an error. - Result func(BackupInstancesClient) (OperationJobExtendedInfo, error) -} - -// UnmarshalJSON is the custom unmarshaller for CreateFuture. -func (future *BackupInstancesValidateForRestoreFuture) UnmarshalJSON(body []byte) error { - var azFuture azure.Future - if err := json.Unmarshal(body, &azFuture); err != nil { - return err - } - future.FutureAPI = &azFuture - future.Result = future.result - return nil -} - -// result is the default implementation for BackupInstancesValidateForRestoreFuture.Result. -func (future *BackupInstancesValidateForRestoreFuture) result(client BackupInstancesClient) (ojei OperationJobExtendedInfo, err error) { - var done bool - done, err = future.DoneWithContext(context.Background(), client) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupInstancesValidateForRestoreFuture", "Result", future.Response(), "Polling failure") - return - } - if !done { - ojei.Response.Response = future.Response() - err = azure.NewAsyncOpIncompleteError("dataprotection.BackupInstancesValidateForRestoreFuture") - return - } - sender := autorest.DecorateSender(client, autorest.DoRetryForStatusCodes(client.RetryAttempts, client.RetryDuration, autorest.StatusCodesForRetry...)) - if ojei.Response.Response, err = future.GetResult(sender); err == nil && ojei.Response.Response.StatusCode != http.StatusNoContent { - ojei, err = client.ValidateForRestoreResponder(ojei.Response.Response) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupInstancesValidateForRestoreFuture", "Result", ojei.Response.Response, "Failure responding to request") - } - } - return -} - -// BasicBackupParameters backupParameters base -type BasicBackupParameters interface { - AsAzureBackupParams() (*AzureBackupParams, bool) - AsBackupParameters() (*BackupParameters, bool) -} - -// BackupParameters backupParameters base -type BackupParameters struct { - // ObjectType - Possible values include: 'ObjectTypeBasicBackupParametersObjectTypeBackupParameters', 'ObjectTypeBasicBackupParametersObjectTypeAzureBackupParams' - ObjectType ObjectTypeBasicBackupParameters `json:"objectType,omitempty"` -} - -func unmarshalBasicBackupParameters(body []byte) (BasicBackupParameters, error) { - var m map[string]interface{} - err := json.Unmarshal(body, &m) - if err != nil { - return nil, err - } - - switch m["objectType"] { - case string(ObjectTypeBasicBackupParametersObjectTypeAzureBackupParams): - var abp AzureBackupParams - err := json.Unmarshal(body, &abp) - return abp, err - default: - var bp BackupParameters - err := json.Unmarshal(body, &bp) - return bp, err - } -} - -func unmarshalBasicBackupParametersArray(body []byte) ([]BasicBackupParameters, error) { - var rawMessages []*json.RawMessage - err := json.Unmarshal(body, &rawMessages) - if err != nil { - return nil, err - } - - bpArray := make([]BasicBackupParameters, len(rawMessages)) - - for index, rawMessage := range rawMessages { - bp, err := unmarshalBasicBackupParameters(*rawMessage) - if err != nil { - return nil, err - } - bpArray[index] = bp - } - return bpArray, nil -} - -// MarshalJSON is the custom marshaler for BackupParameters. -func (bp BackupParameters) MarshalJSON() ([]byte, error) { - bp.ObjectType = ObjectTypeBasicBackupParametersObjectTypeBackupParameters - objectMap := make(map[string]interface{}) - if bp.ObjectType != "" { - objectMap["objectType"] = bp.ObjectType - } - return json.Marshal(objectMap) -} - -// AsAzureBackupParams is the BasicBackupParameters implementation for BackupParameters. -func (bp BackupParameters) AsAzureBackupParams() (*AzureBackupParams, bool) { - return nil, false -} - -// AsBackupParameters is the BasicBackupParameters implementation for BackupParameters. -func (bp BackupParameters) AsBackupParameters() (*BackupParameters, bool) { - return &bp, true -} - -// AsBasicBackupParameters is the BasicBackupParameters implementation for BackupParameters. -func (bp BackupParameters) AsBasicBackupParameters() (BasicBackupParameters, bool) { - return &bp, true -} - -// BackupPolicy rule based backup policy -type BackupPolicy struct { - // PolicyRules - Policy rule dictionary that contains rules for each backuptype i.e Full/Incremental/Logs etc - PolicyRules *[]BasicBasePolicyRule `json:"policyRules,omitempty"` - // DatasourceTypes - Type of datasource for the backup management - DatasourceTypes *[]string `json:"datasourceTypes,omitempty"` - // ObjectType - Possible values include: 'ObjectTypeBasicBaseBackupPolicyObjectTypeBaseBackupPolicy', 'ObjectTypeBasicBaseBackupPolicyObjectTypeBackupPolicy' - ObjectType ObjectTypeBasicBaseBackupPolicy `json:"objectType,omitempty"` -} - -// MarshalJSON is the custom marshaler for BackupPolicy. -func (bp BackupPolicy) MarshalJSON() ([]byte, error) { - bp.ObjectType = ObjectTypeBasicBaseBackupPolicyObjectTypeBackupPolicy - objectMap := make(map[string]interface{}) - if bp.PolicyRules != nil { - objectMap["policyRules"] = bp.PolicyRules - } - if bp.DatasourceTypes != nil { - objectMap["datasourceTypes"] = bp.DatasourceTypes - } - if bp.ObjectType != "" { - objectMap["objectType"] = bp.ObjectType - } - return json.Marshal(objectMap) -} - -// AsBackupPolicy is the BasicBaseBackupPolicy implementation for BackupPolicy. -func (bp BackupPolicy) AsBackupPolicy() (*BackupPolicy, bool) { - return &bp, true -} - -// AsBaseBackupPolicy is the BasicBaseBackupPolicy implementation for BackupPolicy. -func (bp BackupPolicy) AsBaseBackupPolicy() (*BaseBackupPolicy, bool) { - return nil, false -} - -// AsBasicBaseBackupPolicy is the BasicBaseBackupPolicy implementation for BackupPolicy. -func (bp BackupPolicy) AsBasicBaseBackupPolicy() (BasicBaseBackupPolicy, bool) { - return &bp, true -} - -// UnmarshalJSON is the custom unmarshaler for BackupPolicy struct. -func (bp *BackupPolicy) UnmarshalJSON(body []byte) error { - var m map[string]*json.RawMessage - err := json.Unmarshal(body, &m) - if err != nil { - return err - } - for k, v := range m { - switch k { - case "policyRules": - if v != nil { - policyRules, err := unmarshalBasicBasePolicyRuleArray(*v) - if err != nil { - return err - } - bp.PolicyRules = &policyRules - } - case "datasourceTypes": - if v != nil { - var datasourceTypes []string - err = json.Unmarshal(*v, &datasourceTypes) - if err != nil { - return err - } - bp.DatasourceTypes = &datasourceTypes - } - case "objectType": - if v != nil { - var objectType ObjectTypeBasicBaseBackupPolicy - err = json.Unmarshal(*v, &objectType) - if err != nil { - return err - } - bp.ObjectType = objectType - } - } - } - - return nil -} - -// BackupSchedule schedule for backup -type BackupSchedule struct { - // RepeatingTimeIntervals - ISO 8601 repeating time interval format - RepeatingTimeIntervals *[]string `json:"repeatingTimeIntervals,omitempty"` - // TimeZone - Time zone for a schedule. Example: Pacific Standard Time - TimeZone *string `json:"timeZone,omitempty"` -} - -// BackupVault backup Vault -type BackupVault struct { - // ProvisioningState - READ-ONLY; Provisioning state of the BackupVault resource. Possible values include: 'ProvisioningStateFailed', 'ProvisioningStateProvisioning', 'ProvisioningStateSucceeded', 'ProvisioningStateUnknown', 'ProvisioningStateUpdating' - ProvisioningState ProvisioningState `json:"provisioningState,omitempty"` - // ResourceMoveState - READ-ONLY; Resource move state for backup vault. Possible values include: 'ResourceMoveStateUnknown', 'ResourceMoveStateInProgress', 'ResourceMoveStatePrepareFailed', 'ResourceMoveStateCommitFailed', 'ResourceMoveStateFailed', 'ResourceMoveStatePrepareTimedout', 'ResourceMoveStateCommitTimedout', 'ResourceMoveStateCriticalFailure', 'ResourceMoveStatePartialSuccess', 'ResourceMoveStateMoveSucceeded' - ResourceMoveState ResourceMoveState `json:"resourceMoveState,omitempty"` - // ResourceMoveDetails - READ-ONLY; Resource move details for backup vault - ResourceMoveDetails *ResourceMoveDetails `json:"resourceMoveDetails,omitempty"` - // StorageSettings - Storage Settings - StorageSettings *[]StorageSetting `json:"storageSettings,omitempty"` -} - -// MarshalJSON is the custom marshaler for BackupVault. -func (bv BackupVault) MarshalJSON() ([]byte, error) { - objectMap := make(map[string]interface{}) - if bv.StorageSettings != nil { - objectMap["storageSettings"] = bv.StorageSettings - } - return json.Marshal(objectMap) -} - -// BackupVaultResource backup Vault Resource -type BackupVaultResource struct { - autorest.Response `json:"-"` - // Properties - BackupVaultResource properties - Properties *BackupVault `json:"properties,omitempty"` - // ETag - Optional ETag. - ETag *string `json:"eTag,omitempty"` - // ID - READ-ONLY; Resource Id represents the complete path to the resource. - ID *string `json:"id,omitempty"` - // Identity - Input Managed Identity Details - Identity *DppIdentityDetails `json:"identity,omitempty"` - // Location - Resource location. - Location *string `json:"location,omitempty"` - // Name - READ-ONLY; Resource name associated with the resource. - Name *string `json:"name,omitempty"` - // Tags - Resource tags. - Tags map[string]*string `json:"tags"` - // Type - READ-ONLY; Resource type represents the complete path of the form Namespace/ResourceType/ResourceType/... - Type *string `json:"type,omitempty"` - SystemData *SystemData `json:"systemData,omitempty"` -} - -// MarshalJSON is the custom marshaler for BackupVaultResource. -func (bvr BackupVaultResource) MarshalJSON() ([]byte, error) { - objectMap := make(map[string]interface{}) - if bvr.Properties != nil { - objectMap["properties"] = bvr.Properties - } - if bvr.ETag != nil { - objectMap["eTag"] = bvr.ETag - } - if bvr.Identity != nil { - objectMap["identity"] = bvr.Identity - } - if bvr.Location != nil { - objectMap["location"] = bvr.Location - } - if bvr.Tags != nil { - objectMap["tags"] = bvr.Tags - } - if bvr.SystemData != nil { - objectMap["systemData"] = bvr.SystemData - } - return json.Marshal(objectMap) -} - -// BackupVaultResourceList list of BackupVault resources -type BackupVaultResourceList struct { - autorest.Response `json:"-"` - // Value - List of resources. - Value *[]BackupVaultResource `json:"value,omitempty"` - // NextLink - The uri to fetch the next page of resources. Call ListNext() fetches next page of resources. - NextLink *string `json:"nextLink,omitempty"` -} - -// BackupVaultResourceListIterator provides access to a complete listing of BackupVaultResource values. -type BackupVaultResourceListIterator struct { - i int - page BackupVaultResourceListPage -} - -// NextWithContext advances to the next value. If there was an error making -// the request the iterator does not advance and the error is returned. -func (iter *BackupVaultResourceListIterator) NextWithContext(ctx context.Context) (err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/BackupVaultResourceListIterator.NextWithContext") - defer func() { - sc := -1 - if iter.Response().Response.Response != nil { - sc = iter.Response().Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - iter.i++ - if iter.i < len(iter.page.Values()) { - return nil - } - err = iter.page.NextWithContext(ctx) - if err != nil { - iter.i-- - return err - } - iter.i = 0 - return nil -} - -// Next advances to the next value. If there was an error making -// the request the iterator does not advance and the error is returned. -// Deprecated: Use NextWithContext() instead. -func (iter *BackupVaultResourceListIterator) Next() error { - return iter.NextWithContext(context.Background()) -} - -// NotDone returns true if the enumeration should be started or is not yet complete. -func (iter BackupVaultResourceListIterator) NotDone() bool { - return iter.page.NotDone() && iter.i < len(iter.page.Values()) -} - -// Response returns the raw server response from the last page request. -func (iter BackupVaultResourceListIterator) Response() BackupVaultResourceList { - return iter.page.Response() -} - -// Value returns the current value or a zero-initialized value if the -// iterator has advanced beyond the end of the collection. -func (iter BackupVaultResourceListIterator) Value() BackupVaultResource { - if !iter.page.NotDone() { - return BackupVaultResource{} - } - return iter.page.Values()[iter.i] -} - -// Creates a new instance of the BackupVaultResourceListIterator type. -func NewBackupVaultResourceListIterator(page BackupVaultResourceListPage) BackupVaultResourceListIterator { - return BackupVaultResourceListIterator{page: page} -} - -// IsEmpty returns true if the ListResult contains no values. -func (bvrl BackupVaultResourceList) IsEmpty() bool { - return bvrl.Value == nil || len(*bvrl.Value) == 0 -} - -// hasNextLink returns true if the NextLink is not empty. -func (bvrl BackupVaultResourceList) hasNextLink() bool { - return bvrl.NextLink != nil && len(*bvrl.NextLink) != 0 -} - -// backupVaultResourceListPreparer prepares a request to retrieve the next set of results. -// It returns nil if no more results exist. -func (bvrl BackupVaultResourceList) backupVaultResourceListPreparer(ctx context.Context) (*http.Request, error) { - if !bvrl.hasNextLink() { - return nil, nil - } - return autorest.Prepare((&http.Request{}).WithContext(ctx), - autorest.AsJSON(), - autorest.AsGet(), - autorest.WithBaseURL(to.String(bvrl.NextLink))) -} - -// BackupVaultResourceListPage contains a page of BackupVaultResource values. -type BackupVaultResourceListPage struct { - fn func(context.Context, BackupVaultResourceList) (BackupVaultResourceList, error) - bvrl BackupVaultResourceList -} - -// NextWithContext advances to the next page of values. If there was an error making -// the request the page does not advance and the error is returned. -func (page *BackupVaultResourceListPage) NextWithContext(ctx context.Context) (err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/BackupVaultResourceListPage.NextWithContext") - defer func() { - sc := -1 - if page.Response().Response.Response != nil { - sc = page.Response().Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - for { - next, err := page.fn(ctx, page.bvrl) - if err != nil { - return err - } - page.bvrl = next - if !next.hasNextLink() || !next.IsEmpty() { - break - } - } - return nil -} - -// Next advances to the next page of values. If there was an error making -// the request the page does not advance and the error is returned. -// Deprecated: Use NextWithContext() instead. -func (page *BackupVaultResourceListPage) Next() error { - return page.NextWithContext(context.Background()) -} - -// NotDone returns true if the page enumeration should be started or is not yet complete. -func (page BackupVaultResourceListPage) NotDone() bool { - return !page.bvrl.IsEmpty() -} - -// Response returns the raw server response from the last page request. -func (page BackupVaultResourceListPage) Response() BackupVaultResourceList { - return page.bvrl -} - -// Values returns the slice of values for the current page or nil if there are no values. -func (page BackupVaultResourceListPage) Values() []BackupVaultResource { - if page.bvrl.IsEmpty() { - return nil - } - return *page.bvrl.Value -} - -// Creates a new instance of the BackupVaultResourceListPage type. -func NewBackupVaultResourceListPage(cur BackupVaultResourceList, getNextPage func(context.Context, BackupVaultResourceList) (BackupVaultResourceList, error)) BackupVaultResourceListPage { - return BackupVaultResourceListPage{ - fn: getNextPage, - bvrl: cur, - } -} - -// BackupVaultsCreateOrUpdateFuture an abstraction for monitoring and retrieving the results of a -// long-running operation. -type BackupVaultsCreateOrUpdateFuture struct { - azure.FutureAPI - // Result returns the result of the asynchronous operation. - // If the operation has not completed it will return an error. - Result func(BackupVaultsClient) (BackupVaultResource, error) -} - -// UnmarshalJSON is the custom unmarshaller for CreateFuture. -func (future *BackupVaultsCreateOrUpdateFuture) UnmarshalJSON(body []byte) error { - var azFuture azure.Future - if err := json.Unmarshal(body, &azFuture); err != nil { - return err - } - future.FutureAPI = &azFuture - future.Result = future.result - return nil -} - -// result is the default implementation for BackupVaultsCreateOrUpdateFuture.Result. -func (future *BackupVaultsCreateOrUpdateFuture) result(client BackupVaultsClient) (bvr BackupVaultResource, err error) { - var done bool - done, err = future.DoneWithContext(context.Background(), client) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupVaultsCreateOrUpdateFuture", "Result", future.Response(), "Polling failure") - return - } - if !done { - bvr.Response.Response = future.Response() - err = azure.NewAsyncOpIncompleteError("dataprotection.BackupVaultsCreateOrUpdateFuture") - return - } - sender := autorest.DecorateSender(client, autorest.DoRetryForStatusCodes(client.RetryAttempts, client.RetryDuration, autorest.StatusCodesForRetry...)) - if bvr.Response.Response, err = future.GetResult(sender); err == nil && bvr.Response.Response.StatusCode != http.StatusNoContent { - bvr, err = client.CreateOrUpdateResponder(bvr.Response.Response) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupVaultsCreateOrUpdateFuture", "Result", bvr.Response.Response, "Failure responding to request") - } - } - return -} - -// BackupVaultsUpdateFuture an abstraction for monitoring and retrieving the results of a long-running -// operation. -type BackupVaultsUpdateFuture struct { - azure.FutureAPI - // Result returns the result of the asynchronous operation. - // If the operation has not completed it will return an error. - Result func(BackupVaultsClient) (BackupVaultResource, error) -} - -// UnmarshalJSON is the custom unmarshaller for CreateFuture. -func (future *BackupVaultsUpdateFuture) UnmarshalJSON(body []byte) error { - var azFuture azure.Future - if err := json.Unmarshal(body, &azFuture); err != nil { - return err - } - future.FutureAPI = &azFuture - future.Result = future.result - return nil -} - -// result is the default implementation for BackupVaultsUpdateFuture.Result. -func (future *BackupVaultsUpdateFuture) result(client BackupVaultsClient) (bvr BackupVaultResource, err error) { - var done bool - done, err = future.DoneWithContext(context.Background(), client) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupVaultsUpdateFuture", "Result", future.Response(), "Polling failure") - return - } - if !done { - bvr.Response.Response = future.Response() - err = azure.NewAsyncOpIncompleteError("dataprotection.BackupVaultsUpdateFuture") - return - } - sender := autorest.DecorateSender(client, autorest.DoRetryForStatusCodes(client.RetryAttempts, client.RetryDuration, autorest.StatusCodesForRetry...)) - if bvr.Response.Response, err = future.GetResult(sender); err == nil && bvr.Response.Response.StatusCode != http.StatusNoContent { - bvr, err = client.UpdateResponder(bvr.Response.Response) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.BackupVaultsUpdateFuture", "Result", bvr.Response.Response, "Failure responding to request") - } - } - return -} - -// BasicBaseBackupPolicy backupPolicy base -type BasicBaseBackupPolicy interface { - AsBackupPolicy() (*BackupPolicy, bool) - AsBaseBackupPolicy() (*BaseBackupPolicy, bool) -} - -// BaseBackupPolicy backupPolicy base -type BaseBackupPolicy struct { - // DatasourceTypes - Type of datasource for the backup management - DatasourceTypes *[]string `json:"datasourceTypes,omitempty"` - // ObjectType - Possible values include: 'ObjectTypeBasicBaseBackupPolicyObjectTypeBaseBackupPolicy', 'ObjectTypeBasicBaseBackupPolicyObjectTypeBackupPolicy' - ObjectType ObjectTypeBasicBaseBackupPolicy `json:"objectType,omitempty"` -} - -func unmarshalBasicBaseBackupPolicy(body []byte) (BasicBaseBackupPolicy, error) { - var m map[string]interface{} - err := json.Unmarshal(body, &m) - if err != nil { - return nil, err - } - - switch m["objectType"] { - case string(ObjectTypeBasicBaseBackupPolicyObjectTypeBackupPolicy): - var bp BackupPolicy - err := json.Unmarshal(body, &bp) - return bp, err - default: - var bbp BaseBackupPolicy - err := json.Unmarshal(body, &bbp) - return bbp, err - } -} - -func unmarshalBasicBaseBackupPolicyArray(body []byte) ([]BasicBaseBackupPolicy, error) { - var rawMessages []*json.RawMessage - err := json.Unmarshal(body, &rawMessages) - if err != nil { - return nil, err - } - - bbpArray := make([]BasicBaseBackupPolicy, len(rawMessages)) - - for index, rawMessage := range rawMessages { - bbp, err := unmarshalBasicBaseBackupPolicy(*rawMessage) - if err != nil { - return nil, err - } - bbpArray[index] = bbp - } - return bbpArray, nil -} - -// MarshalJSON is the custom marshaler for BaseBackupPolicy. -func (bbp BaseBackupPolicy) MarshalJSON() ([]byte, error) { - bbp.ObjectType = ObjectTypeBasicBaseBackupPolicyObjectTypeBaseBackupPolicy - objectMap := make(map[string]interface{}) - if bbp.DatasourceTypes != nil { - objectMap["datasourceTypes"] = bbp.DatasourceTypes - } - if bbp.ObjectType != "" { - objectMap["objectType"] = bbp.ObjectType - } - return json.Marshal(objectMap) -} - -// AsBackupPolicy is the BasicBaseBackupPolicy implementation for BaseBackupPolicy. -func (bbp BaseBackupPolicy) AsBackupPolicy() (*BackupPolicy, bool) { - return nil, false -} - -// AsBaseBackupPolicy is the BasicBaseBackupPolicy implementation for BaseBackupPolicy. -func (bbp BaseBackupPolicy) AsBaseBackupPolicy() (*BaseBackupPolicy, bool) { - return &bbp, true -} - -// AsBasicBaseBackupPolicy is the BasicBaseBackupPolicy implementation for BaseBackupPolicy. -func (bbp BaseBackupPolicy) AsBasicBaseBackupPolicy() (BasicBaseBackupPolicy, bool) { - return &bbp, true -} - -// BaseBackupPolicyResource baseBackupPolicy resource -type BaseBackupPolicyResource struct { - autorest.Response `json:"-"` - // Properties - BaseBackupPolicyResource properties - Properties BasicBaseBackupPolicy `json:"properties,omitempty"` - // ID - READ-ONLY; Resource Id represents the complete path to the resource. - ID *string `json:"id,omitempty"` - // Name - READ-ONLY; Resource name associated with the resource. - Name *string `json:"name,omitempty"` - // Type - READ-ONLY; Resource type represents the complete path of the form Namespace/ResourceType/ResourceType/... - Type *string `json:"type,omitempty"` - SystemData *SystemData `json:"systemData,omitempty"` -} - -// MarshalJSON is the custom marshaler for BaseBackupPolicyResource. -func (bbpr BaseBackupPolicyResource) MarshalJSON() ([]byte, error) { - objectMap := make(map[string]interface{}) - objectMap["properties"] = bbpr.Properties - if bbpr.SystemData != nil { - objectMap["systemData"] = bbpr.SystemData - } - return json.Marshal(objectMap) -} - -// UnmarshalJSON is the custom unmarshaler for BaseBackupPolicyResource struct. -func (bbpr *BaseBackupPolicyResource) UnmarshalJSON(body []byte) error { - var m map[string]*json.RawMessage - err := json.Unmarshal(body, &m) - if err != nil { - return err - } - for k, v := range m { - switch k { - case "properties": - if v != nil { - properties, err := unmarshalBasicBaseBackupPolicy(*v) - if err != nil { - return err - } - bbpr.Properties = properties - } - case "id": - if v != nil { - var ID string - err = json.Unmarshal(*v, &ID) - if err != nil { - return err - } - bbpr.ID = &ID - } - case "name": - if v != nil { - var name string - err = json.Unmarshal(*v, &name) - if err != nil { - return err - } - bbpr.Name = &name - } - case "type": - if v != nil { - var typeVar string - err = json.Unmarshal(*v, &typeVar) - if err != nil { - return err - } - bbpr.Type = &typeVar - } - case "systemData": - if v != nil { - var systemData SystemData - err = json.Unmarshal(*v, &systemData) - if err != nil { - return err - } - bbpr.SystemData = &systemData - } - } - } - - return nil -} - -// BaseBackupPolicyResourceList list of BaseBackupPolicy resources -type BaseBackupPolicyResourceList struct { - autorest.Response `json:"-"` - // Value - List of resources. - Value *[]BaseBackupPolicyResource `json:"value,omitempty"` - // NextLink - The uri to fetch the next page of resources. Call ListNext() fetches next page of resources. - NextLink *string `json:"nextLink,omitempty"` -} - -// BaseBackupPolicyResourceListIterator provides access to a complete listing of BaseBackupPolicyResource -// values. -type BaseBackupPolicyResourceListIterator struct { - i int - page BaseBackupPolicyResourceListPage -} - -// NextWithContext advances to the next value. If there was an error making -// the request the iterator does not advance and the error is returned. -func (iter *BaseBackupPolicyResourceListIterator) NextWithContext(ctx context.Context) (err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/BaseBackupPolicyResourceListIterator.NextWithContext") - defer func() { - sc := -1 - if iter.Response().Response.Response != nil { - sc = iter.Response().Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - iter.i++ - if iter.i < len(iter.page.Values()) { - return nil - } - err = iter.page.NextWithContext(ctx) - if err != nil { - iter.i-- - return err - } - iter.i = 0 - return nil -} - -// Next advances to the next value. If there was an error making -// the request the iterator does not advance and the error is returned. -// Deprecated: Use NextWithContext() instead. -func (iter *BaseBackupPolicyResourceListIterator) Next() error { - return iter.NextWithContext(context.Background()) -} - -// NotDone returns true if the enumeration should be started or is not yet complete. -func (iter BaseBackupPolicyResourceListIterator) NotDone() bool { - return iter.page.NotDone() && iter.i < len(iter.page.Values()) -} - -// Response returns the raw server response from the last page request. -func (iter BaseBackupPolicyResourceListIterator) Response() BaseBackupPolicyResourceList { - return iter.page.Response() -} - -// Value returns the current value or a zero-initialized value if the -// iterator has advanced beyond the end of the collection. -func (iter BaseBackupPolicyResourceListIterator) Value() BaseBackupPolicyResource { - if !iter.page.NotDone() { - return BaseBackupPolicyResource{} - } - return iter.page.Values()[iter.i] -} - -// Creates a new instance of the BaseBackupPolicyResourceListIterator type. -func NewBaseBackupPolicyResourceListIterator(page BaseBackupPolicyResourceListPage) BaseBackupPolicyResourceListIterator { - return BaseBackupPolicyResourceListIterator{page: page} -} - -// IsEmpty returns true if the ListResult contains no values. -func (bbprl BaseBackupPolicyResourceList) IsEmpty() bool { - return bbprl.Value == nil || len(*bbprl.Value) == 0 -} - -// hasNextLink returns true if the NextLink is not empty. -func (bbprl BaseBackupPolicyResourceList) hasNextLink() bool { - return bbprl.NextLink != nil && len(*bbprl.NextLink) != 0 -} - -// baseBackupPolicyResourceListPreparer prepares a request to retrieve the next set of results. -// It returns nil if no more results exist. -func (bbprl BaseBackupPolicyResourceList) baseBackupPolicyResourceListPreparer(ctx context.Context) (*http.Request, error) { - if !bbprl.hasNextLink() { - return nil, nil - } - return autorest.Prepare((&http.Request{}).WithContext(ctx), - autorest.AsJSON(), - autorest.AsGet(), - autorest.WithBaseURL(to.String(bbprl.NextLink))) -} - -// BaseBackupPolicyResourceListPage contains a page of BaseBackupPolicyResource values. -type BaseBackupPolicyResourceListPage struct { - fn func(context.Context, BaseBackupPolicyResourceList) (BaseBackupPolicyResourceList, error) - bbprl BaseBackupPolicyResourceList -} - -// NextWithContext advances to the next page of values. If there was an error making -// the request the page does not advance and the error is returned. -func (page *BaseBackupPolicyResourceListPage) NextWithContext(ctx context.Context) (err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/BaseBackupPolicyResourceListPage.NextWithContext") - defer func() { - sc := -1 - if page.Response().Response.Response != nil { - sc = page.Response().Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - for { - next, err := page.fn(ctx, page.bbprl) - if err != nil { - return err - } - page.bbprl = next - if !next.hasNextLink() || !next.IsEmpty() { - break - } - } - return nil -} - -// Next advances to the next page of values. If there was an error making -// the request the page does not advance and the error is returned. -// Deprecated: Use NextWithContext() instead. -func (page *BaseBackupPolicyResourceListPage) Next() error { - return page.NextWithContext(context.Background()) -} - -// NotDone returns true if the page enumeration should be started or is not yet complete. -func (page BaseBackupPolicyResourceListPage) NotDone() bool { - return !page.bbprl.IsEmpty() -} - -// Response returns the raw server response from the last page request. -func (page BaseBackupPolicyResourceListPage) Response() BaseBackupPolicyResourceList { - return page.bbprl -} - -// Values returns the slice of values for the current page or nil if there are no values. -func (page BaseBackupPolicyResourceListPage) Values() []BaseBackupPolicyResource { - if page.bbprl.IsEmpty() { - return nil - } - return *page.bbprl.Value -} - -// Creates a new instance of the BaseBackupPolicyResourceListPage type. -func NewBaseBackupPolicyResourceListPage(cur BaseBackupPolicyResourceList, getNextPage func(context.Context, BaseBackupPolicyResourceList) (BaseBackupPolicyResourceList, error)) BaseBackupPolicyResourceListPage { - return BaseBackupPolicyResourceListPage{ - fn: getNextPage, - bbprl: cur, - } -} - -// BasicBasePolicyRule basePolicy Rule -type BasicBasePolicyRule interface { - AsAzureBackupRule() (*AzureBackupRule, bool) - AsAzureRetentionRule() (*AzureRetentionRule, bool) - AsBasePolicyRule() (*BasePolicyRule, bool) -} - -// BasePolicyRule basePolicy Rule -type BasePolicyRule struct { - Name *string `json:"name,omitempty"` - // ObjectType - Possible values include: 'ObjectTypeBasicBasePolicyRuleObjectTypeBasePolicyRule', 'ObjectTypeBasicBasePolicyRuleObjectTypeAzureBackupRule', 'ObjectTypeBasicBasePolicyRuleObjectTypeAzureRetentionRule' - ObjectType ObjectTypeBasicBasePolicyRule `json:"objectType,omitempty"` -} - -func unmarshalBasicBasePolicyRule(body []byte) (BasicBasePolicyRule, error) { - var m map[string]interface{} - err := json.Unmarshal(body, &m) - if err != nil { - return nil, err - } - - switch m["objectType"] { - case string(ObjectTypeBasicBasePolicyRuleObjectTypeAzureBackupRule): - var abr AzureBackupRule - err := json.Unmarshal(body, &abr) - return abr, err - case string(ObjectTypeBasicBasePolicyRuleObjectTypeAzureRetentionRule): - var arr AzureRetentionRule - err := json.Unmarshal(body, &arr) - return arr, err - default: - var bpr BasePolicyRule - err := json.Unmarshal(body, &bpr) - return bpr, err - } -} - -func unmarshalBasicBasePolicyRuleArray(body []byte) ([]BasicBasePolicyRule, error) { - var rawMessages []*json.RawMessage - err := json.Unmarshal(body, &rawMessages) - if err != nil { - return nil, err - } - - bprArray := make([]BasicBasePolicyRule, len(rawMessages)) - - for index, rawMessage := range rawMessages { - bpr, err := unmarshalBasicBasePolicyRule(*rawMessage) - if err != nil { - return nil, err - } - bprArray[index] = bpr - } - return bprArray, nil -} - -// MarshalJSON is the custom marshaler for BasePolicyRule. -func (bpr BasePolicyRule) MarshalJSON() ([]byte, error) { - bpr.ObjectType = ObjectTypeBasicBasePolicyRuleObjectTypeBasePolicyRule - objectMap := make(map[string]interface{}) - if bpr.Name != nil { - objectMap["name"] = bpr.Name - } - if bpr.ObjectType != "" { - objectMap["objectType"] = bpr.ObjectType - } - return json.Marshal(objectMap) -} - -// AsAzureBackupRule is the BasicBasePolicyRule implementation for BasePolicyRule. -func (bpr BasePolicyRule) AsAzureBackupRule() (*AzureBackupRule, bool) { - return nil, false -} - -// AsAzureRetentionRule is the BasicBasePolicyRule implementation for BasePolicyRule. -func (bpr BasePolicyRule) AsAzureRetentionRule() (*AzureRetentionRule, bool) { - return nil, false -} - -// AsBasePolicyRule is the BasicBasePolicyRule implementation for BasePolicyRule. -func (bpr BasePolicyRule) AsBasePolicyRule() (*BasePolicyRule, bool) { - return &bpr, true -} - -// AsBasicBasePolicyRule is the BasicBasePolicyRule implementation for BasePolicyRule. -func (bpr BasePolicyRule) AsBasicBasePolicyRule() (BasicBasePolicyRule, bool) { - return &bpr, true -} - -// CheckNameAvailabilityRequest checkNameAvailability Request -type CheckNameAvailabilityRequest struct { - // Name - Resource name for which availability needs to be checked - Name *string `json:"name,omitempty"` - // Type - Describes the Resource type: Microsoft.DataProtection/BackupVaults - Type *string `json:"type,omitempty"` -} - -// CheckNameAvailabilityResult checkNameAvailability Result -type CheckNameAvailabilityResult struct { - autorest.Response `json:"-"` - // Message - Gets or sets the message. - Message *string `json:"message,omitempty"` - // NameAvailable - Gets or sets a value indicating whether [name available]. - NameAvailable *bool `json:"nameAvailable,omitempty"` - // Reason - Gets or sets the reason. - Reason *string `json:"reason,omitempty"` -} - -// ClientDiscoveryDisplay localized display information of an operation. -type ClientDiscoveryDisplay struct { - // Description - Description of the operation having details of what operation is about. - Description *string `json:"description,omitempty"` - // Operation - Operations Name itself. - Operation *string `json:"operation,omitempty"` - // Provider - Name of the provider for display purposes - Provider *string `json:"provider,omitempty"` - // Resource - ResourceType for which this Operation can be performed. - Resource *string `json:"resource,omitempty"` -} - -// ClientDiscoveryForLogSpecification class to represent shoebox log specification in json client -// discovery. -type ClientDiscoveryForLogSpecification struct { - // BlobDuration - blob duration of shoebox log specification - BlobDuration *string `json:"blobDuration,omitempty"` - // DisplayName - Localized display name - DisplayName *string `json:"displayName,omitempty"` - // Name - Name for shoebox log specification. - Name *string `json:"name,omitempty"` -} - -// ClientDiscoveryForProperties class to represent shoebox properties in json client discovery. -type ClientDiscoveryForProperties struct { - // ServiceSpecification - Operation properties. - ServiceSpecification *ClientDiscoveryForServiceSpecification `json:"serviceSpecification,omitempty"` -} - -// ClientDiscoveryForServiceSpecification class to represent shoebox service specification in json client -// discovery. -type ClientDiscoveryForServiceSpecification struct { - // LogSpecifications - List of log specifications of this operation. - LogSpecifications *[]ClientDiscoveryForLogSpecification `json:"logSpecifications,omitempty"` -} - -// ClientDiscoveryResponse operations List response which contains list of available APIs. -type ClientDiscoveryResponse struct { - autorest.Response `json:"-"` - // NextLink - Link to the next chunk of Response. - NextLink *string `json:"nextLink,omitempty"` - // Value - List of available operations. - Value *[]ClientDiscoveryValueForSingleAPI `json:"value,omitempty"` -} - -// ClientDiscoveryResponseIterator provides access to a complete listing of -// ClientDiscoveryValueForSingleAPI values. -type ClientDiscoveryResponseIterator struct { - i int - page ClientDiscoveryResponsePage -} - -// NextWithContext advances to the next value. If there was an error making -// the request the iterator does not advance and the error is returned. -func (iter *ClientDiscoveryResponseIterator) NextWithContext(ctx context.Context) (err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/ClientDiscoveryResponseIterator.NextWithContext") - defer func() { - sc := -1 - if iter.Response().Response.Response != nil { - sc = iter.Response().Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - iter.i++ - if iter.i < len(iter.page.Values()) { - return nil - } - err = iter.page.NextWithContext(ctx) - if err != nil { - iter.i-- - return err - } - iter.i = 0 - return nil -} - -// Next advances to the next value. If there was an error making -// the request the iterator does not advance and the error is returned. -// Deprecated: Use NextWithContext() instead. -func (iter *ClientDiscoveryResponseIterator) Next() error { - return iter.NextWithContext(context.Background()) -} - -// NotDone returns true if the enumeration should be started or is not yet complete. -func (iter ClientDiscoveryResponseIterator) NotDone() bool { - return iter.page.NotDone() && iter.i < len(iter.page.Values()) -} - -// Response returns the raw server response from the last page request. -func (iter ClientDiscoveryResponseIterator) Response() ClientDiscoveryResponse { - return iter.page.Response() -} - -// Value returns the current value or a zero-initialized value if the -// iterator has advanced beyond the end of the collection. -func (iter ClientDiscoveryResponseIterator) Value() ClientDiscoveryValueForSingleAPI { - if !iter.page.NotDone() { - return ClientDiscoveryValueForSingleAPI{} - } - return iter.page.Values()[iter.i] -} - -// Creates a new instance of the ClientDiscoveryResponseIterator type. -func NewClientDiscoveryResponseIterator(page ClientDiscoveryResponsePage) ClientDiscoveryResponseIterator { - return ClientDiscoveryResponseIterator{page: page} -} - -// IsEmpty returns true if the ListResult contains no values. -func (cdr ClientDiscoveryResponse) IsEmpty() bool { - return cdr.Value == nil || len(*cdr.Value) == 0 -} - -// hasNextLink returns true if the NextLink is not empty. -func (cdr ClientDiscoveryResponse) hasNextLink() bool { - return cdr.NextLink != nil && len(*cdr.NextLink) != 0 -} - -// clientDiscoveryResponsePreparer prepares a request to retrieve the next set of results. -// It returns nil if no more results exist. -func (cdr ClientDiscoveryResponse) clientDiscoveryResponsePreparer(ctx context.Context) (*http.Request, error) { - if !cdr.hasNextLink() { - return nil, nil - } - return autorest.Prepare((&http.Request{}).WithContext(ctx), - autorest.AsJSON(), - autorest.AsGet(), - autorest.WithBaseURL(to.String(cdr.NextLink))) -} - -// ClientDiscoveryResponsePage contains a page of ClientDiscoveryValueForSingleAPI values. -type ClientDiscoveryResponsePage struct { - fn func(context.Context, ClientDiscoveryResponse) (ClientDiscoveryResponse, error) - cdr ClientDiscoveryResponse -} - -// NextWithContext advances to the next page of values. If there was an error making -// the request the page does not advance and the error is returned. -func (page *ClientDiscoveryResponsePage) NextWithContext(ctx context.Context) (err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/ClientDiscoveryResponsePage.NextWithContext") - defer func() { - sc := -1 - if page.Response().Response.Response != nil { - sc = page.Response().Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - for { - next, err := page.fn(ctx, page.cdr) - if err != nil { - return err - } - page.cdr = next - if !next.hasNextLink() || !next.IsEmpty() { - break - } - } - return nil -} - -// Next advances to the next page of values. If there was an error making -// the request the page does not advance and the error is returned. -// Deprecated: Use NextWithContext() instead. -func (page *ClientDiscoveryResponsePage) Next() error { - return page.NextWithContext(context.Background()) -} - -// NotDone returns true if the page enumeration should be started or is not yet complete. -func (page ClientDiscoveryResponsePage) NotDone() bool { - return !page.cdr.IsEmpty() -} - -// Response returns the raw server response from the last page request. -func (page ClientDiscoveryResponsePage) Response() ClientDiscoveryResponse { - return page.cdr -} - -// Values returns the slice of values for the current page or nil if there are no values. -func (page ClientDiscoveryResponsePage) Values() []ClientDiscoveryValueForSingleAPI { - if page.cdr.IsEmpty() { - return nil - } - return *page.cdr.Value -} - -// Creates a new instance of the ClientDiscoveryResponsePage type. -func NewClientDiscoveryResponsePage(cur ClientDiscoveryResponse, getNextPage func(context.Context, ClientDiscoveryResponse) (ClientDiscoveryResponse, error)) ClientDiscoveryResponsePage { - return ClientDiscoveryResponsePage{ - fn: getNextPage, - cdr: cur, - } -} - -// ClientDiscoveryValueForSingleAPI available operation details. -type ClientDiscoveryValueForSingleAPI struct { - // Display - Contains the localized display information for this particular operation - Display *ClientDiscoveryDisplay `json:"display,omitempty"` - // Name - Name of the Operation. - Name *string `json:"name,omitempty"` - // IsDataAction - Indicates whether the operation is a data action - IsDataAction *bool `json:"isDataAction,omitempty"` - // Origin - The intended executor of the operation;governs the display of the operation in the RBAC UX and the audit logs UX - Origin *string `json:"origin,omitempty"` - // Properties - Properties for the given operation. - Properties *ClientDiscoveryForProperties `json:"properties,omitempty"` -} - -// CloudError an error response from Azure Backup. -type CloudError struct { - Error *Error `json:"error,omitempty"` -} - -// CopyOnExpiryOption copy on Expiry Option -type CopyOnExpiryOption struct { - // ObjectType - Possible values include: 'ObjectTypeBasicCopyOptionObjectTypeCopyOption', 'ObjectTypeBasicCopyOptionObjectTypeCopyOnExpiryOption', 'ObjectTypeBasicCopyOptionObjectTypeCustomCopyOption', 'ObjectTypeBasicCopyOptionObjectTypeImmediateCopyOption' - ObjectType ObjectTypeBasicCopyOption `json:"objectType,omitempty"` -} - -// MarshalJSON is the custom marshaler for CopyOnExpiryOption. -func (coeo CopyOnExpiryOption) MarshalJSON() ([]byte, error) { - coeo.ObjectType = ObjectTypeBasicCopyOptionObjectTypeCopyOnExpiryOption - objectMap := make(map[string]interface{}) - if coeo.ObjectType != "" { - objectMap["objectType"] = coeo.ObjectType - } - return json.Marshal(objectMap) -} - -// AsCopyOnExpiryOption is the BasicCopyOption implementation for CopyOnExpiryOption. -func (coeo CopyOnExpiryOption) AsCopyOnExpiryOption() (*CopyOnExpiryOption, bool) { - return &coeo, true -} - -// AsCustomCopyOption is the BasicCopyOption implementation for CopyOnExpiryOption. -func (coeo CopyOnExpiryOption) AsCustomCopyOption() (*CustomCopyOption, bool) { - return nil, false -} - -// AsImmediateCopyOption is the BasicCopyOption implementation for CopyOnExpiryOption. -func (coeo CopyOnExpiryOption) AsImmediateCopyOption() (*ImmediateCopyOption, bool) { - return nil, false -} - -// AsCopyOption is the BasicCopyOption implementation for CopyOnExpiryOption. -func (coeo CopyOnExpiryOption) AsCopyOption() (*CopyOption, bool) { - return nil, false -} - -// AsBasicCopyOption is the BasicCopyOption implementation for CopyOnExpiryOption. -func (coeo CopyOnExpiryOption) AsBasicCopyOption() (BasicCopyOption, bool) { - return &coeo, true -} - -// BasicCopyOption options to copy -type BasicCopyOption interface { - AsCopyOnExpiryOption() (*CopyOnExpiryOption, bool) - AsCustomCopyOption() (*CustomCopyOption, bool) - AsImmediateCopyOption() (*ImmediateCopyOption, bool) - AsCopyOption() (*CopyOption, bool) -} - -// CopyOption options to copy -type CopyOption struct { - // ObjectType - Possible values include: 'ObjectTypeBasicCopyOptionObjectTypeCopyOption', 'ObjectTypeBasicCopyOptionObjectTypeCopyOnExpiryOption', 'ObjectTypeBasicCopyOptionObjectTypeCustomCopyOption', 'ObjectTypeBasicCopyOptionObjectTypeImmediateCopyOption' - ObjectType ObjectTypeBasicCopyOption `json:"objectType,omitempty"` -} - -func unmarshalBasicCopyOption(body []byte) (BasicCopyOption, error) { - var m map[string]interface{} - err := json.Unmarshal(body, &m) - if err != nil { - return nil, err - } - - switch m["objectType"] { - case string(ObjectTypeBasicCopyOptionObjectTypeCopyOnExpiryOption): - var coeo CopyOnExpiryOption - err := json.Unmarshal(body, &coeo) - return coeo, err - case string(ObjectTypeBasicCopyOptionObjectTypeCustomCopyOption): - var cco CustomCopyOption - err := json.Unmarshal(body, &cco) - return cco, err - case string(ObjectTypeBasicCopyOptionObjectTypeImmediateCopyOption): - var ico ImmediateCopyOption - err := json.Unmarshal(body, &ico) - return ico, err - default: - var co CopyOption - err := json.Unmarshal(body, &co) - return co, err - } -} - -func unmarshalBasicCopyOptionArray(body []byte) ([]BasicCopyOption, error) { - var rawMessages []*json.RawMessage - err := json.Unmarshal(body, &rawMessages) - if err != nil { - return nil, err - } - - coArray := make([]BasicCopyOption, len(rawMessages)) - - for index, rawMessage := range rawMessages { - co, err := unmarshalBasicCopyOption(*rawMessage) - if err != nil { - return nil, err - } - coArray[index] = co - } - return coArray, nil -} - -// MarshalJSON is the custom marshaler for CopyOption. -func (co CopyOption) MarshalJSON() ([]byte, error) { - co.ObjectType = ObjectTypeBasicCopyOptionObjectTypeCopyOption - objectMap := make(map[string]interface{}) - if co.ObjectType != "" { - objectMap["objectType"] = co.ObjectType - } - return json.Marshal(objectMap) -} - -// AsCopyOnExpiryOption is the BasicCopyOption implementation for CopyOption. -func (co CopyOption) AsCopyOnExpiryOption() (*CopyOnExpiryOption, bool) { - return nil, false -} - -// AsCustomCopyOption is the BasicCopyOption implementation for CopyOption. -func (co CopyOption) AsCustomCopyOption() (*CustomCopyOption, bool) { - return nil, false -} - -// AsImmediateCopyOption is the BasicCopyOption implementation for CopyOption. -func (co CopyOption) AsImmediateCopyOption() (*ImmediateCopyOption, bool) { - return nil, false -} - -// AsCopyOption is the BasicCopyOption implementation for CopyOption. -func (co CopyOption) AsCopyOption() (*CopyOption, bool) { - return &co, true -} - -// AsBasicCopyOption is the BasicCopyOption implementation for CopyOption. -func (co CopyOption) AsBasicCopyOption() (BasicCopyOption, bool) { - return &co, true -} - -// CustomCopyOption duration based custom options to copy -type CustomCopyOption struct { - // Duration - Data copied after given timespan - Duration *string `json:"duration,omitempty"` - // ObjectType - Possible values include: 'ObjectTypeBasicCopyOptionObjectTypeCopyOption', 'ObjectTypeBasicCopyOptionObjectTypeCopyOnExpiryOption', 'ObjectTypeBasicCopyOptionObjectTypeCustomCopyOption', 'ObjectTypeBasicCopyOptionObjectTypeImmediateCopyOption' - ObjectType ObjectTypeBasicCopyOption `json:"objectType,omitempty"` -} - -// MarshalJSON is the custom marshaler for CustomCopyOption. -func (cco CustomCopyOption) MarshalJSON() ([]byte, error) { - cco.ObjectType = ObjectTypeBasicCopyOptionObjectTypeCustomCopyOption - objectMap := make(map[string]interface{}) - if cco.Duration != nil { - objectMap["duration"] = cco.Duration - } - if cco.ObjectType != "" { - objectMap["objectType"] = cco.ObjectType - } - return json.Marshal(objectMap) -} - -// AsCopyOnExpiryOption is the BasicCopyOption implementation for CustomCopyOption. -func (cco CustomCopyOption) AsCopyOnExpiryOption() (*CopyOnExpiryOption, bool) { - return nil, false -} - -// AsCustomCopyOption is the BasicCopyOption implementation for CustomCopyOption. -func (cco CustomCopyOption) AsCustomCopyOption() (*CustomCopyOption, bool) { - return &cco, true -} - -// AsImmediateCopyOption is the BasicCopyOption implementation for CustomCopyOption. -func (cco CustomCopyOption) AsImmediateCopyOption() (*ImmediateCopyOption, bool) { - return nil, false -} - -// AsCopyOption is the BasicCopyOption implementation for CustomCopyOption. -func (cco CustomCopyOption) AsCopyOption() (*CopyOption, bool) { - return nil, false -} - -// AsBasicCopyOption is the BasicCopyOption implementation for CustomCopyOption. -func (cco CustomCopyOption) AsBasicCopyOption() (BasicCopyOption, bool) { - return &cco, true -} - -// Datasource datasource to be backed up -type Datasource struct { - // DatasourceType - DatasourceType of the resource. - DatasourceType *string `json:"datasourceType,omitempty"` - // ObjectType - Type of Datasource object, used to initialize the right inherited type - ObjectType *string `json:"objectType,omitempty"` - // ResourceID - Full ARM ID of the resource. For azure resources, this is ARM ID. For non azure resources, this will be the ID created by backup service via Fabric/Vault. - ResourceID *string `json:"resourceID,omitempty"` - // ResourceLocation - Location of datasource. - ResourceLocation *string `json:"resourceLocation,omitempty"` - // ResourceName - Unique identifier of the resource in the context of parent. - ResourceName *string `json:"resourceName,omitempty"` - // ResourceType - Resource Type of Datasource. - ResourceType *string `json:"resourceType,omitempty"` - // ResourceURI - Uri of the resource. - ResourceURI *string `json:"resourceUri,omitempty"` -} - -// DatasourceSet datasourceSet details of datasource to be backed up -type DatasourceSet struct { - // DatasourceType - DatasourceType of the resource. - DatasourceType *string `json:"datasourceType,omitempty"` - // ObjectType - Type of Datasource object, used to initialize the right inherited type - ObjectType *string `json:"objectType,omitempty"` - // ResourceID - Full ARM ID of the resource. For azure resources, this is ARM ID. For non azure resources, this will be the ID created by backup service via Fabric/Vault. - ResourceID *string `json:"resourceID,omitempty"` - // ResourceLocation - Location of datasource. - ResourceLocation *string `json:"resourceLocation,omitempty"` - // ResourceName - Unique identifier of the resource in the context of parent. - ResourceName *string `json:"resourceName,omitempty"` - // ResourceType - Resource Type of Datasource. - ResourceType *string `json:"resourceType,omitempty"` - // ResourceURI - Uri of the resource. - ResourceURI *string `json:"resourceUri,omitempty"` -} - -// DataStoreInfoBase dataStoreInfo base -type DataStoreInfoBase struct { - // DataStoreType - type of datastore; Operational/Vault/Archive. Possible values include: 'DataStoreTypesOperationalStore', 'DataStoreTypesVaultStore', 'DataStoreTypesArchiveStore' - DataStoreType DataStoreTypes `json:"dataStoreType,omitempty"` - // ObjectType - Type of Datasource object, used to initialize the right inherited type - ObjectType *string `json:"objectType,omitempty"` -} - -// BasicDataStoreParameters parameters for DataStore -type BasicDataStoreParameters interface { - AsAzureOperationalStoreParameters() (*AzureOperationalStoreParameters, bool) - AsDataStoreParameters() (*DataStoreParameters, bool) -} - -// DataStoreParameters parameters for DataStore -type DataStoreParameters struct { - // DataStoreType - type of datastore; Operational/Vault/Archive. Possible values include: 'DataStoreTypesOperationalStore', 'DataStoreTypesVaultStore', 'DataStoreTypesArchiveStore' - DataStoreType DataStoreTypes `json:"dataStoreType,omitempty"` - // ObjectType - Possible values include: 'ObjectTypeBasicDataStoreParametersObjectTypeDataStoreParameters', 'ObjectTypeBasicDataStoreParametersObjectTypeAzureOperationalStoreParameters' - ObjectType ObjectTypeBasicDataStoreParameters `json:"objectType,omitempty"` -} - -func unmarshalBasicDataStoreParameters(body []byte) (BasicDataStoreParameters, error) { - var m map[string]interface{} - err := json.Unmarshal(body, &m) - if err != nil { - return nil, err - } - - switch m["objectType"] { - case string(ObjectTypeBasicDataStoreParametersObjectTypeAzureOperationalStoreParameters): - var aosp AzureOperationalStoreParameters - err := json.Unmarshal(body, &aosp) - return aosp, err - default: - var dsp DataStoreParameters - err := json.Unmarshal(body, &dsp) - return dsp, err - } -} - -func unmarshalBasicDataStoreParametersArray(body []byte) ([]BasicDataStoreParameters, error) { - var rawMessages []*json.RawMessage - err := json.Unmarshal(body, &rawMessages) - if err != nil { - return nil, err - } - - dspArray := make([]BasicDataStoreParameters, len(rawMessages)) - - for index, rawMessage := range rawMessages { - dsp, err := unmarshalBasicDataStoreParameters(*rawMessage) - if err != nil { - return nil, err - } - dspArray[index] = dsp - } - return dspArray, nil -} - -// MarshalJSON is the custom marshaler for DataStoreParameters. -func (dsp DataStoreParameters) MarshalJSON() ([]byte, error) { - dsp.ObjectType = ObjectTypeBasicDataStoreParametersObjectTypeDataStoreParameters - objectMap := make(map[string]interface{}) - if dsp.DataStoreType != "" { - objectMap["dataStoreType"] = dsp.DataStoreType - } - if dsp.ObjectType != "" { - objectMap["objectType"] = dsp.ObjectType - } - return json.Marshal(objectMap) -} - -// AsAzureOperationalStoreParameters is the BasicDataStoreParameters implementation for DataStoreParameters. -func (dsp DataStoreParameters) AsAzureOperationalStoreParameters() (*AzureOperationalStoreParameters, bool) { - return nil, false -} - -// AsDataStoreParameters is the BasicDataStoreParameters implementation for DataStoreParameters. -func (dsp DataStoreParameters) AsDataStoreParameters() (*DataStoreParameters, bool) { - return &dsp, true -} - -// AsBasicDataStoreParameters is the BasicDataStoreParameters implementation for DataStoreParameters. -func (dsp DataStoreParameters) AsBasicDataStoreParameters() (BasicDataStoreParameters, bool) { - return &dsp, true -} - -// Day day of the week -type Day struct { - // Date - Date of the month - Date *int32 `json:"date,omitempty"` - // IsLast - Whether Date is last date of month - IsLast *bool `json:"isLast,omitempty"` -} - -// BasicDeleteOption delete Option -type BasicDeleteOption interface { - AsAbsoluteDeleteOption() (*AbsoluteDeleteOption, bool) - AsDeleteOption() (*DeleteOption, bool) -} - -// DeleteOption delete Option -type DeleteOption struct { - // Duration - Duration of deletion after given timespan - Duration *string `json:"duration,omitempty"` - // ObjectType - Possible values include: 'ObjectTypeBasicDeleteOptionObjectTypeDeleteOption', 'ObjectTypeBasicDeleteOptionObjectTypeAbsoluteDeleteOption' - ObjectType ObjectTypeBasicDeleteOption `json:"objectType,omitempty"` -} - -func unmarshalBasicDeleteOption(body []byte) (BasicDeleteOption, error) { - var m map[string]interface{} - err := json.Unmarshal(body, &m) - if err != nil { - return nil, err - } - - switch m["objectType"] { - case string(ObjectTypeBasicDeleteOptionObjectTypeAbsoluteDeleteOption): - var ado AbsoluteDeleteOption - err := json.Unmarshal(body, &ado) - return ado, err - default: - var do DeleteOption - err := json.Unmarshal(body, &do) - return do, err - } -} - -func unmarshalBasicDeleteOptionArray(body []byte) ([]BasicDeleteOption, error) { - var rawMessages []*json.RawMessage - err := json.Unmarshal(body, &rawMessages) - if err != nil { - return nil, err - } - - doArray := make([]BasicDeleteOption, len(rawMessages)) - - for index, rawMessage := range rawMessages { - do, err := unmarshalBasicDeleteOption(*rawMessage) - if err != nil { - return nil, err - } - doArray[index] = do - } - return doArray, nil -} - -// MarshalJSON is the custom marshaler for DeleteOption. -func (do DeleteOption) MarshalJSON() ([]byte, error) { - do.ObjectType = ObjectTypeBasicDeleteOptionObjectTypeDeleteOption - objectMap := make(map[string]interface{}) - if do.Duration != nil { - objectMap["duration"] = do.Duration - } - if do.ObjectType != "" { - objectMap["objectType"] = do.ObjectType - } - return json.Marshal(objectMap) -} - -// AsAbsoluteDeleteOption is the BasicDeleteOption implementation for DeleteOption. -func (do DeleteOption) AsAbsoluteDeleteOption() (*AbsoluteDeleteOption, bool) { - return nil, false -} - -// AsDeleteOption is the BasicDeleteOption implementation for DeleteOption. -func (do DeleteOption) AsDeleteOption() (*DeleteOption, bool) { - return &do, true -} - -// AsBasicDeleteOption is the BasicDeleteOption implementation for DeleteOption. -func (do DeleteOption) AsBasicDeleteOption() (BasicDeleteOption, bool) { - return &do, true -} - -// DppBaseResource base resource under Microsoft.DataProtection provider namespace -type DppBaseResource struct { - autorest.Response `json:"-"` - // ID - READ-ONLY; Resource Id represents the complete path to the resource. - ID *string `json:"id,omitempty"` - // Name - READ-ONLY; Resource name associated with the resource. - Name *string `json:"name,omitempty"` - // Type - READ-ONLY; Resource type represents the complete path of the form Namespace/ResourceType/ResourceType/... - Type *string `json:"type,omitempty"` -} - -// MarshalJSON is the custom marshaler for DppBaseResource. -func (dbr DppBaseResource) MarshalJSON() ([]byte, error) { - objectMap := make(map[string]interface{}) - return json.Marshal(objectMap) -} - -// DppBaseResourceList base for all lists of V2 resources. -type DppBaseResourceList struct { - autorest.Response `json:"-"` - // Value - List of Dpp resources. - Value *[]DppBaseResource `json:"value,omitempty"` - // NextLink - The uri to fetch the next page of resources. Call ListNext() fetches next page of resources. - NextLink *string `json:"nextLink,omitempty"` -} - -// DppBaseResourceListIterator provides access to a complete listing of DppBaseResource values. -type DppBaseResourceListIterator struct { - i int - page DppBaseResourceListPage -} - -// NextWithContext advances to the next value. If there was an error making -// the request the iterator does not advance and the error is returned. -func (iter *DppBaseResourceListIterator) NextWithContext(ctx context.Context) (err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/DppBaseResourceListIterator.NextWithContext") - defer func() { - sc := -1 - if iter.Response().Response.Response != nil { - sc = iter.Response().Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - iter.i++ - if iter.i < len(iter.page.Values()) { - return nil - } - err = iter.page.NextWithContext(ctx) - if err != nil { - iter.i-- - return err - } - iter.i = 0 - return nil -} - -// Next advances to the next value. If there was an error making -// the request the iterator does not advance and the error is returned. -// Deprecated: Use NextWithContext() instead. -func (iter *DppBaseResourceListIterator) Next() error { - return iter.NextWithContext(context.Background()) -} - -// NotDone returns true if the enumeration should be started or is not yet complete. -func (iter DppBaseResourceListIterator) NotDone() bool { - return iter.page.NotDone() && iter.i < len(iter.page.Values()) -} - -// Response returns the raw server response from the last page request. -func (iter DppBaseResourceListIterator) Response() DppBaseResourceList { - return iter.page.Response() -} - -// Value returns the current value or a zero-initialized value if the -// iterator has advanced beyond the end of the collection. -func (iter DppBaseResourceListIterator) Value() DppBaseResource { - if !iter.page.NotDone() { - return DppBaseResource{} - } - return iter.page.Values()[iter.i] -} - -// Creates a new instance of the DppBaseResourceListIterator type. -func NewDppBaseResourceListIterator(page DppBaseResourceListPage) DppBaseResourceListIterator { - return DppBaseResourceListIterator{page: page} -} - -// IsEmpty returns true if the ListResult contains no values. -func (dbrl DppBaseResourceList) IsEmpty() bool { - return dbrl.Value == nil || len(*dbrl.Value) == 0 -} - -// hasNextLink returns true if the NextLink is not empty. -func (dbrl DppBaseResourceList) hasNextLink() bool { - return dbrl.NextLink != nil && len(*dbrl.NextLink) != 0 -} - -// dppBaseResourceListPreparer prepares a request to retrieve the next set of results. -// It returns nil if no more results exist. -func (dbrl DppBaseResourceList) dppBaseResourceListPreparer(ctx context.Context) (*http.Request, error) { - if !dbrl.hasNextLink() { - return nil, nil - } - return autorest.Prepare((&http.Request{}).WithContext(ctx), - autorest.AsJSON(), - autorest.AsGet(), - autorest.WithBaseURL(to.String(dbrl.NextLink))) -} - -// DppBaseResourceListPage contains a page of DppBaseResource values. -type DppBaseResourceListPage struct { - fn func(context.Context, DppBaseResourceList) (DppBaseResourceList, error) - dbrl DppBaseResourceList -} - -// NextWithContext advances to the next page of values. If there was an error making -// the request the page does not advance and the error is returned. -func (page *DppBaseResourceListPage) NextWithContext(ctx context.Context) (err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/DppBaseResourceListPage.NextWithContext") - defer func() { - sc := -1 - if page.Response().Response.Response != nil { - sc = page.Response().Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - for { - next, err := page.fn(ctx, page.dbrl) - if err != nil { - return err - } - page.dbrl = next - if !next.hasNextLink() || !next.IsEmpty() { - break - } - } - return nil -} - -// Next advances to the next page of values. If there was an error making -// the request the page does not advance and the error is returned. -// Deprecated: Use NextWithContext() instead. -func (page *DppBaseResourceListPage) Next() error { - return page.NextWithContext(context.Background()) -} - -// NotDone returns true if the page enumeration should be started or is not yet complete. -func (page DppBaseResourceListPage) NotDone() bool { - return !page.dbrl.IsEmpty() -} - -// Response returns the raw server response from the last page request. -func (page DppBaseResourceListPage) Response() DppBaseResourceList { - return page.dbrl -} - -// Values returns the slice of values for the current page or nil if there are no values. -func (page DppBaseResourceListPage) Values() []DppBaseResource { - if page.dbrl.IsEmpty() { - return nil - } - return *page.dbrl.Value -} - -// Creates a new instance of the DppBaseResourceListPage type. -func NewDppBaseResourceListPage(cur DppBaseResourceList, getNextPage func(context.Context, DppBaseResourceList) (DppBaseResourceList, error)) DppBaseResourceListPage { - return DppBaseResourceListPage{ - fn: getNextPage, - dbrl: cur, - } -} - -// DppIdentityDetails identity details -type DppIdentityDetails struct { - // PrincipalID - READ-ONLY; The object ID of the service principal object for the managed identity that is used to grant role-based access to an Azure resource. - PrincipalID *string `json:"principalId,omitempty"` - // TenantID - READ-ONLY; A Globally Unique Identifier (GUID) that represents the Azure AD tenant where the resource is now a member. - TenantID *string `json:"tenantId,omitempty"` - // Type - The identityType which can be either SystemAssigned or None - Type *string `json:"type,omitempty"` -} - -// MarshalJSON is the custom marshaler for DppIdentityDetails. -func (did DppIdentityDetails) MarshalJSON() ([]byte, error) { - objectMap := make(map[string]interface{}) - if did.Type != nil { - objectMap["type"] = did.Type - } - return json.Marshal(objectMap) -} - -// DppResource resource class -type DppResource struct { - // ID - READ-ONLY; Resource Id represents the complete path to the resource. - ID *string `json:"id,omitempty"` - // Name - READ-ONLY; Resource name associated with the resource. - Name *string `json:"name,omitempty"` - // Type - READ-ONLY; Resource type represents the complete path of the form Namespace/ResourceType/ResourceType/... - Type *string `json:"type,omitempty"` - SystemData *SystemData `json:"systemData,omitempty"` -} - -// MarshalJSON is the custom marshaler for DppResource. -func (dr DppResource) MarshalJSON() ([]byte, error) { - objectMap := make(map[string]interface{}) - if dr.SystemData != nil { - objectMap["systemData"] = dr.SystemData - } - return json.Marshal(objectMap) -} - -// DppResourceList listResource -type DppResourceList struct { - // NextLink - The uri to fetch the next page of resources. Call ListNext() fetches next page of resources. - NextLink *string `json:"nextLink,omitempty"` -} - -// DppTrackedResource ... -type DppTrackedResource struct { - // ETag - Optional ETag. - ETag *string `json:"eTag,omitempty"` - // ID - READ-ONLY; Resource Id represents the complete path to the resource. - ID *string `json:"id,omitempty"` - // Identity - Input Managed Identity Details - Identity *DppIdentityDetails `json:"identity,omitempty"` - // Location - Resource location. - Location *string `json:"location,omitempty"` - // Name - READ-ONLY; Resource name associated with the resource. - Name *string `json:"name,omitempty"` - // Tags - Resource tags. - Tags map[string]*string `json:"tags"` - // Type - READ-ONLY; Resource type represents the complete path of the form Namespace/ResourceType/ResourceType/... - Type *string `json:"type,omitempty"` - SystemData *SystemData `json:"systemData,omitempty"` -} - -// MarshalJSON is the custom marshaler for DppTrackedResource. -func (dtr DppTrackedResource) MarshalJSON() ([]byte, error) { - objectMap := make(map[string]interface{}) - if dtr.ETag != nil { - objectMap["eTag"] = dtr.ETag - } - if dtr.Identity != nil { - objectMap["identity"] = dtr.Identity - } - if dtr.Location != nil { - objectMap["location"] = dtr.Location - } - if dtr.Tags != nil { - objectMap["tags"] = dtr.Tags - } - if dtr.SystemData != nil { - objectMap["systemData"] = dtr.SystemData - } - return json.Marshal(objectMap) -} - -// DppTrackedResourceList ... -type DppTrackedResourceList struct { - // NextLink - The uri to fetch the next page of resources. Call ListNext() fetches next page of resources. - NextLink *string `json:"nextLink,omitempty"` -} - -// DppWorkerRequest ... -type DppWorkerRequest struct { - SubscriptionID *string `json:"subscriptionId,omitempty"` - URI *string `json:"uri,omitempty"` - Headers map[string][]string `json:"headers"` - SupportedGroupVersions *[]string `json:"supportedGroupVersions,omitempty"` - CultureInfo *string `json:"cultureInfo,omitempty"` - Parameters map[string]*string `json:"parameters"` - HTTPMethod *string `json:"httpMethod,omitempty"` -} - -// MarshalJSON is the custom marshaler for DppWorkerRequest. -func (dwr DppWorkerRequest) MarshalJSON() ([]byte, error) { - objectMap := make(map[string]interface{}) - if dwr.SubscriptionID != nil { - objectMap["subscriptionId"] = dwr.SubscriptionID - } - if dwr.URI != nil { - objectMap["uri"] = dwr.URI - } - if dwr.Headers != nil { - objectMap["headers"] = dwr.Headers - } - if dwr.SupportedGroupVersions != nil { - objectMap["supportedGroupVersions"] = dwr.SupportedGroupVersions - } - if dwr.CultureInfo != nil { - objectMap["cultureInfo"] = dwr.CultureInfo - } - if dwr.Parameters != nil { - objectMap["parameters"] = dwr.Parameters - } - if dwr.HTTPMethod != nil { - objectMap["httpMethod"] = dwr.HTTPMethod - } - return json.Marshal(objectMap) -} - -// Error the resource management error response. -type Error struct { - // AdditionalInfo - READ-ONLY; The error additional info. - AdditionalInfo *[]ErrorAdditionalInfo `json:"additionalInfo,omitempty"` - // Code - READ-ONLY; The error code. - Code *string `json:"code,omitempty"` - // Details - READ-ONLY; The error details. - Details *[]Error `json:"details,omitempty"` - // Message - READ-ONLY; The error message. - Message *string `json:"message,omitempty"` - // Target - READ-ONLY; The error target. - Target *string `json:"target,omitempty"` -} - -// MarshalJSON is the custom marshaler for Error. -func (e Error) MarshalJSON() ([]byte, error) { - objectMap := make(map[string]interface{}) - return json.Marshal(objectMap) -} - -// ErrorAdditionalInfo the resource management error additional info. -type ErrorAdditionalInfo struct { - // Info - READ-ONLY; The additional info. - Info interface{} `json:"info,omitempty"` - // Type - READ-ONLY; The additional info type. - Type *string `json:"type,omitempty"` -} - -// MarshalJSON is the custom marshaler for ErrorAdditionalInfo. -func (eai ErrorAdditionalInfo) MarshalJSON() ([]byte, error) { - objectMap := make(map[string]interface{}) - return json.Marshal(objectMap) -} - -// ExportJobsResult the result for export jobs containing blob details. -type ExportJobsResult struct { - autorest.Response `json:"-"` - // BlobURL - READ-ONLY; URL of the blob into which the serialized string of list of jobs is exported. - BlobURL *string `json:"blobUrl,omitempty"` - // BlobSasKey - READ-ONLY; SAS key to access the blob. - BlobSasKey *string `json:"blobSasKey,omitempty"` - // ExcelFileBlobURL - READ-ONLY; URL of the blob into which the ExcelFile is uploaded. - ExcelFileBlobURL *string `json:"excelFileBlobUrl,omitempty"` - // ExcelFileBlobSasKey - READ-ONLY; SAS key to access the ExcelFile blob. - ExcelFileBlobSasKey *string `json:"excelFileBlobSasKey,omitempty"` -} - -// MarshalJSON is the custom marshaler for ExportJobsResult. -func (ejr ExportJobsResult) MarshalJSON() ([]byte, error) { - objectMap := make(map[string]interface{}) - return json.Marshal(objectMap) -} - -// ExportJobsTriggerFuture an abstraction for monitoring and retrieving the results of a long-running -// operation. -type ExportJobsTriggerFuture struct { - azure.FutureAPI - // Result returns the result of the asynchronous operation. - // If the operation has not completed it will return an error. - Result func(ExportJobsClient) (autorest.Response, error) -} - -// UnmarshalJSON is the custom unmarshaller for CreateFuture. -func (future *ExportJobsTriggerFuture) UnmarshalJSON(body []byte) error { - var azFuture azure.Future - if err := json.Unmarshal(body, &azFuture); err != nil { - return err - } - future.FutureAPI = &azFuture - future.Result = future.result - return nil -} - -// result is the default implementation for ExportJobsTriggerFuture.Result. -func (future *ExportJobsTriggerFuture) result(client ExportJobsClient) (ar autorest.Response, err error) { - var done bool - done, err = future.DoneWithContext(context.Background(), client) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ExportJobsTriggerFuture", "Result", future.Response(), "Polling failure") - return - } - if !done { - ar.Response = future.Response() - err = azure.NewAsyncOpIncompleteError("dataprotection.ExportJobsTriggerFuture") - return - } - ar.Response = future.Response() - return -} - -// FeatureValidationRequest base class for feature object -type FeatureValidationRequest struct { - // FeatureType - backup support feature type. Possible values include: 'FeatureTypeInvalid', 'FeatureTypeDataSourceType' - FeatureType FeatureType `json:"featureType,omitempty"` - // FeatureName - backup support feature name. - FeatureName *string `json:"featureName,omitempty"` - // ObjectType - Possible values include: 'ObjectTypeBasicFeatureValidationRequestBaseObjectTypeFeatureValidationRequestBase', 'ObjectTypeBasicFeatureValidationRequestBaseObjectTypeFeatureValidationRequest' - ObjectType ObjectTypeBasicFeatureValidationRequestBase `json:"objectType,omitempty"` -} - -// MarshalJSON is the custom marshaler for FeatureValidationRequest. -func (fvr FeatureValidationRequest) MarshalJSON() ([]byte, error) { - fvr.ObjectType = ObjectTypeBasicFeatureValidationRequestBaseObjectTypeFeatureValidationRequest - objectMap := make(map[string]interface{}) - if fvr.FeatureType != "" { - objectMap["featureType"] = fvr.FeatureType - } - if fvr.FeatureName != nil { - objectMap["featureName"] = fvr.FeatureName - } - if fvr.ObjectType != "" { - objectMap["objectType"] = fvr.ObjectType - } - return json.Marshal(objectMap) -} - -// AsFeatureValidationRequest is the BasicFeatureValidationRequestBase implementation for FeatureValidationRequest. -func (fvr FeatureValidationRequest) AsFeatureValidationRequest() (*FeatureValidationRequest, bool) { - return &fvr, true -} - -// AsFeatureValidationRequestBase is the BasicFeatureValidationRequestBase implementation for FeatureValidationRequest. -func (fvr FeatureValidationRequest) AsFeatureValidationRequestBase() (*FeatureValidationRequestBase, bool) { - return nil, false -} - -// AsBasicFeatureValidationRequestBase is the BasicFeatureValidationRequestBase implementation for FeatureValidationRequest. -func (fvr FeatureValidationRequest) AsBasicFeatureValidationRequestBase() (BasicFeatureValidationRequestBase, bool) { - return &fvr, true -} - -// BasicFeatureValidationRequestBase base class for Backup Feature support -type BasicFeatureValidationRequestBase interface { - AsFeatureValidationRequest() (*FeatureValidationRequest, bool) - AsFeatureValidationRequestBase() (*FeatureValidationRequestBase, bool) -} - -// FeatureValidationRequestBase base class for Backup Feature support -type FeatureValidationRequestBase struct { - // ObjectType - Possible values include: 'ObjectTypeBasicFeatureValidationRequestBaseObjectTypeFeatureValidationRequestBase', 'ObjectTypeBasicFeatureValidationRequestBaseObjectTypeFeatureValidationRequest' - ObjectType ObjectTypeBasicFeatureValidationRequestBase `json:"objectType,omitempty"` -} - -func unmarshalBasicFeatureValidationRequestBase(body []byte) (BasicFeatureValidationRequestBase, error) { - var m map[string]interface{} - err := json.Unmarshal(body, &m) - if err != nil { - return nil, err - } - - switch m["objectType"] { - case string(ObjectTypeBasicFeatureValidationRequestBaseObjectTypeFeatureValidationRequest): - var fvr FeatureValidationRequest - err := json.Unmarshal(body, &fvr) - return fvr, err - default: - var fvrb FeatureValidationRequestBase - err := json.Unmarshal(body, &fvrb) - return fvrb, err - } -} - -func unmarshalBasicFeatureValidationRequestBaseArray(body []byte) ([]BasicFeatureValidationRequestBase, error) { - var rawMessages []*json.RawMessage - err := json.Unmarshal(body, &rawMessages) - if err != nil { - return nil, err - } - - fvrbArray := make([]BasicFeatureValidationRequestBase, len(rawMessages)) - - for index, rawMessage := range rawMessages { - fvrb, err := unmarshalBasicFeatureValidationRequestBase(*rawMessage) - if err != nil { - return nil, err - } - fvrbArray[index] = fvrb - } - return fvrbArray, nil -} - -// MarshalJSON is the custom marshaler for FeatureValidationRequestBase. -func (fvrb FeatureValidationRequestBase) MarshalJSON() ([]byte, error) { - fvrb.ObjectType = ObjectTypeBasicFeatureValidationRequestBaseObjectTypeFeatureValidationRequestBase - objectMap := make(map[string]interface{}) - if fvrb.ObjectType != "" { - objectMap["objectType"] = fvrb.ObjectType - } - return json.Marshal(objectMap) -} - -// AsFeatureValidationRequest is the BasicFeatureValidationRequestBase implementation for FeatureValidationRequestBase. -func (fvrb FeatureValidationRequestBase) AsFeatureValidationRequest() (*FeatureValidationRequest, bool) { - return nil, false -} - -// AsFeatureValidationRequestBase is the BasicFeatureValidationRequestBase implementation for FeatureValidationRequestBase. -func (fvrb FeatureValidationRequestBase) AsFeatureValidationRequestBase() (*FeatureValidationRequestBase, bool) { - return &fvrb, true -} - -// AsBasicFeatureValidationRequestBase is the BasicFeatureValidationRequestBase implementation for FeatureValidationRequestBase. -func (fvrb FeatureValidationRequestBase) AsBasicFeatureValidationRequestBase() (BasicFeatureValidationRequestBase, bool) { - return &fvrb, true -} - -// FeatureValidationResponse feature Validation Response -type FeatureValidationResponse struct { - // FeatureType - backup support feature type. Possible values include: 'FeatureTypeInvalid', 'FeatureTypeDataSourceType' - FeatureType FeatureType `json:"featureType,omitempty"` - // Features - Response features - Features *[]SupportedFeature `json:"features,omitempty"` - // ObjectType - Possible values include: 'ObjectTypeBasicFeatureValidationResponseBaseObjectTypeFeatureValidationResponseBase', 'ObjectTypeBasicFeatureValidationResponseBaseObjectTypeFeatureValidationResponse' - ObjectType ObjectTypeBasicFeatureValidationResponseBase `json:"objectType,omitempty"` -} - -// MarshalJSON is the custom marshaler for FeatureValidationResponse. -func (fvr FeatureValidationResponse) MarshalJSON() ([]byte, error) { - fvr.ObjectType = ObjectTypeBasicFeatureValidationResponseBaseObjectTypeFeatureValidationResponse - objectMap := make(map[string]interface{}) - if fvr.FeatureType != "" { - objectMap["featureType"] = fvr.FeatureType - } - if fvr.Features != nil { - objectMap["features"] = fvr.Features - } - if fvr.ObjectType != "" { - objectMap["objectType"] = fvr.ObjectType - } - return json.Marshal(objectMap) -} - -// AsFeatureValidationResponse is the BasicFeatureValidationResponseBase implementation for FeatureValidationResponse. -func (fvr FeatureValidationResponse) AsFeatureValidationResponse() (*FeatureValidationResponse, bool) { - return &fvr, true -} - -// AsFeatureValidationResponseBase is the BasicFeatureValidationResponseBase implementation for FeatureValidationResponse. -func (fvr FeatureValidationResponse) AsFeatureValidationResponseBase() (*FeatureValidationResponseBase, bool) { - return nil, false -} - -// AsBasicFeatureValidationResponseBase is the BasicFeatureValidationResponseBase implementation for FeatureValidationResponse. -func (fvr FeatureValidationResponse) AsBasicFeatureValidationResponseBase() (BasicFeatureValidationResponseBase, bool) { - return &fvr, true -} - -// BasicFeatureValidationResponseBase base class for Backup Feature support -type BasicFeatureValidationResponseBase interface { - AsFeatureValidationResponse() (*FeatureValidationResponse, bool) - AsFeatureValidationResponseBase() (*FeatureValidationResponseBase, bool) -} - -// FeatureValidationResponseBase base class for Backup Feature support -type FeatureValidationResponseBase struct { - autorest.Response `json:"-"` - // ObjectType - Possible values include: 'ObjectTypeBasicFeatureValidationResponseBaseObjectTypeFeatureValidationResponseBase', 'ObjectTypeBasicFeatureValidationResponseBaseObjectTypeFeatureValidationResponse' - ObjectType ObjectTypeBasicFeatureValidationResponseBase `json:"objectType,omitempty"` -} - -func unmarshalBasicFeatureValidationResponseBase(body []byte) (BasicFeatureValidationResponseBase, error) { - var m map[string]interface{} - err := json.Unmarshal(body, &m) - if err != nil { - return nil, err - } - - switch m["objectType"] { - case string(ObjectTypeBasicFeatureValidationResponseBaseObjectTypeFeatureValidationResponse): - var fvr FeatureValidationResponse - err := json.Unmarshal(body, &fvr) - return fvr, err - default: - var fvrb FeatureValidationResponseBase - err := json.Unmarshal(body, &fvrb) - return fvrb, err - } -} - -func unmarshalBasicFeatureValidationResponseBaseArray(body []byte) ([]BasicFeatureValidationResponseBase, error) { - var rawMessages []*json.RawMessage - err := json.Unmarshal(body, &rawMessages) - if err != nil { - return nil, err - } - - fvrbArray := make([]BasicFeatureValidationResponseBase, len(rawMessages)) - - for index, rawMessage := range rawMessages { - fvrb, err := unmarshalBasicFeatureValidationResponseBase(*rawMessage) - if err != nil { - return nil, err - } - fvrbArray[index] = fvrb - } - return fvrbArray, nil -} - -// MarshalJSON is the custom marshaler for FeatureValidationResponseBase. -func (fvrb FeatureValidationResponseBase) MarshalJSON() ([]byte, error) { - fvrb.ObjectType = ObjectTypeBasicFeatureValidationResponseBaseObjectTypeFeatureValidationResponseBase - objectMap := make(map[string]interface{}) - if fvrb.ObjectType != "" { - objectMap["objectType"] = fvrb.ObjectType - } - return json.Marshal(objectMap) -} - -// AsFeatureValidationResponse is the BasicFeatureValidationResponseBase implementation for FeatureValidationResponseBase. -func (fvrb FeatureValidationResponseBase) AsFeatureValidationResponse() (*FeatureValidationResponse, bool) { - return nil, false -} - -// AsFeatureValidationResponseBase is the BasicFeatureValidationResponseBase implementation for FeatureValidationResponseBase. -func (fvrb FeatureValidationResponseBase) AsFeatureValidationResponseBase() (*FeatureValidationResponseBase, bool) { - return &fvrb, true -} - -// AsBasicFeatureValidationResponseBase is the BasicFeatureValidationResponseBase implementation for FeatureValidationResponseBase. -func (fvrb FeatureValidationResponseBase) AsBasicFeatureValidationResponseBase() (BasicFeatureValidationResponseBase, bool) { - return &fvrb, true -} - -// FeatureValidationResponseBaseModel ... -type FeatureValidationResponseBaseModel struct { - autorest.Response `json:"-"` - Value BasicFeatureValidationResponseBase `json:"value,omitempty"` -} - -// UnmarshalJSON is the custom unmarshaler for FeatureValidationResponseBaseModel struct. -func (fvrbm *FeatureValidationResponseBaseModel) UnmarshalJSON(body []byte) error { - fvrb, err := unmarshalBasicFeatureValidationResponseBase(body) - if err != nil { - return err - } - fvrbm.Value = fvrb - - return nil -} - -// ImmediateCopyOption immediate copy Option -type ImmediateCopyOption struct { - // ObjectType - Possible values include: 'ObjectTypeBasicCopyOptionObjectTypeCopyOption', 'ObjectTypeBasicCopyOptionObjectTypeCopyOnExpiryOption', 'ObjectTypeBasicCopyOptionObjectTypeCustomCopyOption', 'ObjectTypeBasicCopyOptionObjectTypeImmediateCopyOption' - ObjectType ObjectTypeBasicCopyOption `json:"objectType,omitempty"` -} - -// MarshalJSON is the custom marshaler for ImmediateCopyOption. -func (ico ImmediateCopyOption) MarshalJSON() ([]byte, error) { - ico.ObjectType = ObjectTypeBasicCopyOptionObjectTypeImmediateCopyOption - objectMap := make(map[string]interface{}) - if ico.ObjectType != "" { - objectMap["objectType"] = ico.ObjectType - } - return json.Marshal(objectMap) -} - -// AsCopyOnExpiryOption is the BasicCopyOption implementation for ImmediateCopyOption. -func (ico ImmediateCopyOption) AsCopyOnExpiryOption() (*CopyOnExpiryOption, bool) { - return nil, false -} - -// AsCustomCopyOption is the BasicCopyOption implementation for ImmediateCopyOption. -func (ico ImmediateCopyOption) AsCustomCopyOption() (*CustomCopyOption, bool) { - return nil, false -} - -// AsImmediateCopyOption is the BasicCopyOption implementation for ImmediateCopyOption. -func (ico ImmediateCopyOption) AsImmediateCopyOption() (*ImmediateCopyOption, bool) { - return &ico, true -} - -// AsCopyOption is the BasicCopyOption implementation for ImmediateCopyOption. -func (ico ImmediateCopyOption) AsCopyOption() (*CopyOption, bool) { - return nil, false -} - -// AsBasicCopyOption is the BasicCopyOption implementation for ImmediateCopyOption. -func (ico ImmediateCopyOption) AsBasicCopyOption() (BasicCopyOption, bool) { - return &ico, true -} - -// InnerError inner Error -type InnerError struct { - // AdditionalInfo - Any Key value pairs that can be provided to the client for additional verbose information. - AdditionalInfo map[string]*string `json:"additionalInfo"` - // Code - Unique code for this error - Code *string `json:"code,omitempty"` - // EmbeddedInnerError - Child Inner Error, to allow Nesting. - EmbeddedInnerError *InnerError `json:"embeddedInnerError,omitempty"` -} - -// MarshalJSON is the custom marshaler for InnerError. -func (ie InnerError) MarshalJSON() ([]byte, error) { - objectMap := make(map[string]interface{}) - if ie.AdditionalInfo != nil { - objectMap["additionalInfo"] = ie.AdditionalInfo - } - if ie.Code != nil { - objectMap["code"] = ie.Code - } - if ie.EmbeddedInnerError != nil { - objectMap["embeddedInnerError"] = ie.EmbeddedInnerError - } - return json.Marshal(objectMap) -} - -// BasicItemLevelRestoreCriteria class to contain criteria for item level restore -type BasicItemLevelRestoreCriteria interface { - AsRangeBasedItemLevelRestoreCriteria() (*RangeBasedItemLevelRestoreCriteria, bool) - AsItemLevelRestoreCriteria() (*ItemLevelRestoreCriteria, bool) -} - -// ItemLevelRestoreCriteria class to contain criteria for item level restore -type ItemLevelRestoreCriteria struct { - // ObjectType - Possible values include: 'ObjectTypeBasicItemLevelRestoreCriteriaObjectTypeItemLevelRestoreCriteria', 'ObjectTypeBasicItemLevelRestoreCriteriaObjectTypeRangeBasedItemLevelRestoreCriteria' - ObjectType ObjectTypeBasicItemLevelRestoreCriteria `json:"objectType,omitempty"` -} - -func unmarshalBasicItemLevelRestoreCriteria(body []byte) (BasicItemLevelRestoreCriteria, error) { - var m map[string]interface{} - err := json.Unmarshal(body, &m) - if err != nil { - return nil, err - } - - switch m["objectType"] { - case string(ObjectTypeBasicItemLevelRestoreCriteriaObjectTypeRangeBasedItemLevelRestoreCriteria): - var rbilrc RangeBasedItemLevelRestoreCriteria - err := json.Unmarshal(body, &rbilrc) - return rbilrc, err - default: - var ilrc ItemLevelRestoreCriteria - err := json.Unmarshal(body, &ilrc) - return ilrc, err - } -} - -func unmarshalBasicItemLevelRestoreCriteriaArray(body []byte) ([]BasicItemLevelRestoreCriteria, error) { - var rawMessages []*json.RawMessage - err := json.Unmarshal(body, &rawMessages) - if err != nil { - return nil, err - } - - ilrcArray := make([]BasicItemLevelRestoreCriteria, len(rawMessages)) - - for index, rawMessage := range rawMessages { - ilrc, err := unmarshalBasicItemLevelRestoreCriteria(*rawMessage) - if err != nil { - return nil, err - } - ilrcArray[index] = ilrc - } - return ilrcArray, nil -} - -// MarshalJSON is the custom marshaler for ItemLevelRestoreCriteria. -func (ilrc ItemLevelRestoreCriteria) MarshalJSON() ([]byte, error) { - ilrc.ObjectType = ObjectTypeBasicItemLevelRestoreCriteriaObjectTypeItemLevelRestoreCriteria - objectMap := make(map[string]interface{}) - if ilrc.ObjectType != "" { - objectMap["objectType"] = ilrc.ObjectType - } - return json.Marshal(objectMap) -} - -// AsRangeBasedItemLevelRestoreCriteria is the BasicItemLevelRestoreCriteria implementation for ItemLevelRestoreCriteria. -func (ilrc ItemLevelRestoreCriteria) AsRangeBasedItemLevelRestoreCriteria() (*RangeBasedItemLevelRestoreCriteria, bool) { - return nil, false -} - -// AsItemLevelRestoreCriteria is the BasicItemLevelRestoreCriteria implementation for ItemLevelRestoreCriteria. -func (ilrc ItemLevelRestoreCriteria) AsItemLevelRestoreCriteria() (*ItemLevelRestoreCriteria, bool) { - return &ilrc, true -} - -// AsBasicItemLevelRestoreCriteria is the BasicItemLevelRestoreCriteria implementation for ItemLevelRestoreCriteria. -func (ilrc ItemLevelRestoreCriteria) AsBasicItemLevelRestoreCriteria() (BasicItemLevelRestoreCriteria, bool) { - return &ilrc, true -} - -// ItemLevelRestoreTargetInfo restore target info for Item level restore operation -type ItemLevelRestoreTargetInfo struct { - // RestoreCriteria - Restore Criteria - RestoreCriteria *[]BasicItemLevelRestoreCriteria `json:"restoreCriteria,omitempty"` - // DatasourceInfo - Information of target DS - DatasourceInfo *Datasource `json:"datasourceInfo,omitempty"` - // DatasourceSetInfo - Information of target DS Set - DatasourceSetInfo *DatasourceSet `json:"datasourceSetInfo,omitempty"` - // DatasourceAuthCredentials - Credentials to use to authenticate with data source provider. - DatasourceAuthCredentials BasicAuthCredentials `json:"datasourceAuthCredentials,omitempty"` - // RecoveryOption - Recovery Option - RecoveryOption *string `json:"recoveryOption,omitempty"` - // RestoreLocation - Target Restore region - RestoreLocation *string `json:"restoreLocation,omitempty"` - // ObjectType - Possible values include: 'ObjectTypeBasicRestoreTargetInfoBaseObjectTypeRestoreTargetInfoBase', 'ObjectTypeBasicRestoreTargetInfoBaseObjectTypeItemLevelRestoreTargetInfo', 'ObjectTypeBasicRestoreTargetInfoBaseObjectTypeRestoreFilesTargetInfo', 'ObjectTypeBasicRestoreTargetInfoBaseObjectTypeRestoreTargetInfo' - ObjectType ObjectTypeBasicRestoreTargetInfoBase `json:"objectType,omitempty"` -} - -// MarshalJSON is the custom marshaler for ItemLevelRestoreTargetInfo. -func (ilrti ItemLevelRestoreTargetInfo) MarshalJSON() ([]byte, error) { - ilrti.ObjectType = ObjectTypeBasicRestoreTargetInfoBaseObjectTypeItemLevelRestoreTargetInfo - objectMap := make(map[string]interface{}) - if ilrti.RestoreCriteria != nil { - objectMap["restoreCriteria"] = ilrti.RestoreCriteria - } - if ilrti.DatasourceInfo != nil { - objectMap["datasourceInfo"] = ilrti.DatasourceInfo - } - if ilrti.DatasourceSetInfo != nil { - objectMap["datasourceSetInfo"] = ilrti.DatasourceSetInfo - } - objectMap["datasourceAuthCredentials"] = ilrti.DatasourceAuthCredentials - if ilrti.RecoveryOption != nil { - objectMap["recoveryOption"] = ilrti.RecoveryOption - } - if ilrti.RestoreLocation != nil { - objectMap["restoreLocation"] = ilrti.RestoreLocation - } - if ilrti.ObjectType != "" { - objectMap["objectType"] = ilrti.ObjectType - } - return json.Marshal(objectMap) -} - -// AsItemLevelRestoreTargetInfo is the BasicRestoreTargetInfoBase implementation for ItemLevelRestoreTargetInfo. -func (ilrti ItemLevelRestoreTargetInfo) AsItemLevelRestoreTargetInfo() (*ItemLevelRestoreTargetInfo, bool) { - return &ilrti, true -} - -// AsRestoreFilesTargetInfo is the BasicRestoreTargetInfoBase implementation for ItemLevelRestoreTargetInfo. -func (ilrti ItemLevelRestoreTargetInfo) AsRestoreFilesTargetInfo() (*RestoreFilesTargetInfo, bool) { - return nil, false -} - -// AsRestoreTargetInfo is the BasicRestoreTargetInfoBase implementation for ItemLevelRestoreTargetInfo. -func (ilrti ItemLevelRestoreTargetInfo) AsRestoreTargetInfo() (*RestoreTargetInfo, bool) { - return nil, false -} - -// AsRestoreTargetInfoBase is the BasicRestoreTargetInfoBase implementation for ItemLevelRestoreTargetInfo. -func (ilrti ItemLevelRestoreTargetInfo) AsRestoreTargetInfoBase() (*RestoreTargetInfoBase, bool) { - return nil, false -} - -// AsBasicRestoreTargetInfoBase is the BasicRestoreTargetInfoBase implementation for ItemLevelRestoreTargetInfo. -func (ilrti ItemLevelRestoreTargetInfo) AsBasicRestoreTargetInfoBase() (BasicRestoreTargetInfoBase, bool) { - return &ilrti, true -} - -// UnmarshalJSON is the custom unmarshaler for ItemLevelRestoreTargetInfo struct. -func (ilrti *ItemLevelRestoreTargetInfo) UnmarshalJSON(body []byte) error { - var m map[string]*json.RawMessage - err := json.Unmarshal(body, &m) - if err != nil { - return err - } - for k, v := range m { - switch k { - case "restoreCriteria": - if v != nil { - restoreCriteria, err := unmarshalBasicItemLevelRestoreCriteriaArray(*v) - if err != nil { - return err - } - ilrti.RestoreCriteria = &restoreCriteria - } - case "datasourceInfo": - if v != nil { - var datasourceInfo Datasource - err = json.Unmarshal(*v, &datasourceInfo) - if err != nil { - return err - } - ilrti.DatasourceInfo = &datasourceInfo - } - case "datasourceSetInfo": - if v != nil { - var datasourceSetInfo DatasourceSet - err = json.Unmarshal(*v, &datasourceSetInfo) - if err != nil { - return err - } - ilrti.DatasourceSetInfo = &datasourceSetInfo - } - case "datasourceAuthCredentials": - if v != nil { - datasourceAuthCredentials, err := unmarshalBasicAuthCredentials(*v) - if err != nil { - return err - } - ilrti.DatasourceAuthCredentials = datasourceAuthCredentials - } - case "recoveryOption": - if v != nil { - var recoveryOption string - err = json.Unmarshal(*v, &recoveryOption) - if err != nil { - return err - } - ilrti.RecoveryOption = &recoveryOption - } - case "restoreLocation": - if v != nil { - var restoreLocation string - err = json.Unmarshal(*v, &restoreLocation) - if err != nil { - return err - } - ilrti.RestoreLocation = &restoreLocation - } - case "objectType": - if v != nil { - var objectType ObjectTypeBasicRestoreTargetInfoBase - err = json.Unmarshal(*v, &objectType) - if err != nil { - return err - } - ilrti.ObjectType = objectType - } - } - } - - return nil -} - -// JobExtendedInfo extended Information about the job -type JobExtendedInfo struct { - // AdditionalDetails - Job's Additional Details - AdditionalDetails map[string]*string `json:"additionalDetails"` - // BackupInstanceState - READ-ONLY; State of the Backup Instance - BackupInstanceState *string `json:"backupInstanceState,omitempty"` - // DataTransferredInBytes - READ-ONLY; Number of bytes transferred - DataTransferredInBytes *float64 `json:"dataTransferredInBytes,omitempty"` - // RecoveryDestination - READ-ONLY; Destination where restore is done - RecoveryDestination *string `json:"recoveryDestination,omitempty"` - // SourceRecoverPoint - READ-ONLY; Details of the Source Recovery Point - SourceRecoverPoint *RestoreJobRecoveryPointDetails `json:"sourceRecoverPoint,omitempty"` - // SubTasks - READ-ONLY; List of Sub Tasks of the job - SubTasks *[]JobSubTask `json:"subTasks,omitempty"` - // TargetRecoverPoint - READ-ONLY; Details of the Target Recovery Point - TargetRecoverPoint *RestoreJobRecoveryPointDetails `json:"targetRecoverPoint,omitempty"` -} - -// MarshalJSON is the custom marshaler for JobExtendedInfo. -func (jei JobExtendedInfo) MarshalJSON() ([]byte, error) { - objectMap := make(map[string]interface{}) - if jei.AdditionalDetails != nil { - objectMap["additionalDetails"] = jei.AdditionalDetails - } - return json.Marshal(objectMap) -} - -// JobSubTask details of Job's Sub Task -type JobSubTask struct { - // AdditionalDetails - Additional details of Sub Tasks - AdditionalDetails map[string]*string `json:"additionalDetails"` - // TaskID - Task Id of the Sub Task - TaskID *int32 `json:"taskId,omitempty"` - // TaskName - Name of the Sub Task - TaskName *string `json:"taskName,omitempty"` - // TaskProgress - READ-ONLY; Progress of the Sub Task - TaskProgress *string `json:"taskProgress,omitempty"` - // TaskStatus - Status of the Sub Task - TaskStatus *string `json:"taskStatus,omitempty"` -} - -// MarshalJSON is the custom marshaler for JobSubTask. -func (jst JobSubTask) MarshalJSON() ([]byte, error) { - objectMap := make(map[string]interface{}) - if jst.AdditionalDetails != nil { - objectMap["additionalDetails"] = jst.AdditionalDetails - } - if jst.TaskID != nil { - objectMap["taskId"] = jst.TaskID - } - if jst.TaskName != nil { - objectMap["taskName"] = jst.TaskName - } - if jst.TaskStatus != nil { - objectMap["taskStatus"] = jst.TaskStatus - } - return json.Marshal(objectMap) -} - -// BasicOperationExtendedInfo operation Extended Info -type BasicOperationExtendedInfo interface { - AsOperationJobExtendedInfo() (*OperationJobExtendedInfo, bool) - AsOperationExtendedInfo() (*OperationExtendedInfo, bool) -} - -// OperationExtendedInfo operation Extended Info -type OperationExtendedInfo struct { - // ObjectType - Possible values include: 'ObjectTypeBasicOperationExtendedInfoObjectTypeOperationExtendedInfo', 'ObjectTypeBasicOperationExtendedInfoObjectTypeOperationJobExtendedInfo' - ObjectType ObjectTypeBasicOperationExtendedInfo `json:"objectType,omitempty"` -} - -func unmarshalBasicOperationExtendedInfo(body []byte) (BasicOperationExtendedInfo, error) { - var m map[string]interface{} - err := json.Unmarshal(body, &m) - if err != nil { - return nil, err - } - - switch m["objectType"] { - case string(ObjectTypeBasicOperationExtendedInfoObjectTypeOperationJobExtendedInfo): - var ojei OperationJobExtendedInfo - err := json.Unmarshal(body, &ojei) - return ojei, err - default: - var oei OperationExtendedInfo - err := json.Unmarshal(body, &oei) - return oei, err - } -} - -func unmarshalBasicOperationExtendedInfoArray(body []byte) ([]BasicOperationExtendedInfo, error) { - var rawMessages []*json.RawMessage - err := json.Unmarshal(body, &rawMessages) - if err != nil { - return nil, err - } - - oeiArray := make([]BasicOperationExtendedInfo, len(rawMessages)) - - for index, rawMessage := range rawMessages { - oei, err := unmarshalBasicOperationExtendedInfo(*rawMessage) - if err != nil { - return nil, err - } - oeiArray[index] = oei - } - return oeiArray, nil -} - -// MarshalJSON is the custom marshaler for OperationExtendedInfo. -func (oei OperationExtendedInfo) MarshalJSON() ([]byte, error) { - oei.ObjectType = ObjectTypeBasicOperationExtendedInfoObjectTypeOperationExtendedInfo - objectMap := make(map[string]interface{}) - if oei.ObjectType != "" { - objectMap["objectType"] = oei.ObjectType - } - return json.Marshal(objectMap) -} - -// AsOperationJobExtendedInfo is the BasicOperationExtendedInfo implementation for OperationExtendedInfo. -func (oei OperationExtendedInfo) AsOperationJobExtendedInfo() (*OperationJobExtendedInfo, bool) { - return nil, false -} - -// AsOperationExtendedInfo is the BasicOperationExtendedInfo implementation for OperationExtendedInfo. -func (oei OperationExtendedInfo) AsOperationExtendedInfo() (*OperationExtendedInfo, bool) { - return &oei, true -} - -// AsBasicOperationExtendedInfo is the BasicOperationExtendedInfo implementation for OperationExtendedInfo. -func (oei OperationExtendedInfo) AsBasicOperationExtendedInfo() (BasicOperationExtendedInfo, bool) { - return &oei, true -} - -// OperationJobExtendedInfo operation Job Extended Info -type OperationJobExtendedInfo struct { - autorest.Response `json:"-"` - // JobID - Arm Id of the job created for this operation. - JobID *string `json:"jobId,omitempty"` - // ObjectType - Possible values include: 'ObjectTypeBasicOperationExtendedInfoObjectTypeOperationExtendedInfo', 'ObjectTypeBasicOperationExtendedInfoObjectTypeOperationJobExtendedInfo' - ObjectType ObjectTypeBasicOperationExtendedInfo `json:"objectType,omitempty"` -} - -// MarshalJSON is the custom marshaler for OperationJobExtendedInfo. -func (ojei OperationJobExtendedInfo) MarshalJSON() ([]byte, error) { - ojei.ObjectType = ObjectTypeBasicOperationExtendedInfoObjectTypeOperationJobExtendedInfo - objectMap := make(map[string]interface{}) - if ojei.JobID != nil { - objectMap["jobId"] = ojei.JobID - } - if ojei.ObjectType != "" { - objectMap["objectType"] = ojei.ObjectType - } - return json.Marshal(objectMap) -} - -// AsOperationJobExtendedInfo is the BasicOperationExtendedInfo implementation for OperationJobExtendedInfo. -func (ojei OperationJobExtendedInfo) AsOperationJobExtendedInfo() (*OperationJobExtendedInfo, bool) { - return &ojei, true -} - -// AsOperationExtendedInfo is the BasicOperationExtendedInfo implementation for OperationJobExtendedInfo. -func (ojei OperationJobExtendedInfo) AsOperationExtendedInfo() (*OperationExtendedInfo, bool) { - return nil, false -} - -// AsBasicOperationExtendedInfo is the BasicOperationExtendedInfo implementation for OperationJobExtendedInfo. -func (ojei OperationJobExtendedInfo) AsBasicOperationExtendedInfo() (BasicOperationExtendedInfo, bool) { - return &ojei, true -} - -// OperationResource operation Resource -type OperationResource struct { - autorest.Response `json:"-"` - // EndTime - End time of the operation - EndTime *date.Time `json:"endTime,omitempty"` - // Error - Required if status == failed or status == canceled. This is the OData v4 error format, used by the RPC and will go into the v2.2 Azure REST API guidelines. - // The full set of optional properties (e.g. inner errors / details) can be found in the "Error Response" section. - Error *Error `json:"error,omitempty"` - // ID - It should match what is used to GET the operation result - ID *string `json:"id,omitempty"` - // Name - It must match the last segment of the "id" field, and will typically be a GUID / system generated value - Name *string `json:"name,omitempty"` - // Properties - End time of the operation - Properties BasicOperationExtendedInfo `json:"properties,omitempty"` - // StartTime - Start time of the operation - StartTime *date.Time `json:"startTime,omitempty"` - Status *string `json:"status,omitempty"` -} - -// UnmarshalJSON is the custom unmarshaler for OperationResource struct. -func (or *OperationResource) UnmarshalJSON(body []byte) error { - var m map[string]*json.RawMessage - err := json.Unmarshal(body, &m) - if err != nil { - return err - } - for k, v := range m { - switch k { - case "endTime": - if v != nil { - var endTime date.Time - err = json.Unmarshal(*v, &endTime) - if err != nil { - return err - } - or.EndTime = &endTime - } - case "error": - if v != nil { - var errorVar Error - err = json.Unmarshal(*v, &errorVar) - if err != nil { - return err - } - or.Error = &errorVar - } - case "id": - if v != nil { - var ID string - err = json.Unmarshal(*v, &ID) - if err != nil { - return err - } - or.ID = &ID - } - case "name": - if v != nil { - var name string - err = json.Unmarshal(*v, &name) - if err != nil { - return err - } - or.Name = &name - } - case "properties": - if v != nil { - properties, err := unmarshalBasicOperationExtendedInfo(*v) - if err != nil { - return err - } - or.Properties = properties - } - case "startTime": - if v != nil { - var startTime date.Time - err = json.Unmarshal(*v, &startTime) - if err != nil { - return err - } - or.StartTime = &startTime - } - case "status": - if v != nil { - var status string - err = json.Unmarshal(*v, &status) - if err != nil { - return err - } - or.Status = &status - } - } - } - - return nil -} - -// PatchResourceRequestInput patch Request content for Microsoft.DataProtection resources -type PatchResourceRequestInput struct { - // Identity - Input Managed Identity Details - Identity *DppIdentityDetails `json:"identity,omitempty"` - // Tags - Resource tags. - Tags map[string]*string `json:"tags"` -} - -// MarshalJSON is the custom marshaler for PatchResourceRequestInput. -func (prri PatchResourceRequestInput) MarshalJSON() ([]byte, error) { - objectMap := make(map[string]interface{}) - if prri.Identity != nil { - objectMap["identity"] = prri.Identity - } - if prri.Tags != nil { - objectMap["tags"] = prri.Tags - } - return json.Marshal(objectMap) -} - -// PolicyInfo policy Info in backupInstance -type PolicyInfo struct { - PolicyID *string `json:"policyId,omitempty"` - // PolicyVersion - READ-ONLY - PolicyVersion *string `json:"policyVersion,omitempty"` - // PolicyParameters - Policy parameters for the backup instance - PolicyParameters *PolicyParameters `json:"policyParameters,omitempty"` -} - -// MarshalJSON is the custom marshaler for PolicyInfo. -func (pi PolicyInfo) MarshalJSON() ([]byte, error) { - objectMap := make(map[string]interface{}) - if pi.PolicyID != nil { - objectMap["policyId"] = pi.PolicyID - } - if pi.PolicyParameters != nil { - objectMap["policyParameters"] = pi.PolicyParameters - } - return json.Marshal(objectMap) -} - -// PolicyParameters parameters in Policy -type PolicyParameters struct { - // DataStoreParametersList - Gets or sets the DataStore Parameters - DataStoreParametersList *[]BasicDataStoreParameters `json:"dataStoreParametersList,omitempty"` -} - -// UnmarshalJSON is the custom unmarshaler for PolicyParameters struct. -func (pp *PolicyParameters) UnmarshalJSON(body []byte) error { - var m map[string]*json.RawMessage - err := json.Unmarshal(body, &m) - if err != nil { - return err - } - for k, v := range m { - switch k { - case "dataStoreParametersList": - if v != nil { - dataStoreParametersList, err := unmarshalBasicDataStoreParametersArray(*v) - if err != nil { - return err - } - pp.DataStoreParametersList = &dataStoreParametersList - } - } - } - - return nil -} - -// ProtectionStatusDetails protection status details -type ProtectionStatusDetails struct { - // ErrorDetails - Specifies the protection status error of the resource - ErrorDetails *UserFacingError `json:"errorDetails,omitempty"` - // Status - Specifies the protection status of the resource. Possible values include: 'StatusConfiguringProtection', 'StatusConfiguringProtectionFailed', 'StatusProtectionConfigured', 'StatusProtectionStopped', 'StatusSoftDeleted', 'StatusSoftDeleting' - Status Status `json:"status,omitempty"` -} - -// RangeBasedItemLevelRestoreCriteria item Level target info for restore operation -type RangeBasedItemLevelRestoreCriteria struct { - // MinMatchingValue - minimum value for range prefix match - MinMatchingValue *string `json:"minMatchingValue,omitempty"` - // MaxMatchingValue - maximum value for range prefix match - MaxMatchingValue *string `json:"maxMatchingValue,omitempty"` - // ObjectType - Possible values include: 'ObjectTypeBasicItemLevelRestoreCriteriaObjectTypeItemLevelRestoreCriteria', 'ObjectTypeBasicItemLevelRestoreCriteriaObjectTypeRangeBasedItemLevelRestoreCriteria' - ObjectType ObjectTypeBasicItemLevelRestoreCriteria `json:"objectType,omitempty"` -} - -// MarshalJSON is the custom marshaler for RangeBasedItemLevelRestoreCriteria. -func (rbilrc RangeBasedItemLevelRestoreCriteria) MarshalJSON() ([]byte, error) { - rbilrc.ObjectType = ObjectTypeBasicItemLevelRestoreCriteriaObjectTypeRangeBasedItemLevelRestoreCriteria - objectMap := make(map[string]interface{}) - if rbilrc.MinMatchingValue != nil { - objectMap["minMatchingValue"] = rbilrc.MinMatchingValue - } - if rbilrc.MaxMatchingValue != nil { - objectMap["maxMatchingValue"] = rbilrc.MaxMatchingValue - } - if rbilrc.ObjectType != "" { - objectMap["objectType"] = rbilrc.ObjectType - } - return json.Marshal(objectMap) -} - -// AsRangeBasedItemLevelRestoreCriteria is the BasicItemLevelRestoreCriteria implementation for RangeBasedItemLevelRestoreCriteria. -func (rbilrc RangeBasedItemLevelRestoreCriteria) AsRangeBasedItemLevelRestoreCriteria() (*RangeBasedItemLevelRestoreCriteria, bool) { - return &rbilrc, true -} - -// AsItemLevelRestoreCriteria is the BasicItemLevelRestoreCriteria implementation for RangeBasedItemLevelRestoreCriteria. -func (rbilrc RangeBasedItemLevelRestoreCriteria) AsItemLevelRestoreCriteria() (*ItemLevelRestoreCriteria, bool) { - return nil, false -} - -// AsBasicItemLevelRestoreCriteria is the BasicItemLevelRestoreCriteria implementation for RangeBasedItemLevelRestoreCriteria. -func (rbilrc RangeBasedItemLevelRestoreCriteria) AsBasicItemLevelRestoreCriteria() (BasicItemLevelRestoreCriteria, bool) { - return &rbilrc, true -} - -// RecoveryPointDataStoreDetails recoveryPoint datastore details -type RecoveryPointDataStoreDetails struct { - CreationTime *date.Time `json:"creationTime,omitempty"` - ExpiryTime *date.Time `json:"expiryTime,omitempty"` - ID *string `json:"id,omitempty"` - MetaData *string `json:"metaData,omitempty"` - State *string `json:"state,omitempty"` - Type *string `json:"type,omitempty"` - Visible *bool `json:"visible,omitempty"` - // RehydrationExpiryTime - READ-ONLY - RehydrationExpiryTime *date.Time `json:"rehydrationExpiryTime,omitempty"` - // RehydrationStatus - READ-ONLY; Possible values include: 'RehydrationStatusCREATEINPROGRESS', 'RehydrationStatusCOMPLETED', 'RehydrationStatusDELETEINPROGRESS', 'RehydrationStatusDELETED', 'RehydrationStatusFAILED' - RehydrationStatus RehydrationStatus `json:"rehydrationStatus,omitempty"` -} - -// MarshalJSON is the custom marshaler for RecoveryPointDataStoreDetails. -func (rpdsd RecoveryPointDataStoreDetails) MarshalJSON() ([]byte, error) { - objectMap := make(map[string]interface{}) - if rpdsd.CreationTime != nil { - objectMap["creationTime"] = rpdsd.CreationTime - } - if rpdsd.ExpiryTime != nil { - objectMap["expiryTime"] = rpdsd.ExpiryTime - } - if rpdsd.ID != nil { - objectMap["id"] = rpdsd.ID - } - if rpdsd.MetaData != nil { - objectMap["metaData"] = rpdsd.MetaData - } - if rpdsd.State != nil { - objectMap["state"] = rpdsd.State - } - if rpdsd.Type != nil { - objectMap["type"] = rpdsd.Type - } - if rpdsd.Visible != nil { - objectMap["visible"] = rpdsd.Visible - } - return json.Marshal(objectMap) -} - -// RecoveryPointsFilters ... -type RecoveryPointsFilters struct { - RestorePointDataStoreID *string `json:"restorePointDataStoreId,omitempty"` - IsVisible *bool `json:"isVisible,omitempty"` - StartDate *string `json:"startDate,omitempty"` - EndDate *string `json:"endDate,omitempty"` - ExtendedInfo *bool `json:"extendedInfo,omitempty"` - RestorePointState *string `json:"restorePointState,omitempty"` -} - -// ResourceGuard ... -type ResourceGuard struct { - // ProvisioningState - READ-ONLY; Provisioning state of the BackupVault resource. Possible values include: 'ProvisioningStateFailed', 'ProvisioningStateProvisioning', 'ProvisioningStateSucceeded', 'ProvisioningStateUnknown', 'ProvisioningStateUpdating' - ProvisioningState ProvisioningState `json:"provisioningState,omitempty"` - // AllowAutoApprovals - READ-ONLY; This flag indicates whether auto approval is allowed or not. - AllowAutoApprovals *bool `json:"allowAutoApprovals,omitempty"` - // ResourceGuardOperations - READ-ONLY; {readonly} List of operation details those are protected by the ResourceGuard resource - ResourceGuardOperations *[]ResourceGuardOperation `json:"resourceGuardOperations,omitempty"` - // VaultCriticalOperationExclusionList - READ-ONLY; List of critical operations which are not protected by this resourceGuard - VaultCriticalOperationExclusionList *[]string `json:"vaultCriticalOperationExclusionList,omitempty"` - // Description - READ-ONLY; Description about the pre-req steps to perform all the critical operations. - Description *string `json:"description,omitempty"` -} - -// MarshalJSON is the custom marshaler for ResourceGuard. -func (rg ResourceGuard) MarshalJSON() ([]byte, error) { - objectMap := make(map[string]interface{}) - return json.Marshal(objectMap) -} - -// ResourceGuardOperation this class contains all the details about a critical operation. -type ResourceGuardOperation struct { - // VaultCriticalOperation - READ-ONLY; Name of the critical operation. - VaultCriticalOperation *string `json:"vaultCriticalOperation,omitempty"` - // RequestResourceType - READ-ONLY; Type of resource request. - RequestResourceType *string `json:"requestResourceType,omitempty"` -} - -// MarshalJSON is the custom marshaler for ResourceGuardOperation. -func (rgo ResourceGuardOperation) MarshalJSON() ([]byte, error) { - objectMap := make(map[string]interface{}) - return json.Marshal(objectMap) -} - -// ResourceGuardResource ... -type ResourceGuardResource struct { - autorest.Response `json:"-"` - // Properties - ResourceGuardResource properties - Properties *ResourceGuard `json:"properties,omitempty"` - // ETag - Optional ETag. - ETag *string `json:"eTag,omitempty"` - // ID - READ-ONLY; Resource Id represents the complete path to the resource. - ID *string `json:"id,omitempty"` - // Identity - Input Managed Identity Details - Identity *DppIdentityDetails `json:"identity,omitempty"` - // Location - Resource location. - Location *string `json:"location,omitempty"` - // Name - READ-ONLY; Resource name associated with the resource. - Name *string `json:"name,omitempty"` - // Tags - Resource tags. - Tags map[string]*string `json:"tags"` - // Type - READ-ONLY; Resource type represents the complete path of the form Namespace/ResourceType/ResourceType/... - Type *string `json:"type,omitempty"` - SystemData *SystemData `json:"systemData,omitempty"` -} - -// MarshalJSON is the custom marshaler for ResourceGuardResource. -func (rgr ResourceGuardResource) MarshalJSON() ([]byte, error) { - objectMap := make(map[string]interface{}) - if rgr.Properties != nil { - objectMap["properties"] = rgr.Properties - } - if rgr.ETag != nil { - objectMap["eTag"] = rgr.ETag - } - if rgr.Identity != nil { - objectMap["identity"] = rgr.Identity - } - if rgr.Location != nil { - objectMap["location"] = rgr.Location - } - if rgr.Tags != nil { - objectMap["tags"] = rgr.Tags - } - if rgr.SystemData != nil { - objectMap["systemData"] = rgr.SystemData - } - return json.Marshal(objectMap) -} - -// ResourceGuardResourceList list of ResourceGuard resources -type ResourceGuardResourceList struct { - autorest.Response `json:"-"` - // Value - List of resources. - Value *[]ResourceGuardResource `json:"value,omitempty"` - // NextLink - The uri to fetch the next page of resources. Call ListNext() fetches next page of resources. - NextLink *string `json:"nextLink,omitempty"` -} - -// ResourceGuardResourceListIterator provides access to a complete listing of ResourceGuardResource values. -type ResourceGuardResourceListIterator struct { - i int - page ResourceGuardResourceListPage -} - -// NextWithContext advances to the next value. If there was an error making -// the request the iterator does not advance and the error is returned. -func (iter *ResourceGuardResourceListIterator) NextWithContext(ctx context.Context) (err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/ResourceGuardResourceListIterator.NextWithContext") - defer func() { - sc := -1 - if iter.Response().Response.Response != nil { - sc = iter.Response().Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - iter.i++ - if iter.i < len(iter.page.Values()) { - return nil - } - err = iter.page.NextWithContext(ctx) - if err != nil { - iter.i-- - return err - } - iter.i = 0 - return nil -} - -// Next advances to the next value. If there was an error making -// the request the iterator does not advance and the error is returned. -// Deprecated: Use NextWithContext() instead. -func (iter *ResourceGuardResourceListIterator) Next() error { - return iter.NextWithContext(context.Background()) -} - -// NotDone returns true if the enumeration should be started or is not yet complete. -func (iter ResourceGuardResourceListIterator) NotDone() bool { - return iter.page.NotDone() && iter.i < len(iter.page.Values()) -} - -// Response returns the raw server response from the last page request. -func (iter ResourceGuardResourceListIterator) Response() ResourceGuardResourceList { - return iter.page.Response() -} - -// Value returns the current value or a zero-initialized value if the -// iterator has advanced beyond the end of the collection. -func (iter ResourceGuardResourceListIterator) Value() ResourceGuardResource { - if !iter.page.NotDone() { - return ResourceGuardResource{} - } - return iter.page.Values()[iter.i] -} - -// Creates a new instance of the ResourceGuardResourceListIterator type. -func NewResourceGuardResourceListIterator(page ResourceGuardResourceListPage) ResourceGuardResourceListIterator { - return ResourceGuardResourceListIterator{page: page} -} - -// IsEmpty returns true if the ListResult contains no values. -func (rgrl ResourceGuardResourceList) IsEmpty() bool { - return rgrl.Value == nil || len(*rgrl.Value) == 0 -} - -// hasNextLink returns true if the NextLink is not empty. -func (rgrl ResourceGuardResourceList) hasNextLink() bool { - return rgrl.NextLink != nil && len(*rgrl.NextLink) != 0 -} - -// resourceGuardResourceListPreparer prepares a request to retrieve the next set of results. -// It returns nil if no more results exist. -func (rgrl ResourceGuardResourceList) resourceGuardResourceListPreparer(ctx context.Context) (*http.Request, error) { - if !rgrl.hasNextLink() { - return nil, nil - } - return autorest.Prepare((&http.Request{}).WithContext(ctx), - autorest.AsJSON(), - autorest.AsGet(), - autorest.WithBaseURL(to.String(rgrl.NextLink))) -} - -// ResourceGuardResourceListPage contains a page of ResourceGuardResource values. -type ResourceGuardResourceListPage struct { - fn func(context.Context, ResourceGuardResourceList) (ResourceGuardResourceList, error) - rgrl ResourceGuardResourceList -} - -// NextWithContext advances to the next page of values. If there was an error making -// the request the page does not advance and the error is returned. -func (page *ResourceGuardResourceListPage) NextWithContext(ctx context.Context) (err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/ResourceGuardResourceListPage.NextWithContext") - defer func() { - sc := -1 - if page.Response().Response.Response != nil { - sc = page.Response().Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - for { - next, err := page.fn(ctx, page.rgrl) - if err != nil { - return err - } - page.rgrl = next - if !next.hasNextLink() || !next.IsEmpty() { - break - } - } - return nil -} - -// Next advances to the next page of values. If there was an error making -// the request the page does not advance and the error is returned. -// Deprecated: Use NextWithContext() instead. -func (page *ResourceGuardResourceListPage) Next() error { - return page.NextWithContext(context.Background()) -} - -// NotDone returns true if the page enumeration should be started or is not yet complete. -func (page ResourceGuardResourceListPage) NotDone() bool { - return !page.rgrl.IsEmpty() -} - -// Response returns the raw server response from the last page request. -func (page ResourceGuardResourceListPage) Response() ResourceGuardResourceList { - return page.rgrl -} - -// Values returns the slice of values for the current page or nil if there are no values. -func (page ResourceGuardResourceListPage) Values() []ResourceGuardResource { - if page.rgrl.IsEmpty() { - return nil - } - return *page.rgrl.Value -} - -// Creates a new instance of the ResourceGuardResourceListPage type. -func NewResourceGuardResourceListPage(cur ResourceGuardResourceList, getNextPage func(context.Context, ResourceGuardResourceList) (ResourceGuardResourceList, error)) ResourceGuardResourceListPage { - return ResourceGuardResourceListPage{ - fn: getNextPage, - rgrl: cur, - } -} - -// ResourceMoveDetails resourceMoveDetails will be returned in response to GetResource call from ARM -type ResourceMoveDetails struct { - // OperationID - CorrelationId of latest ResourceMove operation attempted - OperationID *string `json:"operationId,omitempty"` - // StartTimeUtc - Start time in UTC of latest ResourceMove operation attempted. ISO 8601 format. - StartTimeUtc *string `json:"startTimeUtc,omitempty"` - // CompletionTimeUtc - Completion time in UTC of latest ResourceMove operation attempted. ISO 8601 format. - CompletionTimeUtc *string `json:"completionTimeUtc,omitempty"` - // SourceResourcePath - ARM resource path of source resource - SourceResourcePath *string `json:"sourceResourcePath,omitempty"` - // TargetResourcePath - ARM resource path of target resource used in latest ResourceMove operation - TargetResourcePath *string `json:"targetResourcePath,omitempty"` -} - -// RestorableTimeRange ... -type RestorableTimeRange struct { - // StartTime - Start time for the available restore range - StartTime *string `json:"startTime,omitempty"` - // EndTime - End time for the available restore range - EndTime *string `json:"endTime,omitempty"` - ObjectType *string `json:"objectType,omitempty"` -} - -// RestoreFilesTargetInfo class encapsulating restore as files target parameters -type RestoreFilesTargetInfo struct { - // TargetDetails - Destination of RestoreAsFiles operation, when destination is not a datasource - TargetDetails *TargetDetails `json:"targetDetails,omitempty"` - // RecoveryOption - Recovery Option - RecoveryOption *string `json:"recoveryOption,omitempty"` - // RestoreLocation - Target Restore region - RestoreLocation *string `json:"restoreLocation,omitempty"` - // ObjectType - Possible values include: 'ObjectTypeBasicRestoreTargetInfoBaseObjectTypeRestoreTargetInfoBase', 'ObjectTypeBasicRestoreTargetInfoBaseObjectTypeItemLevelRestoreTargetInfo', 'ObjectTypeBasicRestoreTargetInfoBaseObjectTypeRestoreFilesTargetInfo', 'ObjectTypeBasicRestoreTargetInfoBaseObjectTypeRestoreTargetInfo' - ObjectType ObjectTypeBasicRestoreTargetInfoBase `json:"objectType,omitempty"` -} - -// MarshalJSON is the custom marshaler for RestoreFilesTargetInfo. -func (rfti RestoreFilesTargetInfo) MarshalJSON() ([]byte, error) { - rfti.ObjectType = ObjectTypeBasicRestoreTargetInfoBaseObjectTypeRestoreFilesTargetInfo - objectMap := make(map[string]interface{}) - if rfti.TargetDetails != nil { - objectMap["targetDetails"] = rfti.TargetDetails - } - if rfti.RecoveryOption != nil { - objectMap["recoveryOption"] = rfti.RecoveryOption - } - if rfti.RestoreLocation != nil { - objectMap["restoreLocation"] = rfti.RestoreLocation - } - if rfti.ObjectType != "" { - objectMap["objectType"] = rfti.ObjectType - } - return json.Marshal(objectMap) -} - -// AsItemLevelRestoreTargetInfo is the BasicRestoreTargetInfoBase implementation for RestoreFilesTargetInfo. -func (rfti RestoreFilesTargetInfo) AsItemLevelRestoreTargetInfo() (*ItemLevelRestoreTargetInfo, bool) { - return nil, false -} - -// AsRestoreFilesTargetInfo is the BasicRestoreTargetInfoBase implementation for RestoreFilesTargetInfo. -func (rfti RestoreFilesTargetInfo) AsRestoreFilesTargetInfo() (*RestoreFilesTargetInfo, bool) { - return &rfti, true -} - -// AsRestoreTargetInfo is the BasicRestoreTargetInfoBase implementation for RestoreFilesTargetInfo. -func (rfti RestoreFilesTargetInfo) AsRestoreTargetInfo() (*RestoreTargetInfo, bool) { - return nil, false -} - -// AsRestoreTargetInfoBase is the BasicRestoreTargetInfoBase implementation for RestoreFilesTargetInfo. -func (rfti RestoreFilesTargetInfo) AsRestoreTargetInfoBase() (*RestoreTargetInfoBase, bool) { - return nil, false -} - -// AsBasicRestoreTargetInfoBase is the BasicRestoreTargetInfoBase implementation for RestoreFilesTargetInfo. -func (rfti RestoreFilesTargetInfo) AsBasicRestoreTargetInfoBase() (BasicRestoreTargetInfoBase, bool) { - return &rfti, true -} - -// RestoreJobRecoveryPointDetails ... -type RestoreJobRecoveryPointDetails struct { - RecoveryPointID *string `json:"recoveryPointID,omitempty"` - RecoveryPointTime *date.Time `json:"recoveryPointTime,omitempty"` -} - -// RestoreTargetInfo class encapsulating restore target parameters -type RestoreTargetInfo struct { - // DatasourceInfo - Information of target DS - DatasourceInfo *Datasource `json:"datasourceInfo,omitempty"` - // DatasourceSetInfo - Information of target DS Set - DatasourceSetInfo *DatasourceSet `json:"datasourceSetInfo,omitempty"` - // DatasourceAuthCredentials - Credentials to use to authenticate with data source provider. - DatasourceAuthCredentials BasicAuthCredentials `json:"datasourceAuthCredentials,omitempty"` - // RecoveryOption - Recovery Option - RecoveryOption *string `json:"recoveryOption,omitempty"` - // RestoreLocation - Target Restore region - RestoreLocation *string `json:"restoreLocation,omitempty"` - // ObjectType - Possible values include: 'ObjectTypeBasicRestoreTargetInfoBaseObjectTypeRestoreTargetInfoBase', 'ObjectTypeBasicRestoreTargetInfoBaseObjectTypeItemLevelRestoreTargetInfo', 'ObjectTypeBasicRestoreTargetInfoBaseObjectTypeRestoreFilesTargetInfo', 'ObjectTypeBasicRestoreTargetInfoBaseObjectTypeRestoreTargetInfo' - ObjectType ObjectTypeBasicRestoreTargetInfoBase `json:"objectType,omitempty"` -} - -// MarshalJSON is the custom marshaler for RestoreTargetInfo. -func (rti RestoreTargetInfo) MarshalJSON() ([]byte, error) { - rti.ObjectType = ObjectTypeBasicRestoreTargetInfoBaseObjectTypeRestoreTargetInfo - objectMap := make(map[string]interface{}) - if rti.DatasourceInfo != nil { - objectMap["datasourceInfo"] = rti.DatasourceInfo - } - if rti.DatasourceSetInfo != nil { - objectMap["datasourceSetInfo"] = rti.DatasourceSetInfo - } - objectMap["datasourceAuthCredentials"] = rti.DatasourceAuthCredentials - if rti.RecoveryOption != nil { - objectMap["recoveryOption"] = rti.RecoveryOption - } - if rti.RestoreLocation != nil { - objectMap["restoreLocation"] = rti.RestoreLocation - } - if rti.ObjectType != "" { - objectMap["objectType"] = rti.ObjectType - } - return json.Marshal(objectMap) -} - -// AsItemLevelRestoreTargetInfo is the BasicRestoreTargetInfoBase implementation for RestoreTargetInfo. -func (rti RestoreTargetInfo) AsItemLevelRestoreTargetInfo() (*ItemLevelRestoreTargetInfo, bool) { - return nil, false -} - -// AsRestoreFilesTargetInfo is the BasicRestoreTargetInfoBase implementation for RestoreTargetInfo. -func (rti RestoreTargetInfo) AsRestoreFilesTargetInfo() (*RestoreFilesTargetInfo, bool) { - return nil, false -} - -// AsRestoreTargetInfo is the BasicRestoreTargetInfoBase implementation for RestoreTargetInfo. -func (rti RestoreTargetInfo) AsRestoreTargetInfo() (*RestoreTargetInfo, bool) { - return &rti, true -} - -// AsRestoreTargetInfoBase is the BasicRestoreTargetInfoBase implementation for RestoreTargetInfo. -func (rti RestoreTargetInfo) AsRestoreTargetInfoBase() (*RestoreTargetInfoBase, bool) { - return nil, false -} - -// AsBasicRestoreTargetInfoBase is the BasicRestoreTargetInfoBase implementation for RestoreTargetInfo. -func (rti RestoreTargetInfo) AsBasicRestoreTargetInfoBase() (BasicRestoreTargetInfoBase, bool) { - return &rti, true -} - -// UnmarshalJSON is the custom unmarshaler for RestoreTargetInfo struct. -func (rti *RestoreTargetInfo) UnmarshalJSON(body []byte) error { - var m map[string]*json.RawMessage - err := json.Unmarshal(body, &m) - if err != nil { - return err - } - for k, v := range m { - switch k { - case "datasourceInfo": - if v != nil { - var datasourceInfo Datasource - err = json.Unmarshal(*v, &datasourceInfo) - if err != nil { - return err - } - rti.DatasourceInfo = &datasourceInfo - } - case "datasourceSetInfo": - if v != nil { - var datasourceSetInfo DatasourceSet - err = json.Unmarshal(*v, &datasourceSetInfo) - if err != nil { - return err - } - rti.DatasourceSetInfo = &datasourceSetInfo - } - case "datasourceAuthCredentials": - if v != nil { - datasourceAuthCredentials, err := unmarshalBasicAuthCredentials(*v) - if err != nil { - return err - } - rti.DatasourceAuthCredentials = datasourceAuthCredentials - } - case "recoveryOption": - if v != nil { - var recoveryOption string - err = json.Unmarshal(*v, &recoveryOption) - if err != nil { - return err - } - rti.RecoveryOption = &recoveryOption - } - case "restoreLocation": - if v != nil { - var restoreLocation string - err = json.Unmarshal(*v, &restoreLocation) - if err != nil { - return err - } - rti.RestoreLocation = &restoreLocation - } - case "objectType": - if v != nil { - var objectType ObjectTypeBasicRestoreTargetInfoBase - err = json.Unmarshal(*v, &objectType) - if err != nil { - return err - } - rti.ObjectType = objectType - } - } - } - - return nil -} - -// BasicRestoreTargetInfoBase base class common to RestoreTargetInfo and RestoreFilesTargetInfo -type BasicRestoreTargetInfoBase interface { - AsItemLevelRestoreTargetInfo() (*ItemLevelRestoreTargetInfo, bool) - AsRestoreFilesTargetInfo() (*RestoreFilesTargetInfo, bool) - AsRestoreTargetInfo() (*RestoreTargetInfo, bool) - AsRestoreTargetInfoBase() (*RestoreTargetInfoBase, bool) -} - -// RestoreTargetInfoBase base class common to RestoreTargetInfo and RestoreFilesTargetInfo -type RestoreTargetInfoBase struct { - // RecoveryOption - Recovery Option - RecoveryOption *string `json:"recoveryOption,omitempty"` - // RestoreLocation - Target Restore region - RestoreLocation *string `json:"restoreLocation,omitempty"` - // ObjectType - Possible values include: 'ObjectTypeBasicRestoreTargetInfoBaseObjectTypeRestoreTargetInfoBase', 'ObjectTypeBasicRestoreTargetInfoBaseObjectTypeItemLevelRestoreTargetInfo', 'ObjectTypeBasicRestoreTargetInfoBaseObjectTypeRestoreFilesTargetInfo', 'ObjectTypeBasicRestoreTargetInfoBaseObjectTypeRestoreTargetInfo' - ObjectType ObjectTypeBasicRestoreTargetInfoBase `json:"objectType,omitempty"` -} - -func unmarshalBasicRestoreTargetInfoBase(body []byte) (BasicRestoreTargetInfoBase, error) { - var m map[string]interface{} - err := json.Unmarshal(body, &m) - if err != nil { - return nil, err - } - - switch m["objectType"] { - case string(ObjectTypeBasicRestoreTargetInfoBaseObjectTypeItemLevelRestoreTargetInfo): - var ilrti ItemLevelRestoreTargetInfo - err := json.Unmarshal(body, &ilrti) - return ilrti, err - case string(ObjectTypeBasicRestoreTargetInfoBaseObjectTypeRestoreFilesTargetInfo): - var rfti RestoreFilesTargetInfo - err := json.Unmarshal(body, &rfti) - return rfti, err - case string(ObjectTypeBasicRestoreTargetInfoBaseObjectTypeRestoreTargetInfo): - var rti RestoreTargetInfo - err := json.Unmarshal(body, &rti) - return rti, err - default: - var rtib RestoreTargetInfoBase - err := json.Unmarshal(body, &rtib) - return rtib, err - } -} - -func unmarshalBasicRestoreTargetInfoBaseArray(body []byte) ([]BasicRestoreTargetInfoBase, error) { - var rawMessages []*json.RawMessage - err := json.Unmarshal(body, &rawMessages) - if err != nil { - return nil, err - } - - rtibArray := make([]BasicRestoreTargetInfoBase, len(rawMessages)) - - for index, rawMessage := range rawMessages { - rtib, err := unmarshalBasicRestoreTargetInfoBase(*rawMessage) - if err != nil { - return nil, err - } - rtibArray[index] = rtib - } - return rtibArray, nil -} - -// MarshalJSON is the custom marshaler for RestoreTargetInfoBase. -func (rtib RestoreTargetInfoBase) MarshalJSON() ([]byte, error) { - rtib.ObjectType = ObjectTypeBasicRestoreTargetInfoBaseObjectTypeRestoreTargetInfoBase - objectMap := make(map[string]interface{}) - if rtib.RecoveryOption != nil { - objectMap["recoveryOption"] = rtib.RecoveryOption - } - if rtib.RestoreLocation != nil { - objectMap["restoreLocation"] = rtib.RestoreLocation - } - if rtib.ObjectType != "" { - objectMap["objectType"] = rtib.ObjectType - } - return json.Marshal(objectMap) -} - -// AsItemLevelRestoreTargetInfo is the BasicRestoreTargetInfoBase implementation for RestoreTargetInfoBase. -func (rtib RestoreTargetInfoBase) AsItemLevelRestoreTargetInfo() (*ItemLevelRestoreTargetInfo, bool) { - return nil, false -} - -// AsRestoreFilesTargetInfo is the BasicRestoreTargetInfoBase implementation for RestoreTargetInfoBase. -func (rtib RestoreTargetInfoBase) AsRestoreFilesTargetInfo() (*RestoreFilesTargetInfo, bool) { - return nil, false -} - -// AsRestoreTargetInfo is the BasicRestoreTargetInfoBase implementation for RestoreTargetInfoBase. -func (rtib RestoreTargetInfoBase) AsRestoreTargetInfo() (*RestoreTargetInfo, bool) { - return nil, false -} - -// AsRestoreTargetInfoBase is the BasicRestoreTargetInfoBase implementation for RestoreTargetInfoBase. -func (rtib RestoreTargetInfoBase) AsRestoreTargetInfoBase() (*RestoreTargetInfoBase, bool) { - return &rtib, true -} - -// AsBasicRestoreTargetInfoBase is the BasicRestoreTargetInfoBase implementation for RestoreTargetInfoBase. -func (rtib RestoreTargetInfoBase) AsBasicRestoreTargetInfoBase() (BasicRestoreTargetInfoBase, bool) { - return &rtib, true -} - -// RetentionTag retention tag -type RetentionTag struct { - // ETag - READ-ONLY; Retention Tag version. - ETag *string `json:"eTag,omitempty"` - // ID - READ-ONLY; Retention Tag version. - ID *string `json:"id,omitempty"` - // TagName - Retention Tag Name to relate it to retention rule. - TagName *string `json:"tagName,omitempty"` -} - -// MarshalJSON is the custom marshaler for RetentionTag. -func (rt RetentionTag) MarshalJSON() ([]byte, error) { - objectMap := make(map[string]interface{}) - if rt.TagName != nil { - objectMap["tagName"] = rt.TagName - } - return json.Marshal(objectMap) -} - -// ScheduleBasedBackupCriteria schedule based backup criteria -type ScheduleBasedBackupCriteria struct { - // AbsoluteCriteria - it contains absolute values like "AllBackup" / "FirstOfDay" / "FirstOfWeek" / "FirstOfMonth" - // and should be part of AbsoluteMarker enum - AbsoluteCriteria *[]AbsoluteMarker `json:"absoluteCriteria,omitempty"` - // DaysOfMonth - This is day of the month from 1 to 28 other wise last of month - DaysOfMonth *[]Day `json:"daysOfMonth,omitempty"` - // DaysOfTheWeek - It should be Sunday/Monday/T..../Saturday - DaysOfTheWeek *[]DayOfWeek `json:"daysOfTheWeek,omitempty"` - // MonthsOfYear - It should be January/February/....../December - MonthsOfYear *[]Month `json:"monthsOfYear,omitempty"` - // ScheduleTimes - List of schedule times for backup - ScheduleTimes *[]date.Time `json:"scheduleTimes,omitempty"` - // WeeksOfTheMonth - It should be First/Second/Third/Fourth/Last - WeeksOfTheMonth *[]WeekNumber `json:"weeksOfTheMonth,omitempty"` - // ObjectType - Possible values include: 'ObjectTypeBasicBackupCriteriaObjectTypeBackupCriteria', 'ObjectTypeBasicBackupCriteriaObjectTypeScheduleBasedBackupCriteria' - ObjectType ObjectTypeBasicBackupCriteria `json:"objectType,omitempty"` -} - -// MarshalJSON is the custom marshaler for ScheduleBasedBackupCriteria. -func (sbbc ScheduleBasedBackupCriteria) MarshalJSON() ([]byte, error) { - sbbc.ObjectType = ObjectTypeBasicBackupCriteriaObjectTypeScheduleBasedBackupCriteria - objectMap := make(map[string]interface{}) - if sbbc.AbsoluteCriteria != nil { - objectMap["absoluteCriteria"] = sbbc.AbsoluteCriteria - } - if sbbc.DaysOfMonth != nil { - objectMap["daysOfMonth"] = sbbc.DaysOfMonth - } - if sbbc.DaysOfTheWeek != nil { - objectMap["daysOfTheWeek"] = sbbc.DaysOfTheWeek - } - if sbbc.MonthsOfYear != nil { - objectMap["monthsOfYear"] = sbbc.MonthsOfYear - } - if sbbc.ScheduleTimes != nil { - objectMap["scheduleTimes"] = sbbc.ScheduleTimes - } - if sbbc.WeeksOfTheMonth != nil { - objectMap["weeksOfTheMonth"] = sbbc.WeeksOfTheMonth - } - if sbbc.ObjectType != "" { - objectMap["objectType"] = sbbc.ObjectType - } - return json.Marshal(objectMap) -} - -// AsScheduleBasedBackupCriteria is the BasicBackupCriteria implementation for ScheduleBasedBackupCriteria. -func (sbbc ScheduleBasedBackupCriteria) AsScheduleBasedBackupCriteria() (*ScheduleBasedBackupCriteria, bool) { - return &sbbc, true -} - -// AsBackupCriteria is the BasicBackupCriteria implementation for ScheduleBasedBackupCriteria. -func (sbbc ScheduleBasedBackupCriteria) AsBackupCriteria() (*BackupCriteria, bool) { - return nil, false -} - -// AsBasicBackupCriteria is the BasicBackupCriteria implementation for ScheduleBasedBackupCriteria. -func (sbbc ScheduleBasedBackupCriteria) AsBasicBackupCriteria() (BasicBackupCriteria, bool) { - return &sbbc, true -} - -// ScheduleBasedTriggerContext schedule based trigger context -type ScheduleBasedTriggerContext struct { - // Schedule - Schedule for this backup - Schedule *BackupSchedule `json:"schedule,omitempty"` - // TaggingCriteria - List of tags that can be applicable for given schedule. - TaggingCriteria *[]TaggingCriteria `json:"taggingCriteria,omitempty"` - // ObjectType - Possible values include: 'ObjectTypeBasicTriggerContextObjectTypeTriggerContext', 'ObjectTypeBasicTriggerContextObjectTypeAdhocBasedTriggerContext', 'ObjectTypeBasicTriggerContextObjectTypeScheduleBasedTriggerContext' - ObjectType ObjectTypeBasicTriggerContext `json:"objectType,omitempty"` -} - -// MarshalJSON is the custom marshaler for ScheduleBasedTriggerContext. -func (sbtc ScheduleBasedTriggerContext) MarshalJSON() ([]byte, error) { - sbtc.ObjectType = ObjectTypeBasicTriggerContextObjectTypeScheduleBasedTriggerContext - objectMap := make(map[string]interface{}) - if sbtc.Schedule != nil { - objectMap["schedule"] = sbtc.Schedule - } - if sbtc.TaggingCriteria != nil { - objectMap["taggingCriteria"] = sbtc.TaggingCriteria - } - if sbtc.ObjectType != "" { - objectMap["objectType"] = sbtc.ObjectType - } - return json.Marshal(objectMap) -} - -// AsAdhocBasedTriggerContext is the BasicTriggerContext implementation for ScheduleBasedTriggerContext. -func (sbtc ScheduleBasedTriggerContext) AsAdhocBasedTriggerContext() (*AdhocBasedTriggerContext, bool) { - return nil, false -} - -// AsScheduleBasedTriggerContext is the BasicTriggerContext implementation for ScheduleBasedTriggerContext. -func (sbtc ScheduleBasedTriggerContext) AsScheduleBasedTriggerContext() (*ScheduleBasedTriggerContext, bool) { - return &sbtc, true -} - -// AsTriggerContext is the BasicTriggerContext implementation for ScheduleBasedTriggerContext. -func (sbtc ScheduleBasedTriggerContext) AsTriggerContext() (*TriggerContext, bool) { - return nil, false -} - -// AsBasicTriggerContext is the BasicTriggerContext implementation for ScheduleBasedTriggerContext. -func (sbtc ScheduleBasedTriggerContext) AsBasicTriggerContext() (BasicTriggerContext, bool) { - return &sbtc, true -} - -// SecretStoreBasedAuthCredentials secret store based authentication credentials. -type SecretStoreBasedAuthCredentials struct { - // SecretStoreResource - Secret store resource - SecretStoreResource *SecretStoreResource `json:"secretStoreResource,omitempty"` - // ObjectType - Possible values include: 'ObjectTypeAuthCredentials', 'ObjectTypeSecretStoreBasedAuthCredentials' - ObjectType ObjectType `json:"objectType,omitempty"` -} - -// MarshalJSON is the custom marshaler for SecretStoreBasedAuthCredentials. -func (ssbac SecretStoreBasedAuthCredentials) MarshalJSON() ([]byte, error) { - ssbac.ObjectType = ObjectTypeSecretStoreBasedAuthCredentials - objectMap := make(map[string]interface{}) - if ssbac.SecretStoreResource != nil { - objectMap["secretStoreResource"] = ssbac.SecretStoreResource - } - if ssbac.ObjectType != "" { - objectMap["objectType"] = ssbac.ObjectType - } - return json.Marshal(objectMap) -} - -// AsSecretStoreBasedAuthCredentials is the BasicAuthCredentials implementation for SecretStoreBasedAuthCredentials. -func (ssbac SecretStoreBasedAuthCredentials) AsSecretStoreBasedAuthCredentials() (*SecretStoreBasedAuthCredentials, bool) { - return &ssbac, true -} - -// AsAuthCredentials is the BasicAuthCredentials implementation for SecretStoreBasedAuthCredentials. -func (ssbac SecretStoreBasedAuthCredentials) AsAuthCredentials() (*AuthCredentials, bool) { - return nil, false -} - -// AsBasicAuthCredentials is the BasicAuthCredentials implementation for SecretStoreBasedAuthCredentials. -func (ssbac SecretStoreBasedAuthCredentials) AsBasicAuthCredentials() (BasicAuthCredentials, bool) { - return &ssbac, true -} - -// SecretStoreResource class representing a secret store resource. -type SecretStoreResource struct { - // URI - Uri to get to the resource - URI *string `json:"uri,omitempty"` - // SecretStoreType - Gets or sets the type of secret store. Possible values include: 'SecretStoreTypeInvalid', 'SecretStoreTypeAzureKeyVault' - SecretStoreType SecretStoreType `json:"secretStoreType,omitempty"` -} - -// SourceLifeCycle source LifeCycle -type SourceLifeCycle struct { - DeleteAfter BasicDeleteOption `json:"deleteAfter,omitempty"` - SourceDataStore *DataStoreInfoBase `json:"sourceDataStore,omitempty"` - TargetDataStoreCopySettings *[]TargetCopySetting `json:"targetDataStoreCopySettings,omitempty"` -} - -// UnmarshalJSON is the custom unmarshaler for SourceLifeCycle struct. -func (slc *SourceLifeCycle) UnmarshalJSON(body []byte) error { - var m map[string]*json.RawMessage - err := json.Unmarshal(body, &m) - if err != nil { - return err - } - for k, v := range m { - switch k { - case "deleteAfter": - if v != nil { - deleteAfter, err := unmarshalBasicDeleteOption(*v) - if err != nil { - return err - } - slc.DeleteAfter = deleteAfter - } - case "sourceDataStore": - if v != nil { - var sourceDataStore DataStoreInfoBase - err = json.Unmarshal(*v, &sourceDataStore) - if err != nil { - return err - } - slc.SourceDataStore = &sourceDataStore - } - case "targetDataStoreCopySettings": - if v != nil { - var targetDataStoreCopySettings []TargetCopySetting - err = json.Unmarshal(*v, &targetDataStoreCopySettings) - if err != nil { - return err - } - slc.TargetDataStoreCopySettings = &targetDataStoreCopySettings - } - } - } - - return nil -} - -// StorageSetting storage setting -type StorageSetting struct { - // DatastoreType - Gets or sets the type of the datastore. Possible values include: 'StorageSettingStoreTypesArchiveStore', 'StorageSettingStoreTypesSnapshotStore', 'StorageSettingStoreTypesVaultStore' - DatastoreType StorageSettingStoreTypes `json:"datastoreType,omitempty"` - // Type - Gets or sets the type. Possible values include: 'StorageSettingTypesGeoRedundant', 'StorageSettingTypesLocallyRedundant' - Type StorageSettingTypes `json:"type,omitempty"` -} - -// SupportedFeature elements class for feature request -type SupportedFeature struct { - // FeatureName - support feature type. - FeatureName *string `json:"featureName,omitempty"` - // SupportStatus - feature support status. Possible values include: 'FeatureSupportStatusInvalid', 'FeatureSupportStatusNotSupported', 'FeatureSupportStatusAlphaPreview', 'FeatureSupportStatusPrivatePreview', 'FeatureSupportStatusPublicPreview', 'FeatureSupportStatusGenerallyAvailable' - SupportStatus FeatureSupportStatus `json:"supportStatus,omitempty"` - // ExposureControlledFeatures - support feature type. - ExposureControlledFeatures *[]string `json:"exposureControlledFeatures,omitempty"` -} - -// SystemData metadata pertaining to creation and last modification of the resource. -type SystemData struct { - // CreatedBy - The identity that created the resource. - CreatedBy *string `json:"createdBy,omitempty"` - // CreatedByType - The type of identity that created the resource. Possible values include: 'CreatedByTypeUser', 'CreatedByTypeApplication', 'CreatedByTypeManagedIdentity', 'CreatedByTypeKey' - CreatedByType CreatedByType `json:"createdByType,omitempty"` - // CreatedAt - The timestamp of resource creation (UTC). - CreatedAt *date.Time `json:"createdAt,omitempty"` - // LastModifiedBy - The identity that last modified the resource. - LastModifiedBy *string `json:"lastModifiedBy,omitempty"` - // LastModifiedByType - The type of identity that last modified the resource. Possible values include: 'CreatedByTypeUser', 'CreatedByTypeApplication', 'CreatedByTypeManagedIdentity', 'CreatedByTypeKey' - LastModifiedByType CreatedByType `json:"lastModifiedByType,omitempty"` - // LastModifiedAt - The type of identity that last modified the resource. - LastModifiedAt *date.Time `json:"lastModifiedAt,omitempty"` -} - -// TaggingCriteria tagging criteria -type TaggingCriteria struct { - // Criteria - Criteria which decides whether the tag can be applied to a triggered backup. - Criteria *[]BasicBackupCriteria `json:"criteria,omitempty"` - // IsDefault - Specifies if tag is default. - IsDefault *bool `json:"isDefault,omitempty"` - // TaggingPriority - Retention Tag priority. - TaggingPriority *int64 `json:"taggingPriority,omitempty"` - // TagInfo - Retention tag information - TagInfo *RetentionTag `json:"tagInfo,omitempty"` -} - -// UnmarshalJSON is the custom unmarshaler for TaggingCriteria struct. -func (tc *TaggingCriteria) UnmarshalJSON(body []byte) error { - var m map[string]*json.RawMessage - err := json.Unmarshal(body, &m) - if err != nil { - return err - } - for k, v := range m { - switch k { - case "criteria": - if v != nil { - criteria, err := unmarshalBasicBackupCriteriaArray(*v) - if err != nil { - return err - } - tc.Criteria = &criteria - } - case "isDefault": - if v != nil { - var isDefault bool - err = json.Unmarshal(*v, &isDefault) - if err != nil { - return err - } - tc.IsDefault = &isDefault - } - case "taggingPriority": - if v != nil { - var taggingPriority int64 - err = json.Unmarshal(*v, &taggingPriority) - if err != nil { - return err - } - tc.TaggingPriority = &taggingPriority - } - case "tagInfo": - if v != nil { - var tagInfo RetentionTag - err = json.Unmarshal(*v, &tagInfo) - if err != nil { - return err - } - tc.TagInfo = &tagInfo - } - } - } - - return nil -} - -// TargetCopySetting target copy settings -type TargetCopySetting struct { - // CopyAfter - It can be CustomCopyOption or ImmediateCopyOption. - CopyAfter BasicCopyOption `json:"copyAfter,omitempty"` - // DataStore - Info of target datastore - DataStore *DataStoreInfoBase `json:"dataStore,omitempty"` -} - -// UnmarshalJSON is the custom unmarshaler for TargetCopySetting struct. -func (tcs *TargetCopySetting) UnmarshalJSON(body []byte) error { - var m map[string]*json.RawMessage - err := json.Unmarshal(body, &m) - if err != nil { - return err - } - for k, v := range m { - switch k { - case "copyAfter": - if v != nil { - copyAfter, err := unmarshalBasicCopyOption(*v) - if err != nil { - return err - } - tcs.CopyAfter = copyAfter - } - case "dataStore": - if v != nil { - var dataStore DataStoreInfoBase - err = json.Unmarshal(*v, &dataStore) - if err != nil { - return err - } - tcs.DataStore = &dataStore - } - } - } - - return nil -} - -// TargetDetails class encapsulating target details, used where the destination is not a datasource -type TargetDetails struct { - // FilePrefix - Restore operation may create multiple files inside location pointed by Url - // Below will be the common prefix for all of them - FilePrefix *string `json:"filePrefix,omitempty"` - // RestoreTargetLocationType - Denotes the target location where the data will be restored, - // string value for the enum {Microsoft.Internal.AzureBackup.DataProtection.Common.Interface.RestoreTargetLocationType}. Possible values include: 'RestoreTargetLocationTypeInvalid', 'RestoreTargetLocationTypeAzureBlobs', 'RestoreTargetLocationTypeAzureFiles' - RestoreTargetLocationType RestoreTargetLocationType `json:"restoreTargetLocationType,omitempty"` - // URL - Url denoting the restore destination. It can point to container / file share etc - URL *string `json:"url,omitempty"` -} - -// TriggerBackupRequest trigger backup request -type TriggerBackupRequest struct { - // BackupRuleOptions - Name for the Rule of the Policy which needs to be applied for this backup - BackupRuleOptions *AdHocBackupRuleOptions `json:"backupRuleOptions,omitempty"` -} - -// BasicTriggerContext trigger context -type BasicTriggerContext interface { - AsAdhocBasedTriggerContext() (*AdhocBasedTriggerContext, bool) - AsScheduleBasedTriggerContext() (*ScheduleBasedTriggerContext, bool) - AsTriggerContext() (*TriggerContext, bool) -} - -// TriggerContext trigger context -type TriggerContext struct { - // ObjectType - Possible values include: 'ObjectTypeBasicTriggerContextObjectTypeTriggerContext', 'ObjectTypeBasicTriggerContextObjectTypeAdhocBasedTriggerContext', 'ObjectTypeBasicTriggerContextObjectTypeScheduleBasedTriggerContext' - ObjectType ObjectTypeBasicTriggerContext `json:"objectType,omitempty"` -} - -func unmarshalBasicTriggerContext(body []byte) (BasicTriggerContext, error) { - var m map[string]interface{} - err := json.Unmarshal(body, &m) - if err != nil { - return nil, err - } - - switch m["objectType"] { - case string(ObjectTypeBasicTriggerContextObjectTypeAdhocBasedTriggerContext): - var abtc AdhocBasedTriggerContext - err := json.Unmarshal(body, &abtc) - return abtc, err - case string(ObjectTypeBasicTriggerContextObjectTypeScheduleBasedTriggerContext): - var sbtc ScheduleBasedTriggerContext - err := json.Unmarshal(body, &sbtc) - return sbtc, err - default: - var tc TriggerContext - err := json.Unmarshal(body, &tc) - return tc, err - } -} - -func unmarshalBasicTriggerContextArray(body []byte) ([]BasicTriggerContext, error) { - var rawMessages []*json.RawMessage - err := json.Unmarshal(body, &rawMessages) - if err != nil { - return nil, err - } - - tcArray := make([]BasicTriggerContext, len(rawMessages)) - - for index, rawMessage := range rawMessages { - tc, err := unmarshalBasicTriggerContext(*rawMessage) - if err != nil { - return nil, err - } - tcArray[index] = tc - } - return tcArray, nil -} - -// MarshalJSON is the custom marshaler for TriggerContext. -func (tc TriggerContext) MarshalJSON() ([]byte, error) { - tc.ObjectType = ObjectTypeBasicTriggerContextObjectTypeTriggerContext - objectMap := make(map[string]interface{}) - if tc.ObjectType != "" { - objectMap["objectType"] = tc.ObjectType - } - return json.Marshal(objectMap) -} - -// AsAdhocBasedTriggerContext is the BasicTriggerContext implementation for TriggerContext. -func (tc TriggerContext) AsAdhocBasedTriggerContext() (*AdhocBasedTriggerContext, bool) { - return nil, false -} - -// AsScheduleBasedTriggerContext is the BasicTriggerContext implementation for TriggerContext. -func (tc TriggerContext) AsScheduleBasedTriggerContext() (*ScheduleBasedTriggerContext, bool) { - return nil, false -} - -// AsTriggerContext is the BasicTriggerContext implementation for TriggerContext. -func (tc TriggerContext) AsTriggerContext() (*TriggerContext, bool) { - return &tc, true -} - -// AsBasicTriggerContext is the BasicTriggerContext implementation for TriggerContext. -func (tc TriggerContext) AsBasicTriggerContext() (BasicTriggerContext, bool) { - return &tc, true -} - -// UserFacingError error object used by layers that have access to localized content, and propagate that to -// user -type UserFacingError struct { - // Code - Unique code for this error - Code *string `json:"code,omitempty"` - // Details - Additional related Errors - Details *[]UserFacingError `json:"details,omitempty"` - // InnerError - Inner Error - InnerError *InnerError `json:"innerError,omitempty"` - // IsRetryable - Whether the operation will be retryable or not - IsRetryable *bool `json:"isRetryable,omitempty"` - // IsUserError - Whether the operation is due to a user error or service error - IsUserError *bool `json:"isUserError,omitempty"` - // Properties - Any key value pairs that can be injected inside error object - Properties map[string]*string `json:"properties"` - Message *string `json:"message,omitempty"` - // RecommendedAction - RecommendedAction � localized. - RecommendedAction *[]string `json:"recommendedAction,omitempty"` - // Target - Target of the error. - Target *string `json:"target,omitempty"` -} - -// MarshalJSON is the custom marshaler for UserFacingError. -func (ufe UserFacingError) MarshalJSON() ([]byte, error) { - objectMap := make(map[string]interface{}) - if ufe.Code != nil { - objectMap["code"] = ufe.Code - } - if ufe.Details != nil { - objectMap["details"] = ufe.Details - } - if ufe.InnerError != nil { - objectMap["innerError"] = ufe.InnerError - } - if ufe.IsRetryable != nil { - objectMap["isRetryable"] = ufe.IsRetryable - } - if ufe.IsUserError != nil { - objectMap["isUserError"] = ufe.IsUserError - } - if ufe.Properties != nil { - objectMap["properties"] = ufe.Properties - } - if ufe.Message != nil { - objectMap["message"] = ufe.Message - } - if ufe.RecommendedAction != nil { - objectMap["recommendedAction"] = ufe.RecommendedAction - } - if ufe.Target != nil { - objectMap["target"] = ufe.Target - } - return json.Marshal(objectMap) -} - -// ValidateForBackupRequest validate for backup request -type ValidateForBackupRequest struct { - BackupInstance *BackupInstance `json:"backupInstance,omitempty"` -} - -// ValidateRestoreRequestObject validate restore request object -type ValidateRestoreRequestObject struct { - // RestoreRequestObject - Gets or sets the restore request object. - RestoreRequestObject BasicAzureBackupRestoreRequest `json:"restoreRequestObject,omitempty"` -} - -// UnmarshalJSON is the custom unmarshaler for ValidateRestoreRequestObject struct. -func (vrro *ValidateRestoreRequestObject) UnmarshalJSON(body []byte) error { - var m map[string]*json.RawMessage - err := json.Unmarshal(body, &m) - if err != nil { - return err - } - for k, v := range m { - switch k { - case "restoreRequestObject": - if v != nil { - restoreRequestObject, err := unmarshalBasicAzureBackupRestoreRequest(*v) - if err != nil { - return err - } - vrro.RestoreRequestObject = restoreRequestObject - } - } - } - - return nil -} diff --git a/internal/services/dataprotection/legacysdk/dataprotection/operationresult.go b/internal/services/dataprotection/legacysdk/dataprotection/operationresult.go deleted file mode 100644 index f7a730cee05f..000000000000 --- a/internal/services/dataprotection/legacysdk/dataprotection/operationresult.go +++ /dev/null @@ -1,105 +0,0 @@ -package dataprotection - -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. -// -// Code generated by Microsoft (R) AutoRest Code Generator. -// Changes may cause incorrect behavior and will be lost if the code is regenerated. - -import ( - "context" - "net/http" - - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/azure" - "github.com/Azure/go-autorest/tracing" -) - -// OperationResultClient is the open API 2.0 Specs for Azure Data Protection service -type OperationResultClient struct { - BaseClient -} - -// NewOperationResultClient creates an instance of the OperationResultClient client. -func NewOperationResultClient(subscriptionID string) OperationResultClient { - return NewOperationResultClientWithBaseURI(DefaultBaseURI, subscriptionID) -} - -// NewOperationResultClientWithBaseURI creates an instance of the OperationResultClient client using a custom endpoint. -// Use this when interacting with an Azure cloud that uses a non-standard base URI (sovereign clouds, Azure stack). -func NewOperationResultClientWithBaseURI(baseURI string, subscriptionID string) OperationResultClient { - return OperationResultClient{NewWithBaseURI(baseURI, subscriptionID)} -} - -// Get gets the operation result for a resource -func (client OperationResultClient) Get(ctx context.Context, operationID string, location string) (result OperationJobExtendedInfo, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/OperationResultClient.Get") - defer func() { - sc := -1 - if result.Response.Response != nil { - sc = result.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - req, err := client.GetPreparer(ctx, operationID, location) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.OperationResultClient", "Get", nil, "Failure preparing request") - return - } - - resp, err := client.GetSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.OperationResultClient", "Get", resp, "Failure sending request") - return - } - - result, err = client.GetResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.OperationResultClient", "Get", resp, "Failure responding to request") - return - } - - return -} - -// GetPreparer prepares the Get request. -func (client OperationResultClient) GetPreparer(ctx context.Context, operationID string, location string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "location": autorest.Encode("path", location), - "operationId": autorest.Encode("path", operationID), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsGet(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/providers/Microsoft.DataProtection/locations/{location}/operationResults/{operationId}", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// GetSender sends the Get request. The method will close the -// http.Response Body if it receives an error. -func (client OperationResultClient) GetSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// GetResponder handles the response to the Get request. The method always -// closes the http.Response Body. -func (client OperationResultClient) GetResponder(resp *http.Response) (result OperationJobExtendedInfo, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusAccepted), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} diff --git a/internal/services/dataprotection/legacysdk/dataprotection/operations.go b/internal/services/dataprotection/legacysdk/dataprotection/operations.go deleted file mode 100644 index c2f1b1c58e0b..000000000000 --- a/internal/services/dataprotection/legacysdk/dataprotection/operations.go +++ /dev/null @@ -1,141 +0,0 @@ -package dataprotection - -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. -// -// Code generated by Microsoft (R) AutoRest Code Generator. -// Changes may cause incorrect behavior and will be lost if the code is regenerated. - -import ( - "context" - "net/http" - - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/azure" - "github.com/Azure/go-autorest/tracing" -) - -// OperationsClient is the open API 2.0 Specs for Azure Data Protection service -type OperationsClient struct { - BaseClient -} - -// NewOperationsClient creates an instance of the OperationsClient client. -func NewOperationsClient(subscriptionID string) OperationsClient { - return NewOperationsClientWithBaseURI(DefaultBaseURI, subscriptionID) -} - -// NewOperationsClientWithBaseURI creates an instance of the OperationsClient client using a custom endpoint. Use this -// when interacting with an Azure cloud that uses a non-standard base URI (sovereign clouds, Azure stack). -func NewOperationsClientWithBaseURI(baseURI string, subscriptionID string) OperationsClient { - return OperationsClient{NewWithBaseURI(baseURI, subscriptionID)} -} - -// List returns the list of available operations. -func (client OperationsClient) List(ctx context.Context) (result ClientDiscoveryResponsePage, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/OperationsClient.List") - defer func() { - sc := -1 - if result.cdr.Response.Response != nil { - sc = result.cdr.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - result.fn = client.listNextResults - req, err := client.ListPreparer(ctx) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.OperationsClient", "List", nil, "Failure preparing request") - return - } - - resp, err := client.ListSender(req) - if err != nil { - result.cdr.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.OperationsClient", "List", resp, "Failure sending request") - return - } - - result.cdr, err = client.ListResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.OperationsClient", "List", resp, "Failure responding to request") - return - } - if result.cdr.hasNextLink() && result.cdr.IsEmpty() { - err = result.NextWithContext(ctx) - return - } - - return -} - -// ListPreparer prepares the List request. -func (client OperationsClient) ListPreparer(ctx context.Context) (*http.Request, error) { - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsGet(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPath("/providers/Microsoft.DataProtection/operations"), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// ListSender sends the List request. The method will close the -// http.Response Body if it receives an error. -func (client OperationsClient) ListSender(req *http.Request) (*http.Response, error) { - return client.Send(req, autorest.DoRetryForStatusCodes(client.RetryAttempts, client.RetryDuration, autorest.StatusCodesForRetry...)) -} - -// ListResponder handles the response to the List request. The method always -// closes the http.Response Body. -func (client OperationsClient) ListResponder(resp *http.Response) (result ClientDiscoveryResponse, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// listNextResults retrieves the next set of results, if any. -func (client OperationsClient) listNextResults(ctx context.Context, lastResults ClientDiscoveryResponse) (result ClientDiscoveryResponse, err error) { - req, err := lastResults.clientDiscoveryResponsePreparer(ctx) - if err != nil { - return result, autorest.NewErrorWithError(err, "dataprotection.OperationsClient", "listNextResults", nil, "Failure preparing next results request") - } - if req == nil { - return - } - resp, err := client.ListSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - return result, autorest.NewErrorWithError(err, "dataprotection.OperationsClient", "listNextResults", resp, "Failure sending next results request") - } - result, err = client.ListResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.OperationsClient", "listNextResults", resp, "Failure responding to next results request") - } - return -} - -// ListComplete enumerates all values, automatically crossing page boundaries as required. -func (client OperationsClient) ListComplete(ctx context.Context) (result ClientDiscoveryResponseIterator, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/OperationsClient.List") - defer func() { - sc := -1 - if result.Response().Response.Response != nil { - sc = result.page.Response().Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - result.page, err = client.List(ctx) - return -} diff --git a/internal/services/dataprotection/legacysdk/dataprotection/operationstatus.go b/internal/services/dataprotection/legacysdk/dataprotection/operationstatus.go deleted file mode 100644 index f39eb64e4343..000000000000 --- a/internal/services/dataprotection/legacysdk/dataprotection/operationstatus.go +++ /dev/null @@ -1,105 +0,0 @@ -package dataprotection - -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. -// -// Code generated by Microsoft (R) AutoRest Code Generator. -// Changes may cause incorrect behavior and will be lost if the code is regenerated. - -import ( - "context" - "net/http" - - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/azure" - "github.com/Azure/go-autorest/tracing" -) - -// OperationStatusClient is the open API 2.0 Specs for Azure Data Protection service -type OperationStatusClient struct { - BaseClient -} - -// NewOperationStatusClient creates an instance of the OperationStatusClient client. -func NewOperationStatusClient(subscriptionID string) OperationStatusClient { - return NewOperationStatusClientWithBaseURI(DefaultBaseURI, subscriptionID) -} - -// NewOperationStatusClientWithBaseURI creates an instance of the OperationStatusClient client using a custom endpoint. -// Use this when interacting with an Azure cloud that uses a non-standard base URI (sovereign clouds, Azure stack). -func NewOperationStatusClientWithBaseURI(baseURI string, subscriptionID string) OperationStatusClient { - return OperationStatusClient{NewWithBaseURI(baseURI, subscriptionID)} -} - -// Get sends the get request. -func (client OperationStatusClient) Get(ctx context.Context, location string, operationID string) (result OperationResource, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/OperationStatusClient.Get") - defer func() { - sc := -1 - if result.Response.Response != nil { - sc = result.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - req, err := client.GetPreparer(ctx, location, operationID) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.OperationStatusClient", "Get", nil, "Failure preparing request") - return - } - - resp, err := client.GetSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.OperationStatusClient", "Get", resp, "Failure sending request") - return - } - - result, err = client.GetResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.OperationStatusClient", "Get", resp, "Failure responding to request") - return - } - - return -} - -// GetPreparer prepares the Get request. -func (client OperationStatusClient) GetPreparer(ctx context.Context, location string, operationID string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "location": autorest.Encode("path", location), - "operationId": autorest.Encode("path", operationID), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsGet(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/providers/Microsoft.DataProtection/locations/{location}/operationStatus/{operationId}", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// GetSender sends the Get request. The method will close the -// http.Response Body if it receives an error. -func (client OperationStatusClient) GetSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// GetResponder handles the response to the Get request. The method always -// closes the http.Response Body. -func (client OperationStatusClient) GetResponder(resp *http.Response) (result OperationResource, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} diff --git a/internal/services/dataprotection/legacysdk/dataprotection/recoverypoints.go b/internal/services/dataprotection/legacysdk/dataprotection/recoverypoints.go deleted file mode 100644 index 3b3cbbda7fbf..000000000000 --- a/internal/services/dataprotection/legacysdk/dataprotection/recoverypoints.go +++ /dev/null @@ -1,239 +0,0 @@ -package dataprotection - -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. -// -// Code generated by Microsoft (R) AutoRest Code Generator. -// Changes may cause incorrect behavior and will be lost if the code is regenerated. - -import ( - "context" - "net/http" - - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/azure" - "github.com/Azure/go-autorest/tracing" -) - -// RecoveryPointsClient is the open API 2.0 Specs for Azure Data Protection service -type RecoveryPointsClient struct { - BaseClient -} - -// NewRecoveryPointsClient creates an instance of the RecoveryPointsClient client. -func NewRecoveryPointsClient(subscriptionID string) RecoveryPointsClient { - return NewRecoveryPointsClientWithBaseURI(DefaultBaseURI, subscriptionID) -} - -// NewRecoveryPointsClientWithBaseURI creates an instance of the RecoveryPointsClient client using a custom endpoint. -// Use this when interacting with an Azure cloud that uses a non-standard base URI (sovereign clouds, Azure stack). -func NewRecoveryPointsClientWithBaseURI(baseURI string, subscriptionID string) RecoveryPointsClient { - return RecoveryPointsClient{NewWithBaseURI(baseURI, subscriptionID)} -} - -// Get gets a Recovery Point using recoveryPointId for a Datasource. -// Parameters: -// vaultName - the name of the backup vault. -// resourceGroupName - the name of the resource group where the backup vault is present. -// backupInstanceName - the name of the backup instance -func (client RecoveryPointsClient) Get(ctx context.Context, vaultName string, resourceGroupName string, backupInstanceName string, recoveryPointID string) (result AzureBackupRecoveryPointResource, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/RecoveryPointsClient.Get") - defer func() { - sc := -1 - if result.Response.Response != nil { - sc = result.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - req, err := client.GetPreparer(ctx, vaultName, resourceGroupName, backupInstanceName, recoveryPointID) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.RecoveryPointsClient", "Get", nil, "Failure preparing request") - return - } - - resp, err := client.GetSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.RecoveryPointsClient", "Get", resp, "Failure sending request") - return - } - - result, err = client.GetResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.RecoveryPointsClient", "Get", resp, "Failure responding to request") - return - } - - return -} - -// GetPreparer prepares the Get request. -func (client RecoveryPointsClient) GetPreparer(ctx context.Context, vaultName string, resourceGroupName string, backupInstanceName string, recoveryPointID string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "backupInstanceName": autorest.Encode("path", backupInstanceName), - "recoveryPointId": autorest.Encode("path", recoveryPointID), - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - "vaultName": autorest.Encode("path", vaultName), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsGet(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/backupVaults/{vaultName}/backupInstances/{backupInstanceName}/recoveryPoints/{recoveryPointId}", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// GetSender sends the Get request. The method will close the -// http.Response Body if it receives an error. -func (client RecoveryPointsClient) GetSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// GetResponder handles the response to the Get request. The method always -// closes the http.Response Body. -func (client RecoveryPointsClient) GetResponder(resp *http.Response) (result AzureBackupRecoveryPointResource, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// List returns a list of Recovery Points for a DataSource in a vault. -// Parameters: -// vaultName - the name of the backup vault. -// resourceGroupName - the name of the resource group where the backup vault is present. -// backupInstanceName - the name of the backup instance -// filter - oData filter options. -// skipToken - skipToken Filter. -func (client RecoveryPointsClient) List(ctx context.Context, vaultName string, resourceGroupName string, backupInstanceName string, filter string, skipToken string) (result AzureBackupRecoveryPointResourceListPage, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/RecoveryPointsClient.List") - defer func() { - sc := -1 - if result.abrprl.Response.Response != nil { - sc = result.abrprl.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - result.fn = client.listNextResults - req, err := client.ListPreparer(ctx, vaultName, resourceGroupName, backupInstanceName, filter, skipToken) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.RecoveryPointsClient", "List", nil, "Failure preparing request") - return - } - - resp, err := client.ListSender(req) - if err != nil { - result.abrprl.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.RecoveryPointsClient", "List", resp, "Failure sending request") - return - } - - result.abrprl, err = client.ListResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.RecoveryPointsClient", "List", resp, "Failure responding to request") - return - } - if result.abrprl.hasNextLink() && result.abrprl.IsEmpty() { - err = result.NextWithContext(ctx) - return - } - - return -} - -// ListPreparer prepares the List request. -func (client RecoveryPointsClient) ListPreparer(ctx context.Context, vaultName string, resourceGroupName string, backupInstanceName string, filter string, skipToken string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "backupInstanceName": autorest.Encode("path", backupInstanceName), - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - "vaultName": autorest.Encode("path", vaultName), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - if len(filter) > 0 { - queryParameters["$filter"] = autorest.Encode("query", filter) - } - if len(skipToken) > 0 { - queryParameters["$skipToken"] = autorest.Encode("query", skipToken) - } - - preparer := autorest.CreatePreparer( - autorest.AsGet(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/backupVaults/{vaultName}/backupInstances/{backupInstanceName}/recoveryPoints", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// ListSender sends the List request. The method will close the -// http.Response Body if it receives an error. -func (client RecoveryPointsClient) ListSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// ListResponder handles the response to the List request. The method always -// closes the http.Response Body. -func (client RecoveryPointsClient) ListResponder(resp *http.Response) (result AzureBackupRecoveryPointResourceList, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// listNextResults retrieves the next set of results, if any. -func (client RecoveryPointsClient) listNextResults(ctx context.Context, lastResults AzureBackupRecoveryPointResourceList) (result AzureBackupRecoveryPointResourceList, err error) { - req, err := lastResults.azureBackupRecoveryPointResourceListPreparer(ctx) - if err != nil { - return result, autorest.NewErrorWithError(err, "dataprotection.RecoveryPointsClient", "listNextResults", nil, "Failure preparing next results request") - } - if req == nil { - return - } - resp, err := client.ListSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - return result, autorest.NewErrorWithError(err, "dataprotection.RecoveryPointsClient", "listNextResults", resp, "Failure sending next results request") - } - result, err = client.ListResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.RecoveryPointsClient", "listNextResults", resp, "Failure responding to next results request") - } - return -} - -// ListComplete enumerates all values, automatically crossing page boundaries as required. -func (client RecoveryPointsClient) ListComplete(ctx context.Context, vaultName string, resourceGroupName string, backupInstanceName string, filter string, skipToken string) (result AzureBackupRecoveryPointResourceListIterator, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/RecoveryPointsClient.List") - defer func() { - sc := -1 - if result.Response().Response.Response != nil { - sc = result.page.Response().Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - result.page, err = client.List(ctx, vaultName, resourceGroupName, backupInstanceName, filter, skipToken) - return -} diff --git a/internal/services/dataprotection/legacysdk/dataprotection/resourceguards.go b/internal/services/dataprotection/legacysdk/dataprotection/resourceguards.go deleted file mode 100644 index e745da009ab4..000000000000 --- a/internal/services/dataprotection/legacysdk/dataprotection/resourceguards.go +++ /dev/null @@ -1,1730 +0,0 @@ -package dataprotection - -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. -// -// Code generated by Microsoft (R) AutoRest Code Generator. -// Changes may cause incorrect behavior and will be lost if the code is regenerated. - -import ( - "context" - "net/http" - - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/azure" - "github.com/Azure/go-autorest/tracing" -) - -// ResourceGuardsClient is the open API 2.0 Specs for Azure Data Protection service -type ResourceGuardsClient struct { - BaseClient -} - -// NewResourceGuardsClient creates an instance of the ResourceGuardsClient client. -func NewResourceGuardsClient(subscriptionID string) ResourceGuardsClient { - return NewResourceGuardsClientWithBaseURI(DefaultBaseURI, subscriptionID) -} - -// NewResourceGuardsClientWithBaseURI creates an instance of the ResourceGuardsClient client using a custom endpoint. -// Use this when interacting with an Azure cloud that uses a non-standard base URI (sovereign clouds, Azure stack). -func NewResourceGuardsClientWithBaseURI(baseURI string, subscriptionID string) ResourceGuardsClient { - return ResourceGuardsClient{NewWithBaseURI(baseURI, subscriptionID)} -} - -// Delete sends the delete request. -// Parameters: -// resourceGroupName - the name of the resource group where the backup vault is present. -// resourceGuardsName - the name of ResourceGuard -func (client ResourceGuardsClient) Delete(ctx context.Context, resourceGroupName string, resourceGuardsName string) (result autorest.Response, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/ResourceGuardsClient.Delete") - defer func() { - sc := -1 - if result.Response != nil { - sc = result.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - req, err := client.DeletePreparer(ctx, resourceGroupName, resourceGuardsName) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "Delete", nil, "Failure preparing request") - return - } - - resp, err := client.DeleteSender(req) - if err != nil { - result.Response = resp - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "Delete", resp, "Failure sending request") - return - } - - result, err = client.DeleteResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "Delete", resp, "Failure responding to request") - return - } - - return -} - -// DeletePreparer prepares the Delete request. -func (client ResourceGuardsClient) DeletePreparer(ctx context.Context, resourceGroupName string, resourceGuardsName string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "resourceGuardsName": autorest.Encode("path", resourceGuardsName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsDelete(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/resourceGuards/{resourceGuardsName}", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// DeleteSender sends the Delete request. The method will close the -// http.Response Body if it receives an error. -func (client ResourceGuardsClient) DeleteSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// DeleteResponder handles the response to the Delete request. The method always -// closes the http.Response Body. -func (client ResourceGuardsClient) DeleteResponder(resp *http.Response) (result autorest.Response, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusNoContent), - autorest.ByClosing()) - result.Response = resp - return -} - -// Get sends the get request. -// Parameters: -// resourceGroupName - the name of the resource group where the backup vault is present. -// resourceGuardsName - the name of ResourceGuard -func (client ResourceGuardsClient) Get(ctx context.Context, resourceGroupName string, resourceGuardsName string) (result ResourceGuardResource, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/ResourceGuardsClient.Get") - defer func() { - sc := -1 - if result.Response.Response != nil { - sc = result.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - req, err := client.GetPreparer(ctx, resourceGroupName, resourceGuardsName) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "Get", nil, "Failure preparing request") - return - } - - resp, err := client.GetSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "Get", resp, "Failure sending request") - return - } - - result, err = client.GetResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "Get", resp, "Failure responding to request") - return - } - - return -} - -// GetPreparer prepares the Get request. -func (client ResourceGuardsClient) GetPreparer(ctx context.Context, resourceGroupName string, resourceGuardsName string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "resourceGuardsName": autorest.Encode("path", resourceGuardsName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsGet(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/resourceGuards/{resourceGuardsName}", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// GetSender sends the Get request. The method will close the -// http.Response Body if it receives an error. -func (client ResourceGuardsClient) GetSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// GetResponder handles the response to the Get request. The method always -// closes the http.Response Body. -func (client ResourceGuardsClient) GetResponder(resp *http.Response) (result ResourceGuardResource, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// GetBackupSecurityPINRequestsObjects sends the get backup security pin requests objects request. -// Parameters: -// resourceGroupName - the name of the resource group where the backup vault is present. -func (client ResourceGuardsClient) GetBackupSecurityPINRequestsObjects(ctx context.Context, resourceGroupName string, resourceGuardsName string) (result DppBaseResourceListPage, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/ResourceGuardsClient.GetBackupSecurityPINRequestsObjects") - defer func() { - sc := -1 - if result.dbrl.Response.Response != nil { - sc = result.dbrl.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - result.fn = client.getBackupSecurityPINRequestsObjectsNextResults - req, err := client.GetBackupSecurityPINRequestsObjectsPreparer(ctx, resourceGroupName, resourceGuardsName) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetBackupSecurityPINRequestsObjects", nil, "Failure preparing request") - return - } - - resp, err := client.GetBackupSecurityPINRequestsObjectsSender(req) - if err != nil { - result.dbrl.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetBackupSecurityPINRequestsObjects", resp, "Failure sending request") - return - } - - result.dbrl, err = client.GetBackupSecurityPINRequestsObjectsResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetBackupSecurityPINRequestsObjects", resp, "Failure responding to request") - return - } - if result.dbrl.hasNextLink() && result.dbrl.IsEmpty() { - err = result.NextWithContext(ctx) - return - } - - return -} - -// GetBackupSecurityPINRequestsObjectsPreparer prepares the GetBackupSecurityPINRequestsObjects request. -func (client ResourceGuardsClient) GetBackupSecurityPINRequestsObjectsPreparer(ctx context.Context, resourceGroupName string, resourceGuardsName string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "resourceGuardsName": autorest.Encode("path", resourceGuardsName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsGet(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/resourceGuards/{resourceGuardsName}/getBackupSecurityPINRequests", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// GetBackupSecurityPINRequestsObjectsSender sends the GetBackupSecurityPINRequestsObjects request. The method will close the -// http.Response Body if it receives an error. -func (client ResourceGuardsClient) GetBackupSecurityPINRequestsObjectsSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// GetBackupSecurityPINRequestsObjectsResponder handles the response to the GetBackupSecurityPINRequestsObjects request. The method always -// closes the http.Response Body. -func (client ResourceGuardsClient) GetBackupSecurityPINRequestsObjectsResponder(resp *http.Response) (result DppBaseResourceList, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// getBackupSecurityPINRequestsObjectsNextResults retrieves the next set of results, if any. -func (client ResourceGuardsClient) getBackupSecurityPINRequestsObjectsNextResults(ctx context.Context, lastResults DppBaseResourceList) (result DppBaseResourceList, err error) { - req, err := lastResults.dppBaseResourceListPreparer(ctx) - if err != nil { - return result, autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "getBackupSecurityPINRequestsObjectsNextResults", nil, "Failure preparing next results request") - } - if req == nil { - return - } - resp, err := client.GetBackupSecurityPINRequestsObjectsSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - return result, autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "getBackupSecurityPINRequestsObjectsNextResults", resp, "Failure sending next results request") - } - result, err = client.GetBackupSecurityPINRequestsObjectsResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "getBackupSecurityPINRequestsObjectsNextResults", resp, "Failure responding to next results request") - } - return -} - -// GetBackupSecurityPINRequestsObjectsComplete enumerates all values, automatically crossing page boundaries as required. -func (client ResourceGuardsClient) GetBackupSecurityPINRequestsObjectsComplete(ctx context.Context, resourceGroupName string, resourceGuardsName string) (result DppBaseResourceListIterator, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/ResourceGuardsClient.GetBackupSecurityPINRequestsObjects") - defer func() { - sc := -1 - if result.Response().Response.Response != nil { - sc = result.page.Response().Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - result.page, err = client.GetBackupSecurityPINRequestsObjects(ctx, resourceGroupName, resourceGuardsName) - return -} - -// GetDefaultBackupSecurityPINRequestsObject sends the get default backup security pin requests object request. -// Parameters: -// resourceGroupName - the name of the resource group where the backup vault is present. -func (client ResourceGuardsClient) GetDefaultBackupSecurityPINRequestsObject(ctx context.Context, resourceGroupName string, resourceGuardsName string, requestName string) (result DppBaseResource, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/ResourceGuardsClient.GetDefaultBackupSecurityPINRequestsObject") - defer func() { - sc := -1 - if result.Response.Response != nil { - sc = result.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - req, err := client.GetDefaultBackupSecurityPINRequestsObjectPreparer(ctx, resourceGroupName, resourceGuardsName, requestName) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetDefaultBackupSecurityPINRequestsObject", nil, "Failure preparing request") - return - } - - resp, err := client.GetDefaultBackupSecurityPINRequestsObjectSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetDefaultBackupSecurityPINRequestsObject", resp, "Failure sending request") - return - } - - result, err = client.GetDefaultBackupSecurityPINRequestsObjectResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetDefaultBackupSecurityPINRequestsObject", resp, "Failure responding to request") - return - } - - return -} - -// GetDefaultBackupSecurityPINRequestsObjectPreparer prepares the GetDefaultBackupSecurityPINRequestsObject request. -func (client ResourceGuardsClient) GetDefaultBackupSecurityPINRequestsObjectPreparer(ctx context.Context, resourceGroupName string, resourceGuardsName string, requestName string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "requestName": autorest.Encode("path", requestName), - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "resourceGuardsName": autorest.Encode("path", resourceGuardsName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsGet(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/resourceGuards/{resourceGuardsName}/getBackupSecurityPINRequests/{requestName}", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// GetDefaultBackupSecurityPINRequestsObjectSender sends the GetDefaultBackupSecurityPINRequestsObject request. The method will close the -// http.Response Body if it receives an error. -func (client ResourceGuardsClient) GetDefaultBackupSecurityPINRequestsObjectSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// GetDefaultBackupSecurityPINRequestsObjectResponder handles the response to the GetDefaultBackupSecurityPINRequestsObject request. The method always -// closes the http.Response Body. -func (client ResourceGuardsClient) GetDefaultBackupSecurityPINRequestsObjectResponder(resp *http.Response) (result DppBaseResource, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// GetDefaultDeleteProtectedItemRequestsObject sends the get default delete protected item requests object request. -// Parameters: -// resourceGroupName - the name of the resource group where the backup vault is present. -func (client ResourceGuardsClient) GetDefaultDeleteProtectedItemRequestsObject(ctx context.Context, resourceGroupName string, resourceGuardsName string, requestName string) (result DppBaseResource, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/ResourceGuardsClient.GetDefaultDeleteProtectedItemRequestsObject") - defer func() { - sc := -1 - if result.Response.Response != nil { - sc = result.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - req, err := client.GetDefaultDeleteProtectedItemRequestsObjectPreparer(ctx, resourceGroupName, resourceGuardsName, requestName) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetDefaultDeleteProtectedItemRequestsObject", nil, "Failure preparing request") - return - } - - resp, err := client.GetDefaultDeleteProtectedItemRequestsObjectSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetDefaultDeleteProtectedItemRequestsObject", resp, "Failure sending request") - return - } - - result, err = client.GetDefaultDeleteProtectedItemRequestsObjectResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetDefaultDeleteProtectedItemRequestsObject", resp, "Failure responding to request") - return - } - - return -} - -// GetDefaultDeleteProtectedItemRequestsObjectPreparer prepares the GetDefaultDeleteProtectedItemRequestsObject request. -func (client ResourceGuardsClient) GetDefaultDeleteProtectedItemRequestsObjectPreparer(ctx context.Context, resourceGroupName string, resourceGuardsName string, requestName string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "requestName": autorest.Encode("path", requestName), - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "resourceGuardsName": autorest.Encode("path", resourceGuardsName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsGet(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/resourceGuards/{resourceGuardsName}/deleteProtectedItemRequests/{requestName}", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// GetDefaultDeleteProtectedItemRequestsObjectSender sends the GetDefaultDeleteProtectedItemRequestsObject request. The method will close the -// http.Response Body if it receives an error. -func (client ResourceGuardsClient) GetDefaultDeleteProtectedItemRequestsObjectSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// GetDefaultDeleteProtectedItemRequestsObjectResponder handles the response to the GetDefaultDeleteProtectedItemRequestsObject request. The method always -// closes the http.Response Body. -func (client ResourceGuardsClient) GetDefaultDeleteProtectedItemRequestsObjectResponder(resp *http.Response) (result DppBaseResource, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// GetDefaultDeleteResourceGuardProxyRequestsObject sends the get default delete resource guard proxy requests object -// request. -// Parameters: -// resourceGroupName - the name of the resource group where the backup vault is present. -func (client ResourceGuardsClient) GetDefaultDeleteResourceGuardProxyRequestsObject(ctx context.Context, resourceGroupName string, resourceGuardsName string, requestName string) (result DppBaseResource, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/ResourceGuardsClient.GetDefaultDeleteResourceGuardProxyRequestsObject") - defer func() { - sc := -1 - if result.Response.Response != nil { - sc = result.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - req, err := client.GetDefaultDeleteResourceGuardProxyRequestsObjectPreparer(ctx, resourceGroupName, resourceGuardsName, requestName) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetDefaultDeleteResourceGuardProxyRequestsObject", nil, "Failure preparing request") - return - } - - resp, err := client.GetDefaultDeleteResourceGuardProxyRequestsObjectSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetDefaultDeleteResourceGuardProxyRequestsObject", resp, "Failure sending request") - return - } - - result, err = client.GetDefaultDeleteResourceGuardProxyRequestsObjectResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetDefaultDeleteResourceGuardProxyRequestsObject", resp, "Failure responding to request") - return - } - - return -} - -// GetDefaultDeleteResourceGuardProxyRequestsObjectPreparer prepares the GetDefaultDeleteResourceGuardProxyRequestsObject request. -func (client ResourceGuardsClient) GetDefaultDeleteResourceGuardProxyRequestsObjectPreparer(ctx context.Context, resourceGroupName string, resourceGuardsName string, requestName string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "requestName": autorest.Encode("path", requestName), - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "resourceGuardsName": autorest.Encode("path", resourceGuardsName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsGet(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/resourceGuards/{resourceGuardsName}/deleteResourceGuardProxyRequests/{requestName}", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// GetDefaultDeleteResourceGuardProxyRequestsObjectSender sends the GetDefaultDeleteResourceGuardProxyRequestsObject request. The method will close the -// http.Response Body if it receives an error. -func (client ResourceGuardsClient) GetDefaultDeleteResourceGuardProxyRequestsObjectSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// GetDefaultDeleteResourceGuardProxyRequestsObjectResponder handles the response to the GetDefaultDeleteResourceGuardProxyRequestsObject request. The method always -// closes the http.Response Body. -func (client ResourceGuardsClient) GetDefaultDeleteResourceGuardProxyRequestsObjectResponder(resp *http.Response) (result DppBaseResource, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// GetDefaultDisableSoftDeleteRequestsObject sends the get default disable soft delete requests object request. -// Parameters: -// resourceGroupName - the name of the resource group where the backup vault is present. -func (client ResourceGuardsClient) GetDefaultDisableSoftDeleteRequestsObject(ctx context.Context, resourceGroupName string, resourceGuardsName string, requestName string) (result DppBaseResource, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/ResourceGuardsClient.GetDefaultDisableSoftDeleteRequestsObject") - defer func() { - sc := -1 - if result.Response.Response != nil { - sc = result.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - req, err := client.GetDefaultDisableSoftDeleteRequestsObjectPreparer(ctx, resourceGroupName, resourceGuardsName, requestName) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetDefaultDisableSoftDeleteRequestsObject", nil, "Failure preparing request") - return - } - - resp, err := client.GetDefaultDisableSoftDeleteRequestsObjectSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetDefaultDisableSoftDeleteRequestsObject", resp, "Failure sending request") - return - } - - result, err = client.GetDefaultDisableSoftDeleteRequestsObjectResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetDefaultDisableSoftDeleteRequestsObject", resp, "Failure responding to request") - return - } - - return -} - -// GetDefaultDisableSoftDeleteRequestsObjectPreparer prepares the GetDefaultDisableSoftDeleteRequestsObject request. -func (client ResourceGuardsClient) GetDefaultDisableSoftDeleteRequestsObjectPreparer(ctx context.Context, resourceGroupName string, resourceGuardsName string, requestName string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "requestName": autorest.Encode("path", requestName), - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "resourceGuardsName": autorest.Encode("path", resourceGuardsName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsGet(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/resourceGuards/{resourceGuardsName}/disableSoftDeleteRequests/{requestName}", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// GetDefaultDisableSoftDeleteRequestsObjectSender sends the GetDefaultDisableSoftDeleteRequestsObject request. The method will close the -// http.Response Body if it receives an error. -func (client ResourceGuardsClient) GetDefaultDisableSoftDeleteRequestsObjectSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// GetDefaultDisableSoftDeleteRequestsObjectResponder handles the response to the GetDefaultDisableSoftDeleteRequestsObject request. The method always -// closes the http.Response Body. -func (client ResourceGuardsClient) GetDefaultDisableSoftDeleteRequestsObjectResponder(resp *http.Response) (result DppBaseResource, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// GetDefaultUpdateProtectedItemRequestsObject sends the get default update protected item requests object request. -// Parameters: -// resourceGroupName - the name of the resource group where the backup vault is present. -func (client ResourceGuardsClient) GetDefaultUpdateProtectedItemRequestsObject(ctx context.Context, resourceGroupName string, resourceGuardsName string, requestName string) (result DppBaseResource, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/ResourceGuardsClient.GetDefaultUpdateProtectedItemRequestsObject") - defer func() { - sc := -1 - if result.Response.Response != nil { - sc = result.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - req, err := client.GetDefaultUpdateProtectedItemRequestsObjectPreparer(ctx, resourceGroupName, resourceGuardsName, requestName) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetDefaultUpdateProtectedItemRequestsObject", nil, "Failure preparing request") - return - } - - resp, err := client.GetDefaultUpdateProtectedItemRequestsObjectSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetDefaultUpdateProtectedItemRequestsObject", resp, "Failure sending request") - return - } - - result, err = client.GetDefaultUpdateProtectedItemRequestsObjectResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetDefaultUpdateProtectedItemRequestsObject", resp, "Failure responding to request") - return - } - - return -} - -// GetDefaultUpdateProtectedItemRequestsObjectPreparer prepares the GetDefaultUpdateProtectedItemRequestsObject request. -func (client ResourceGuardsClient) GetDefaultUpdateProtectedItemRequestsObjectPreparer(ctx context.Context, resourceGroupName string, resourceGuardsName string, requestName string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "requestName": autorest.Encode("path", requestName), - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "resourceGuardsName": autorest.Encode("path", resourceGuardsName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsGet(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/resourceGuards/{resourceGuardsName}/updateProtectedItemRequests/{requestName}", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// GetDefaultUpdateProtectedItemRequestsObjectSender sends the GetDefaultUpdateProtectedItemRequestsObject request. The method will close the -// http.Response Body if it receives an error. -func (client ResourceGuardsClient) GetDefaultUpdateProtectedItemRequestsObjectSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// GetDefaultUpdateProtectedItemRequestsObjectResponder handles the response to the GetDefaultUpdateProtectedItemRequestsObject request. The method always -// closes the http.Response Body. -func (client ResourceGuardsClient) GetDefaultUpdateProtectedItemRequestsObjectResponder(resp *http.Response) (result DppBaseResource, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// GetDefaultUpdateProtectionPolicyRequestsObject sends the get default update protection policy requests object -// request. -// Parameters: -// resourceGroupName - the name of the resource group where the backup vault is present. -func (client ResourceGuardsClient) GetDefaultUpdateProtectionPolicyRequestsObject(ctx context.Context, resourceGroupName string, resourceGuardsName string, requestName string) (result DppBaseResource, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/ResourceGuardsClient.GetDefaultUpdateProtectionPolicyRequestsObject") - defer func() { - sc := -1 - if result.Response.Response != nil { - sc = result.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - req, err := client.GetDefaultUpdateProtectionPolicyRequestsObjectPreparer(ctx, resourceGroupName, resourceGuardsName, requestName) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetDefaultUpdateProtectionPolicyRequestsObject", nil, "Failure preparing request") - return - } - - resp, err := client.GetDefaultUpdateProtectionPolicyRequestsObjectSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetDefaultUpdateProtectionPolicyRequestsObject", resp, "Failure sending request") - return - } - - result, err = client.GetDefaultUpdateProtectionPolicyRequestsObjectResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetDefaultUpdateProtectionPolicyRequestsObject", resp, "Failure responding to request") - return - } - - return -} - -// GetDefaultUpdateProtectionPolicyRequestsObjectPreparer prepares the GetDefaultUpdateProtectionPolicyRequestsObject request. -func (client ResourceGuardsClient) GetDefaultUpdateProtectionPolicyRequestsObjectPreparer(ctx context.Context, resourceGroupName string, resourceGuardsName string, requestName string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "requestName": autorest.Encode("path", requestName), - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "resourceGuardsName": autorest.Encode("path", resourceGuardsName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsGet(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/resourceGuards/{resourceGuardsName}/updateProtectionPolicyRequests/{requestName}", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// GetDefaultUpdateProtectionPolicyRequestsObjectSender sends the GetDefaultUpdateProtectionPolicyRequestsObject request. The method will close the -// http.Response Body if it receives an error. -func (client ResourceGuardsClient) GetDefaultUpdateProtectionPolicyRequestsObjectSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// GetDefaultUpdateProtectionPolicyRequestsObjectResponder handles the response to the GetDefaultUpdateProtectionPolicyRequestsObject request. The method always -// closes the http.Response Body. -func (client ResourceGuardsClient) GetDefaultUpdateProtectionPolicyRequestsObjectResponder(resp *http.Response) (result DppBaseResource, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// GetDeleteProtectedItemRequestsObjects sends the get delete protected item requests objects request. -// Parameters: -// resourceGroupName - the name of the resource group where the backup vault is present. -func (client ResourceGuardsClient) GetDeleteProtectedItemRequestsObjects(ctx context.Context, resourceGroupName string, resourceGuardsName string) (result DppBaseResourceListPage, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/ResourceGuardsClient.GetDeleteProtectedItemRequestsObjects") - defer func() { - sc := -1 - if result.dbrl.Response.Response != nil { - sc = result.dbrl.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - result.fn = client.getDeleteProtectedItemRequestsObjectsNextResults - req, err := client.GetDeleteProtectedItemRequestsObjectsPreparer(ctx, resourceGroupName, resourceGuardsName) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetDeleteProtectedItemRequestsObjects", nil, "Failure preparing request") - return - } - - resp, err := client.GetDeleteProtectedItemRequestsObjectsSender(req) - if err != nil { - result.dbrl.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetDeleteProtectedItemRequestsObjects", resp, "Failure sending request") - return - } - - result.dbrl, err = client.GetDeleteProtectedItemRequestsObjectsResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetDeleteProtectedItemRequestsObjects", resp, "Failure responding to request") - return - } - if result.dbrl.hasNextLink() && result.dbrl.IsEmpty() { - err = result.NextWithContext(ctx) - return - } - - return -} - -// GetDeleteProtectedItemRequestsObjectsPreparer prepares the GetDeleteProtectedItemRequestsObjects request. -func (client ResourceGuardsClient) GetDeleteProtectedItemRequestsObjectsPreparer(ctx context.Context, resourceGroupName string, resourceGuardsName string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "resourceGuardsName": autorest.Encode("path", resourceGuardsName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsGet(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/resourceGuards/{resourceGuardsName}/deleteProtectedItemRequests", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// GetDeleteProtectedItemRequestsObjectsSender sends the GetDeleteProtectedItemRequestsObjects request. The method will close the -// http.Response Body if it receives an error. -func (client ResourceGuardsClient) GetDeleteProtectedItemRequestsObjectsSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// GetDeleteProtectedItemRequestsObjectsResponder handles the response to the GetDeleteProtectedItemRequestsObjects request. The method always -// closes the http.Response Body. -func (client ResourceGuardsClient) GetDeleteProtectedItemRequestsObjectsResponder(resp *http.Response) (result DppBaseResourceList, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// getDeleteProtectedItemRequestsObjectsNextResults retrieves the next set of results, if any. -func (client ResourceGuardsClient) getDeleteProtectedItemRequestsObjectsNextResults(ctx context.Context, lastResults DppBaseResourceList) (result DppBaseResourceList, err error) { - req, err := lastResults.dppBaseResourceListPreparer(ctx) - if err != nil { - return result, autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "getDeleteProtectedItemRequestsObjectsNextResults", nil, "Failure preparing next results request") - } - if req == nil { - return - } - resp, err := client.GetDeleteProtectedItemRequestsObjectsSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - return result, autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "getDeleteProtectedItemRequestsObjectsNextResults", resp, "Failure sending next results request") - } - result, err = client.GetDeleteProtectedItemRequestsObjectsResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "getDeleteProtectedItemRequestsObjectsNextResults", resp, "Failure responding to next results request") - } - return -} - -// GetDeleteProtectedItemRequestsObjectsComplete enumerates all values, automatically crossing page boundaries as required. -func (client ResourceGuardsClient) GetDeleteProtectedItemRequestsObjectsComplete(ctx context.Context, resourceGroupName string, resourceGuardsName string) (result DppBaseResourceListIterator, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/ResourceGuardsClient.GetDeleteProtectedItemRequestsObjects") - defer func() { - sc := -1 - if result.Response().Response.Response != nil { - sc = result.page.Response().Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - result.page, err = client.GetDeleteProtectedItemRequestsObjects(ctx, resourceGroupName, resourceGuardsName) - return -} - -// GetDeleteResourceGuardProxyRequestsObjects sends the get delete resource guard proxy requests objects request. -// Parameters: -// resourceGroupName - the name of the resource group where the backup vault is present. -func (client ResourceGuardsClient) GetDeleteResourceGuardProxyRequestsObjects(ctx context.Context, resourceGroupName string, resourceGuardsName string) (result DppBaseResourceListPage, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/ResourceGuardsClient.GetDeleteResourceGuardProxyRequestsObjects") - defer func() { - sc := -1 - if result.dbrl.Response.Response != nil { - sc = result.dbrl.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - result.fn = client.getDeleteResourceGuardProxyRequestsObjectsNextResults - req, err := client.GetDeleteResourceGuardProxyRequestsObjectsPreparer(ctx, resourceGroupName, resourceGuardsName) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetDeleteResourceGuardProxyRequestsObjects", nil, "Failure preparing request") - return - } - - resp, err := client.GetDeleteResourceGuardProxyRequestsObjectsSender(req) - if err != nil { - result.dbrl.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetDeleteResourceGuardProxyRequestsObjects", resp, "Failure sending request") - return - } - - result.dbrl, err = client.GetDeleteResourceGuardProxyRequestsObjectsResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetDeleteResourceGuardProxyRequestsObjects", resp, "Failure responding to request") - return - } - if result.dbrl.hasNextLink() && result.dbrl.IsEmpty() { - err = result.NextWithContext(ctx) - return - } - - return -} - -// GetDeleteResourceGuardProxyRequestsObjectsPreparer prepares the GetDeleteResourceGuardProxyRequestsObjects request. -func (client ResourceGuardsClient) GetDeleteResourceGuardProxyRequestsObjectsPreparer(ctx context.Context, resourceGroupName string, resourceGuardsName string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "resourceGuardsName": autorest.Encode("path", resourceGuardsName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsGet(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/resourceGuards/{resourceGuardsName}/deleteResourceGuardProxyRequests", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// GetDeleteResourceGuardProxyRequestsObjectsSender sends the GetDeleteResourceGuardProxyRequestsObjects request. The method will close the -// http.Response Body if it receives an error. -func (client ResourceGuardsClient) GetDeleteResourceGuardProxyRequestsObjectsSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// GetDeleteResourceGuardProxyRequestsObjectsResponder handles the response to the GetDeleteResourceGuardProxyRequestsObjects request. The method always -// closes the http.Response Body. -func (client ResourceGuardsClient) GetDeleteResourceGuardProxyRequestsObjectsResponder(resp *http.Response) (result DppBaseResourceList, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// getDeleteResourceGuardProxyRequestsObjectsNextResults retrieves the next set of results, if any. -func (client ResourceGuardsClient) getDeleteResourceGuardProxyRequestsObjectsNextResults(ctx context.Context, lastResults DppBaseResourceList) (result DppBaseResourceList, err error) { - req, err := lastResults.dppBaseResourceListPreparer(ctx) - if err != nil { - return result, autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "getDeleteResourceGuardProxyRequestsObjectsNextResults", nil, "Failure preparing next results request") - } - if req == nil { - return - } - resp, err := client.GetDeleteResourceGuardProxyRequestsObjectsSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - return result, autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "getDeleteResourceGuardProxyRequestsObjectsNextResults", resp, "Failure sending next results request") - } - result, err = client.GetDeleteResourceGuardProxyRequestsObjectsResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "getDeleteResourceGuardProxyRequestsObjectsNextResults", resp, "Failure responding to next results request") - } - return -} - -// GetDeleteResourceGuardProxyRequestsObjectsComplete enumerates all values, automatically crossing page boundaries as required. -func (client ResourceGuardsClient) GetDeleteResourceGuardProxyRequestsObjectsComplete(ctx context.Context, resourceGroupName string, resourceGuardsName string) (result DppBaseResourceListIterator, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/ResourceGuardsClient.GetDeleteResourceGuardProxyRequestsObjects") - defer func() { - sc := -1 - if result.Response().Response.Response != nil { - sc = result.page.Response().Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - result.page, err = client.GetDeleteResourceGuardProxyRequestsObjects(ctx, resourceGroupName, resourceGuardsName) - return -} - -// GetDisableSoftDeleteRequestsObjects sends the get disable soft delete requests objects request. -// Parameters: -// resourceGroupName - the name of the resource group where the backup vault is present. -func (client ResourceGuardsClient) GetDisableSoftDeleteRequestsObjects(ctx context.Context, resourceGroupName string, resourceGuardsName string) (result DppBaseResourceListPage, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/ResourceGuardsClient.GetDisableSoftDeleteRequestsObjects") - defer func() { - sc := -1 - if result.dbrl.Response.Response != nil { - sc = result.dbrl.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - result.fn = client.getDisableSoftDeleteRequestsObjectsNextResults - req, err := client.GetDisableSoftDeleteRequestsObjectsPreparer(ctx, resourceGroupName, resourceGuardsName) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetDisableSoftDeleteRequestsObjects", nil, "Failure preparing request") - return - } - - resp, err := client.GetDisableSoftDeleteRequestsObjectsSender(req) - if err != nil { - result.dbrl.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetDisableSoftDeleteRequestsObjects", resp, "Failure sending request") - return - } - - result.dbrl, err = client.GetDisableSoftDeleteRequestsObjectsResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetDisableSoftDeleteRequestsObjects", resp, "Failure responding to request") - return - } - if result.dbrl.hasNextLink() && result.dbrl.IsEmpty() { - err = result.NextWithContext(ctx) - return - } - - return -} - -// GetDisableSoftDeleteRequestsObjectsPreparer prepares the GetDisableSoftDeleteRequestsObjects request. -func (client ResourceGuardsClient) GetDisableSoftDeleteRequestsObjectsPreparer(ctx context.Context, resourceGroupName string, resourceGuardsName string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "resourceGuardsName": autorest.Encode("path", resourceGuardsName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsGet(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/resourceGuards/{resourceGuardsName}/disableSoftDeleteRequests", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// GetDisableSoftDeleteRequestsObjectsSender sends the GetDisableSoftDeleteRequestsObjects request. The method will close the -// http.Response Body if it receives an error. -func (client ResourceGuardsClient) GetDisableSoftDeleteRequestsObjectsSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// GetDisableSoftDeleteRequestsObjectsResponder handles the response to the GetDisableSoftDeleteRequestsObjects request. The method always -// closes the http.Response Body. -func (client ResourceGuardsClient) GetDisableSoftDeleteRequestsObjectsResponder(resp *http.Response) (result DppBaseResourceList, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// getDisableSoftDeleteRequestsObjectsNextResults retrieves the next set of results, if any. -func (client ResourceGuardsClient) getDisableSoftDeleteRequestsObjectsNextResults(ctx context.Context, lastResults DppBaseResourceList) (result DppBaseResourceList, err error) { - req, err := lastResults.dppBaseResourceListPreparer(ctx) - if err != nil { - return result, autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "getDisableSoftDeleteRequestsObjectsNextResults", nil, "Failure preparing next results request") - } - if req == nil { - return - } - resp, err := client.GetDisableSoftDeleteRequestsObjectsSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - return result, autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "getDisableSoftDeleteRequestsObjectsNextResults", resp, "Failure sending next results request") - } - result, err = client.GetDisableSoftDeleteRequestsObjectsResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "getDisableSoftDeleteRequestsObjectsNextResults", resp, "Failure responding to next results request") - } - return -} - -// GetDisableSoftDeleteRequestsObjectsComplete enumerates all values, automatically crossing page boundaries as required. -func (client ResourceGuardsClient) GetDisableSoftDeleteRequestsObjectsComplete(ctx context.Context, resourceGroupName string, resourceGuardsName string) (result DppBaseResourceListIterator, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/ResourceGuardsClient.GetDisableSoftDeleteRequestsObjects") - defer func() { - sc := -1 - if result.Response().Response.Response != nil { - sc = result.page.Response().Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - result.page, err = client.GetDisableSoftDeleteRequestsObjects(ctx, resourceGroupName, resourceGuardsName) - return -} - -// GetResourcesInResourceGroup sends the get resources in resource group request. -// Parameters: -// resourceGroupName - the name of the resource group where the backup vault is present. -func (client ResourceGuardsClient) GetResourcesInResourceGroup(ctx context.Context, resourceGroupName string) (result ResourceGuardResourceListPage, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/ResourceGuardsClient.GetResourcesInResourceGroup") - defer func() { - sc := -1 - if result.rgrl.Response.Response != nil { - sc = result.rgrl.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - result.fn = client.getResourcesInResourceGroupNextResults - req, err := client.GetResourcesInResourceGroupPreparer(ctx, resourceGroupName) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetResourcesInResourceGroup", nil, "Failure preparing request") - return - } - - resp, err := client.GetResourcesInResourceGroupSender(req) - if err != nil { - result.rgrl.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetResourcesInResourceGroup", resp, "Failure sending request") - return - } - - result.rgrl, err = client.GetResourcesInResourceGroupResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetResourcesInResourceGroup", resp, "Failure responding to request") - return - } - if result.rgrl.hasNextLink() && result.rgrl.IsEmpty() { - err = result.NextWithContext(ctx) - return - } - - return -} - -// GetResourcesInResourceGroupPreparer prepares the GetResourcesInResourceGroup request. -func (client ResourceGuardsClient) GetResourcesInResourceGroupPreparer(ctx context.Context, resourceGroupName string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsGet(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/resourceGuards", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// GetResourcesInResourceGroupSender sends the GetResourcesInResourceGroup request. The method will close the -// http.Response Body if it receives an error. -func (client ResourceGuardsClient) GetResourcesInResourceGroupSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// GetResourcesInResourceGroupResponder handles the response to the GetResourcesInResourceGroup request. The method always -// closes the http.Response Body. -func (client ResourceGuardsClient) GetResourcesInResourceGroupResponder(resp *http.Response) (result ResourceGuardResourceList, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// getResourcesInResourceGroupNextResults retrieves the next set of results, if any. -func (client ResourceGuardsClient) getResourcesInResourceGroupNextResults(ctx context.Context, lastResults ResourceGuardResourceList) (result ResourceGuardResourceList, err error) { - req, err := lastResults.resourceGuardResourceListPreparer(ctx) - if err != nil { - return result, autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "getResourcesInResourceGroupNextResults", nil, "Failure preparing next results request") - } - if req == nil { - return - } - resp, err := client.GetResourcesInResourceGroupSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - return result, autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "getResourcesInResourceGroupNextResults", resp, "Failure sending next results request") - } - result, err = client.GetResourcesInResourceGroupResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "getResourcesInResourceGroupNextResults", resp, "Failure responding to next results request") - } - return -} - -// GetResourcesInResourceGroupComplete enumerates all values, automatically crossing page boundaries as required. -func (client ResourceGuardsClient) GetResourcesInResourceGroupComplete(ctx context.Context, resourceGroupName string) (result ResourceGuardResourceListIterator, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/ResourceGuardsClient.GetResourcesInResourceGroup") - defer func() { - sc := -1 - if result.Response().Response.Response != nil { - sc = result.page.Response().Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - result.page, err = client.GetResourcesInResourceGroup(ctx, resourceGroupName) - return -} - -// GetResourcesInSubscription sends the get resources in subscription request. -func (client ResourceGuardsClient) GetResourcesInSubscription(ctx context.Context) (result ResourceGuardResourceListPage, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/ResourceGuardsClient.GetResourcesInSubscription") - defer func() { - sc := -1 - if result.rgrl.Response.Response != nil { - sc = result.rgrl.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - result.fn = client.getResourcesInSubscriptionNextResults - req, err := client.GetResourcesInSubscriptionPreparer(ctx) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetResourcesInSubscription", nil, "Failure preparing request") - return - } - - resp, err := client.GetResourcesInSubscriptionSender(req) - if err != nil { - result.rgrl.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetResourcesInSubscription", resp, "Failure sending request") - return - } - - result.rgrl, err = client.GetResourcesInSubscriptionResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetResourcesInSubscription", resp, "Failure responding to request") - return - } - if result.rgrl.hasNextLink() && result.rgrl.IsEmpty() { - err = result.NextWithContext(ctx) - return - } - - return -} - -// GetResourcesInSubscriptionPreparer prepares the GetResourcesInSubscription request. -func (client ResourceGuardsClient) GetResourcesInSubscriptionPreparer(ctx context.Context) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsGet(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/providers/Microsoft.DataProtection/resourceGuards", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// GetResourcesInSubscriptionSender sends the GetResourcesInSubscription request. The method will close the -// http.Response Body if it receives an error. -func (client ResourceGuardsClient) GetResourcesInSubscriptionSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// GetResourcesInSubscriptionResponder handles the response to the GetResourcesInSubscription request. The method always -// closes the http.Response Body. -func (client ResourceGuardsClient) GetResourcesInSubscriptionResponder(resp *http.Response) (result ResourceGuardResourceList, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// getResourcesInSubscriptionNextResults retrieves the next set of results, if any. -func (client ResourceGuardsClient) getResourcesInSubscriptionNextResults(ctx context.Context, lastResults ResourceGuardResourceList) (result ResourceGuardResourceList, err error) { - req, err := lastResults.resourceGuardResourceListPreparer(ctx) - if err != nil { - return result, autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "getResourcesInSubscriptionNextResults", nil, "Failure preparing next results request") - } - if req == nil { - return - } - resp, err := client.GetResourcesInSubscriptionSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - return result, autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "getResourcesInSubscriptionNextResults", resp, "Failure sending next results request") - } - result, err = client.GetResourcesInSubscriptionResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "getResourcesInSubscriptionNextResults", resp, "Failure responding to next results request") - } - return -} - -// GetResourcesInSubscriptionComplete enumerates all values, automatically crossing page boundaries as required. -func (client ResourceGuardsClient) GetResourcesInSubscriptionComplete(ctx context.Context) (result ResourceGuardResourceListIterator, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/ResourceGuardsClient.GetResourcesInSubscription") - defer func() { - sc := -1 - if result.Response().Response.Response != nil { - sc = result.page.Response().Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - result.page, err = client.GetResourcesInSubscription(ctx) - return -} - -// GetUpdateProtectedItemRequestsObjects sends the get update protected item requests objects request. -// Parameters: -// resourceGroupName - the name of the resource group where the backup vault is present. -func (client ResourceGuardsClient) GetUpdateProtectedItemRequestsObjects(ctx context.Context, resourceGroupName string, resourceGuardsName string) (result DppBaseResourceListPage, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/ResourceGuardsClient.GetUpdateProtectedItemRequestsObjects") - defer func() { - sc := -1 - if result.dbrl.Response.Response != nil { - sc = result.dbrl.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - result.fn = client.getUpdateProtectedItemRequestsObjectsNextResults - req, err := client.GetUpdateProtectedItemRequestsObjectsPreparer(ctx, resourceGroupName, resourceGuardsName) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetUpdateProtectedItemRequestsObjects", nil, "Failure preparing request") - return - } - - resp, err := client.GetUpdateProtectedItemRequestsObjectsSender(req) - if err != nil { - result.dbrl.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetUpdateProtectedItemRequestsObjects", resp, "Failure sending request") - return - } - - result.dbrl, err = client.GetUpdateProtectedItemRequestsObjectsResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetUpdateProtectedItemRequestsObjects", resp, "Failure responding to request") - return - } - if result.dbrl.hasNextLink() && result.dbrl.IsEmpty() { - err = result.NextWithContext(ctx) - return - } - - return -} - -// GetUpdateProtectedItemRequestsObjectsPreparer prepares the GetUpdateProtectedItemRequestsObjects request. -func (client ResourceGuardsClient) GetUpdateProtectedItemRequestsObjectsPreparer(ctx context.Context, resourceGroupName string, resourceGuardsName string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "resourceGuardsName": autorest.Encode("path", resourceGuardsName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsGet(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/resourceGuards/{resourceGuardsName}/updateProtectedItemRequests", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// GetUpdateProtectedItemRequestsObjectsSender sends the GetUpdateProtectedItemRequestsObjects request. The method will close the -// http.Response Body if it receives an error. -func (client ResourceGuardsClient) GetUpdateProtectedItemRequestsObjectsSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// GetUpdateProtectedItemRequestsObjectsResponder handles the response to the GetUpdateProtectedItemRequestsObjects request. The method always -// closes the http.Response Body. -func (client ResourceGuardsClient) GetUpdateProtectedItemRequestsObjectsResponder(resp *http.Response) (result DppBaseResourceList, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// getUpdateProtectedItemRequestsObjectsNextResults retrieves the next set of results, if any. -func (client ResourceGuardsClient) getUpdateProtectedItemRequestsObjectsNextResults(ctx context.Context, lastResults DppBaseResourceList) (result DppBaseResourceList, err error) { - req, err := lastResults.dppBaseResourceListPreparer(ctx) - if err != nil { - return result, autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "getUpdateProtectedItemRequestsObjectsNextResults", nil, "Failure preparing next results request") - } - if req == nil { - return - } - resp, err := client.GetUpdateProtectedItemRequestsObjectsSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - return result, autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "getUpdateProtectedItemRequestsObjectsNextResults", resp, "Failure sending next results request") - } - result, err = client.GetUpdateProtectedItemRequestsObjectsResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "getUpdateProtectedItemRequestsObjectsNextResults", resp, "Failure responding to next results request") - } - return -} - -// GetUpdateProtectedItemRequestsObjectsComplete enumerates all values, automatically crossing page boundaries as required. -func (client ResourceGuardsClient) GetUpdateProtectedItemRequestsObjectsComplete(ctx context.Context, resourceGroupName string, resourceGuardsName string) (result DppBaseResourceListIterator, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/ResourceGuardsClient.GetUpdateProtectedItemRequestsObjects") - defer func() { - sc := -1 - if result.Response().Response.Response != nil { - sc = result.page.Response().Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - result.page, err = client.GetUpdateProtectedItemRequestsObjects(ctx, resourceGroupName, resourceGuardsName) - return -} - -// GetUpdateProtectionPolicyRequestsObjects sends the get update protection policy requests objects request. -// Parameters: -// resourceGroupName - the name of the resource group where the backup vault is present. -func (client ResourceGuardsClient) GetUpdateProtectionPolicyRequestsObjects(ctx context.Context, resourceGroupName string, resourceGuardsName string) (result DppBaseResourceListPage, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/ResourceGuardsClient.GetUpdateProtectionPolicyRequestsObjects") - defer func() { - sc := -1 - if result.dbrl.Response.Response != nil { - sc = result.dbrl.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - result.fn = client.getUpdateProtectionPolicyRequestsObjectsNextResults - req, err := client.GetUpdateProtectionPolicyRequestsObjectsPreparer(ctx, resourceGroupName, resourceGuardsName) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetUpdateProtectionPolicyRequestsObjects", nil, "Failure preparing request") - return - } - - resp, err := client.GetUpdateProtectionPolicyRequestsObjectsSender(req) - if err != nil { - result.dbrl.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetUpdateProtectionPolicyRequestsObjects", resp, "Failure sending request") - return - } - - result.dbrl, err = client.GetUpdateProtectionPolicyRequestsObjectsResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "GetUpdateProtectionPolicyRequestsObjects", resp, "Failure responding to request") - return - } - if result.dbrl.hasNextLink() && result.dbrl.IsEmpty() { - err = result.NextWithContext(ctx) - return - } - - return -} - -// GetUpdateProtectionPolicyRequestsObjectsPreparer prepares the GetUpdateProtectionPolicyRequestsObjects request. -func (client ResourceGuardsClient) GetUpdateProtectionPolicyRequestsObjectsPreparer(ctx context.Context, resourceGroupName string, resourceGuardsName string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "resourceGuardsName": autorest.Encode("path", resourceGuardsName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsGet(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/resourceGuards/{resourceGuardsName}/updateProtectionPolicyRequests", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// GetUpdateProtectionPolicyRequestsObjectsSender sends the GetUpdateProtectionPolicyRequestsObjects request. The method will close the -// http.Response Body if it receives an error. -func (client ResourceGuardsClient) GetUpdateProtectionPolicyRequestsObjectsSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// GetUpdateProtectionPolicyRequestsObjectsResponder handles the response to the GetUpdateProtectionPolicyRequestsObjects request. The method always -// closes the http.Response Body. -func (client ResourceGuardsClient) GetUpdateProtectionPolicyRequestsObjectsResponder(resp *http.Response) (result DppBaseResourceList, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// getUpdateProtectionPolicyRequestsObjectsNextResults retrieves the next set of results, if any. -func (client ResourceGuardsClient) getUpdateProtectionPolicyRequestsObjectsNextResults(ctx context.Context, lastResults DppBaseResourceList) (result DppBaseResourceList, err error) { - req, err := lastResults.dppBaseResourceListPreparer(ctx) - if err != nil { - return result, autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "getUpdateProtectionPolicyRequestsObjectsNextResults", nil, "Failure preparing next results request") - } - if req == nil { - return - } - resp, err := client.GetUpdateProtectionPolicyRequestsObjectsSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - return result, autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "getUpdateProtectionPolicyRequestsObjectsNextResults", resp, "Failure sending next results request") - } - result, err = client.GetUpdateProtectionPolicyRequestsObjectsResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "getUpdateProtectionPolicyRequestsObjectsNextResults", resp, "Failure responding to next results request") - } - return -} - -// GetUpdateProtectionPolicyRequestsObjectsComplete enumerates all values, automatically crossing page boundaries as required. -func (client ResourceGuardsClient) GetUpdateProtectionPolicyRequestsObjectsComplete(ctx context.Context, resourceGroupName string, resourceGuardsName string) (result DppBaseResourceListIterator, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/ResourceGuardsClient.GetUpdateProtectionPolicyRequestsObjects") - defer func() { - sc := -1 - if result.Response().Response.Response != nil { - sc = result.page.Response().Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - result.page, err = client.GetUpdateProtectionPolicyRequestsObjects(ctx, resourceGroupName, resourceGuardsName) - return -} - -// Patch sends the patch request. -// Parameters: -// resourceGroupName - the name of the resource group where the backup vault is present. -// resourceGuardsName - the name of ResourceGuard -// parameters - request body for operation -func (client ResourceGuardsClient) Patch(ctx context.Context, resourceGroupName string, resourceGuardsName string, parameters PatchResourceRequestInput) (result ResourceGuardResource, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/ResourceGuardsClient.Patch") - defer func() { - sc := -1 - if result.Response.Response != nil { - sc = result.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - req, err := client.PatchPreparer(ctx, resourceGroupName, resourceGuardsName, parameters) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "Patch", nil, "Failure preparing request") - return - } - - resp, err := client.PatchSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "Patch", resp, "Failure sending request") - return - } - - result, err = client.PatchResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "Patch", resp, "Failure responding to request") - return - } - - return -} - -// PatchPreparer prepares the Patch request. -func (client ResourceGuardsClient) PatchPreparer(ctx context.Context, resourceGroupName string, resourceGuardsName string, parameters PatchResourceRequestInput) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "resourceGuardsName": autorest.Encode("path", resourceGuardsName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsContentType("application/json; charset=utf-8"), - autorest.AsPatch(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/resourceGuards/{resourceGuardsName}", pathParameters), - autorest.WithJSON(parameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// PatchSender sends the Patch request. The method will close the -// http.Response Body if it receives an error. -func (client ResourceGuardsClient) PatchSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// PatchResponder handles the response to the Patch request. The method always -// closes the http.Response Body. -func (client ResourceGuardsClient) PatchResponder(resp *http.Response) (result ResourceGuardResource, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// Put sends the put request. -// Parameters: -// resourceGroupName - the name of the resource group where the backup vault is present. -// resourceGuardsName - the name of ResourceGuard -// parameters - request body for operation -func (client ResourceGuardsClient) Put(ctx context.Context, resourceGroupName string, resourceGuardsName string, parameters ResourceGuardResource) (result ResourceGuardResource, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/ResourceGuardsClient.Put") - defer func() { - sc := -1 - if result.Response.Response != nil { - sc = result.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - req, err := client.PutPreparer(ctx, resourceGroupName, resourceGuardsName, parameters) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "Put", nil, "Failure preparing request") - return - } - - resp, err := client.PutSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "Put", resp, "Failure sending request") - return - } - - result, err = client.PutResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.ResourceGuardsClient", "Put", resp, "Failure responding to request") - return - } - - return -} - -// PutPreparer prepares the Put request. -func (client ResourceGuardsClient) PutPreparer(ctx context.Context, resourceGroupName string, resourceGuardsName string, parameters ResourceGuardResource) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "resourceGuardsName": autorest.Encode("path", resourceGuardsName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsContentType("application/json; charset=utf-8"), - autorest.AsPut(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/resourceGuards/{resourceGuardsName}", pathParameters), - autorest.WithJSON(parameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// PutSender sends the Put request. The method will close the -// http.Response Body if it receives an error. -func (client ResourceGuardsClient) PutSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// PutResponder handles the response to the Put request. The method always -// closes the http.Response Body. -func (client ResourceGuardsClient) PutResponder(resp *http.Response) (result ResourceGuardResource, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} diff --git a/internal/services/dataprotection/legacysdk/dataprotection/restorabletimeranges.go b/internal/services/dataprotection/legacysdk/dataprotection/restorabletimeranges.go deleted file mode 100644 index 4450de5f4e32..000000000000 --- a/internal/services/dataprotection/legacysdk/dataprotection/restorabletimeranges.go +++ /dev/null @@ -1,114 +0,0 @@ -package dataprotection - -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. -// -// Code generated by Microsoft (R) AutoRest Code Generator. -// Changes may cause incorrect behavior and will be lost if the code is regenerated. - -import ( - "context" - "net/http" - - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/azure" - "github.com/Azure/go-autorest/tracing" -) - -// RestorableTimeRangesClient is the open API 2.0 Specs for Azure Data Protection service -type RestorableTimeRangesClient struct { - BaseClient -} - -// NewRestorableTimeRangesClient creates an instance of the RestorableTimeRangesClient client. -func NewRestorableTimeRangesClient(subscriptionID string) RestorableTimeRangesClient { - return NewRestorableTimeRangesClientWithBaseURI(DefaultBaseURI, subscriptionID) -} - -// NewRestorableTimeRangesClientWithBaseURI creates an instance of the RestorableTimeRangesClient client using a custom -// endpoint. Use this when interacting with an Azure cloud that uses a non-standard base URI (sovereign clouds, Azure -// stack). -func NewRestorableTimeRangesClientWithBaseURI(baseURI string, subscriptionID string) RestorableTimeRangesClient { - return RestorableTimeRangesClient{NewWithBaseURI(baseURI, subscriptionID)} -} - -// Find sends the find request. -// Parameters: -// vaultName - the name of the backup vault. -// resourceGroupName - the name of the resource group where the backup vault is present. -// backupInstanceName - the name of the backup instance -// parameters - request body for operation -func (client RestorableTimeRangesClient) Find(ctx context.Context, vaultName string, resourceGroupName string, backupInstanceName string, parameters AzureBackupFindRestorableTimeRangesRequest) (result AzureBackupFindRestorableTimeRangesResponseResource, err error) { - if tracing.IsEnabled() { - ctx = tracing.StartSpan(ctx, fqdn+"/RestorableTimeRangesClient.Find") - defer func() { - sc := -1 - if result.Response.Response != nil { - sc = result.Response.Response.StatusCode - } - tracing.EndSpan(ctx, sc, err) - }() - } - req, err := client.FindPreparer(ctx, vaultName, resourceGroupName, backupInstanceName, parameters) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.RestorableTimeRangesClient", "Find", nil, "Failure preparing request") - return - } - - resp, err := client.FindSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "dataprotection.RestorableTimeRangesClient", "Find", resp, "Failure sending request") - return - } - - result, err = client.FindResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "dataprotection.RestorableTimeRangesClient", "Find", resp, "Failure responding to request") - return - } - - return -} - -// FindPreparer prepares the Find request. -func (client RestorableTimeRangesClient) FindPreparer(ctx context.Context, vaultName string, resourceGroupName string, backupInstanceName string, parameters AzureBackupFindRestorableTimeRangesRequest) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "backupInstanceName": autorest.Encode("path", backupInstanceName), - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - "vaultName": autorest.Encode("path", vaultName), - } - - const APIVersion = "2021-07-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsContentType("application/json; charset=utf-8"), - autorest.AsPost(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataProtection/backupVaults/{vaultName}/backupInstances/{backupInstanceName}/findRestorableTimeRanges", pathParameters), - autorest.WithJSON(parameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare((&http.Request{}).WithContext(ctx)) -} - -// FindSender sends the Find request. The method will close the -// http.Response Body if it receives an error. -func (client RestorableTimeRangesClient) FindSender(req *http.Request) (*http.Response, error) { - return client.Send(req, azure.DoRetryWithRegistration(client.Client)) -} - -// FindResponder handles the response to the Find request. The method always -// closes the http.Response Body. -func (client RestorableTimeRangesClient) FindResponder(resp *http.Response) (result AzureBackupFindRestorableTimeRangesResponseResource, err error) { - err = autorest.Respond( - resp, - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} diff --git a/internal/services/dataprotection/legacysdk/dataprotection/version.go b/internal/services/dataprotection/legacysdk/dataprotection/version.go deleted file mode 100644 index ca2052fa9faa..000000000000 --- a/internal/services/dataprotection/legacysdk/dataprotection/version.go +++ /dev/null @@ -1,19 +0,0 @@ -package dataprotection - -import "github.com/Azure/azure-sdk-for-go/version" - -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. -// -// Code generated by Microsoft (R) AutoRest Code Generator. -// Changes may cause incorrect behavior and will be lost if the code is regenerated. - -// UserAgent returns the UserAgent string to use when sending http.Requests. -func UserAgent() string { - return "Azure-SDK-For-Go/" + Version() + " dataprotection/2021-07-01" -} - -// Version returns the semantic version (see http://semver.org) of the client. -func Version() string { - return version.Number -} diff --git a/internal/services/dataprotection/parse/backup_instance.go b/internal/services/dataprotection/parse/backup_instance.go deleted file mode 100644 index f257a1a68b91..000000000000 --- a/internal/services/dataprotection/parse/backup_instance.go +++ /dev/null @@ -1,75 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - "strings" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -type BackupInstanceId struct { - SubscriptionId string - ResourceGroup string - BackupVaultName string - Name string -} - -func NewBackupInstanceID(subscriptionId, resourceGroup, backupVaultName, name string) BackupInstanceId { - return BackupInstanceId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourceGroup, - BackupVaultName: backupVaultName, - Name: name, - } -} - -func (id BackupInstanceId) String() string { - segments := []string{ - fmt.Sprintf("Name %q", id.Name), - fmt.Sprintf("Backup Vault Name %q", id.BackupVaultName), - fmt.Sprintf("Resource Group %q", id.ResourceGroup), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Backup Instance", segmentsStr) -} - -func (id BackupInstanceId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.DataProtection/backupVaults/%s/backupInstances/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.BackupVaultName, id.Name) -} - -// BackupInstanceID parses a BackupInstance ID into an BackupInstanceId struct -func BackupInstanceID(input string) (*BackupInstanceId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := BackupInstanceId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - if resourceId.BackupVaultName, err = id.PopSegment("backupVaults"); err != nil { - return nil, err - } - if resourceId.Name, err = id.PopSegment("backupInstances"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/dataprotection/parse/backup_instance_test.go b/internal/services/dataprotection/parse/backup_instance_test.go deleted file mode 100644 index a8575d6214f8..000000000000 --- a/internal/services/dataprotection/parse/backup_instance_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "testing" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -var _ resourceids.Id = BackupInstanceId{} - -func TestBackupInstanceIDFormatter(t *testing.T) { - actual := NewBackupInstanceID("12345678-1234-9876-4563-123456789012", "resourceGroup1", "vault1", "backupInstance1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.DataProtection/backupVaults/vault1/backupInstances/backupInstance1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestBackupInstanceID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *BackupInstanceId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - - { - // missing BackupVaultName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.DataProtection/", - Error: true, - }, - - { - // missing value for BackupVaultName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.DataProtection/backupVaults/", - Error: true, - }, - - { - // missing Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.DataProtection/backupVaults/vault1/", - Error: true, - }, - - { - // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.DataProtection/backupVaults/vault1/backupInstances/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.DataProtection/backupVaults/vault1/backupInstances/backupInstance1", - Expected: &BackupInstanceId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resourceGroup1", - BackupVaultName: "vault1", - Name: "backupInstance1", - }, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESOURCEGROUP1/PROVIDERS/MICROSOFT.DATAPROTECTION/BACKUPVAULTS/VAULT1/BACKUPINSTANCES/BACKUPINSTANCE1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := BackupInstanceID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - if actual.BackupVaultName != v.Expected.BackupVaultName { - t.Fatalf("Expected %q but got %q for BackupVaultName", v.Expected.BackupVaultName, actual.BackupVaultName) - } - if actual.Name != v.Expected.Name { - t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name) - } - } -} diff --git a/internal/services/dataprotection/parse/backup_policy.go b/internal/services/dataprotection/parse/backup_policy.go deleted file mode 100644 index 284f7e1e0f83..000000000000 --- a/internal/services/dataprotection/parse/backup_policy.go +++ /dev/null @@ -1,75 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - "strings" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -type BackupPolicyId struct { - SubscriptionId string - ResourceGroup string - BackupVaultName string - Name string -} - -func NewBackupPolicyID(subscriptionId, resourceGroup, backupVaultName, name string) BackupPolicyId { - return BackupPolicyId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourceGroup, - BackupVaultName: backupVaultName, - Name: name, - } -} - -func (id BackupPolicyId) String() string { - segments := []string{ - fmt.Sprintf("Name %q", id.Name), - fmt.Sprintf("Backup Vault Name %q", id.BackupVaultName), - fmt.Sprintf("Resource Group %q", id.ResourceGroup), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Backup Policy", segmentsStr) -} - -func (id BackupPolicyId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.DataProtection/backupVaults/%s/backupPolicies/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.BackupVaultName, id.Name) -} - -// BackupPolicyID parses a BackupPolicy ID into an BackupPolicyId struct -func BackupPolicyID(input string) (*BackupPolicyId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := BackupPolicyId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - if resourceId.BackupVaultName, err = id.PopSegment("backupVaults"); err != nil { - return nil, err - } - if resourceId.Name, err = id.PopSegment("backupPolicies"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/dataprotection/parse/backup_policy_test.go b/internal/services/dataprotection/parse/backup_policy_test.go deleted file mode 100644 index 3c094fb4cc74..000000000000 --- a/internal/services/dataprotection/parse/backup_policy_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "testing" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -var _ resourceids.Id = BackupPolicyId{} - -func TestBackupPolicyIDFormatter(t *testing.T) { - actual := NewBackupPolicyID("12345678-1234-9876-4563-123456789012", "resourceGroup1", "vault1", "backupPolicy1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.DataProtection/backupVaults/vault1/backupPolicies/backupPolicy1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestBackupPolicyID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *BackupPolicyId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - - { - // missing BackupVaultName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.DataProtection/", - Error: true, - }, - - { - // missing value for BackupVaultName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.DataProtection/backupVaults/", - Error: true, - }, - - { - // missing Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.DataProtection/backupVaults/vault1/", - Error: true, - }, - - { - // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.DataProtection/backupVaults/vault1/backupPolicies/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.DataProtection/backupVaults/vault1/backupPolicies/backupPolicy1", - Expected: &BackupPolicyId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resourceGroup1", - BackupVaultName: "vault1", - Name: "backupPolicy1", - }, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESOURCEGROUP1/PROVIDERS/MICROSOFT.DATAPROTECTION/BACKUPVAULTS/VAULT1/BACKUPPOLICIES/BACKUPPOLICY1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := BackupPolicyID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - if actual.BackupVaultName != v.Expected.BackupVaultName { - t.Fatalf("Expected %q but got %q for BackupVaultName", v.Expected.BackupVaultName, actual.BackupVaultName) - } - if actual.Name != v.Expected.Name { - t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name) - } - } -} diff --git a/internal/services/dataprotection/resourceids.go b/internal/services/dataprotection/resourceids.go deleted file mode 100644 index 08d621225861..000000000000 --- a/internal/services/dataprotection/resourceids.go +++ /dev/null @@ -1,5 +0,0 @@ -package dataprotection - -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=BackupVault -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.DataProtection/backupVaults/vault1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=BackupPolicy -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.DataProtection/backupVaults/vault1/backupPolicies/backupPolicy1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=BackupInstance -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.DataProtection/backupVaults/vault1/backupInstances/backupInstance1 diff --git a/internal/services/dataprotection/transition.go b/internal/services/dataprotection/transition.go new file mode 100644 index 000000000000..f28fff4beb98 --- /dev/null +++ b/internal/services/dataprotection/transition.go @@ -0,0 +1,23 @@ +package dataprotection + +import "github.com/hashicorp/terraform-provider-azurerm/utils" + +func expandTags(input map[string]interface{}) *map[string]string { + output := make(map[string]string) + for k, v := range input { + output[k] = v.(string) + } + return &output +} + +func flattenTags(input *map[string]string) map[string]*string { + output := make(map[string]*string) + + if input != nil { + for k, v := range *input { + output[k] = utils.String(v) + } + } + + return output +} diff --git a/internal/services/dataprotection/validate/backup_instance_id.go b/internal/services/dataprotection/validate/backup_instance_id.go deleted file mode 100644 index 52a66795d026..000000000000 --- a/internal/services/dataprotection/validate/backup_instance_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dataprotection/parse" -) - -func BackupInstanceID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.BackupInstanceID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/dataprotection/validate/backup_instance_id_test.go b/internal/services/dataprotection/validate/backup_instance_id_test.go deleted file mode 100644 index 198efb5bd556..000000000000 --- a/internal/services/dataprotection/validate/backup_instance_id_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestBackupInstanceID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - - { - // empty - Input: "", - Valid: false, - }, - - { - // missing SubscriptionId - Input: "/", - Valid: false, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Valid: false, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Valid: false, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Valid: false, - }, - - { - // missing BackupVaultName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.DataProtection/", - Valid: false, - }, - - { - // missing value for BackupVaultName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.DataProtection/backupVaults/", - Valid: false, - }, - - { - // missing Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.DataProtection/backupVaults/vault1/", - Valid: false, - }, - - { - // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.DataProtection/backupVaults/vault1/backupInstances/", - Valid: false, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.DataProtection/backupVaults/vault1/backupInstances/backupInstance1", - Valid: true, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESOURCEGROUP1/PROVIDERS/MICROSOFT.DATAPROTECTION/BACKUPVAULTS/VAULT1/BACKUPINSTANCES/BACKUPINSTANCE1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := BackupInstanceID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/dataprotection/validate/backup_policy_id.go b/internal/services/dataprotection/validate/backup_policy_id.go deleted file mode 100644 index 31b35c392b36..000000000000 --- a/internal/services/dataprotection/validate/backup_policy_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dataprotection/parse" -) - -func BackupPolicyID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.BackupPolicyID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/dataprotection/validate/backup_policy_id_test.go b/internal/services/dataprotection/validate/backup_policy_id_test.go deleted file mode 100644 index 33353158919c..000000000000 --- a/internal/services/dataprotection/validate/backup_policy_id_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestBackupPolicyID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - - { - // empty - Input: "", - Valid: false, - }, - - { - // missing SubscriptionId - Input: "/", - Valid: false, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Valid: false, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Valid: false, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Valid: false, - }, - - { - // missing BackupVaultName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.DataProtection/", - Valid: false, - }, - - { - // missing value for BackupVaultName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.DataProtection/backupVaults/", - Valid: false, - }, - - { - // missing Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.DataProtection/backupVaults/vault1/", - Valid: false, - }, - - { - // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.DataProtection/backupVaults/vault1/backupPolicies/", - Valid: false, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.DataProtection/backupVaults/vault1/backupPolicies/backupPolicy1", - Valid: true, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESOURCEGROUP1/PROVIDERS/MICROSOFT.DATAPROTECTION/BACKUPVAULTS/VAULT1/BACKUPPOLICIES/BACKUPPOLICY1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := BackupPolicyID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/dataprotection/validate/backup_vault_id.go b/internal/services/dataprotection/validate/backup_vault_id.go deleted file mode 100644 index 0e7c5a727f11..000000000000 --- a/internal/services/dataprotection/validate/backup_vault_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dataprotection/parse" -) - -func BackupVaultID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.BackupVaultID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/dataprotection/validate/backup_vault_id_test.go b/internal/services/dataprotection/validate/backup_vault_id_test.go deleted file mode 100644 index aa463cc3f948..000000000000 --- a/internal/services/dataprotection/validate/backup_vault_id_test.go +++ /dev/null @@ -1,76 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestBackupVaultID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - - { - // empty - Input: "", - Valid: false, - }, - - { - // missing SubscriptionId - Input: "/", - Valid: false, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Valid: false, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Valid: false, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Valid: false, - }, - - { - // missing Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.DataProtection/", - Valid: false, - }, - - { - // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.DataProtection/backupVaults/", - Valid: false, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.DataProtection/backupVaults/vault1", - Valid: true, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESOURCEGROUP1/PROVIDERS/MICROSOFT.DATAPROTECTION/BACKUPVAULTS/VAULT1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := BackupVaultID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/disks/disk_pool_iscsi_target_lun_resource_test.go b/internal/services/disks/disk_pool_iscsi_target_lun_resource_test.go index 3f5527a027ec..90b12d8793ce 100644 --- a/internal/services/disks/disk_pool_iscsi_target_lun_resource_test.go +++ b/internal/services/disks/disk_pool_iscsi_target_lun_resource_test.go @@ -217,9 +217,9 @@ func (r DisksPoolIscsiTargetLunResource) multipleLuns(data acceptance.TestData, %[1]s resource "azurerm_disk_pool_iscsi_target_lun" "test%[2]d" { - iscsi_target_id = azurerm_disk_pool_iscsi_target.test.id + iscsi_target_id = azurerm_disk_pool_iscsi_target.test.id disk_pool_managed_disk_attachment_id = azurerm_disk_pool_managed_disk_attachment.test[%[2]d].id - name = "test-%[2]d" + name = "test-%[2]d" } `, tfCode, i) } diff --git a/internal/services/dns/client/client.go b/internal/services/dns/client/client.go index d1dc5bea72b8..0f34c6a66b83 100644 --- a/internal/services/dns/client/client.go +++ b/internal/services/dns/client/client.go @@ -1,24 +1,14 @@ package client import ( - "github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2018-05-01/dns" + "github.com/Azure/go-autorest/autorest" + dns_v2018_05_01 "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01" "github.com/hashicorp/terraform-provider-azurerm/internal/common" ) -type Client struct { - RecordSetsClient *dns.RecordSetsClient - ZonesClient *dns.ZonesClient -} - -func NewClient(o *common.ClientOptions) *Client { - RecordSetsClient := dns.NewRecordSetsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) - o.ConfigureClient(&RecordSetsClient.Client, o.ResourceManagerAuthorizer) - - ZonesClient := dns.NewZonesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) - o.ConfigureClient(&ZonesClient.Client, o.ResourceManagerAuthorizer) - - return &Client{ - RecordSetsClient: &RecordSetsClient, - ZonesClient: &ZonesClient, - } +func NewClient(o *common.ClientOptions) *dns_v2018_05_01.Client { + client := dns_v2018_05_01.NewClientWithBaseURI(o.ResourceManagerEndpoint, func(c *autorest.Client) { + c.Authorizer = o.ResourceManagerAuthorizer + }) + return &client } diff --git a/internal/services/dns/dns_a_record_data_source.go b/internal/services/dns/dns_a_record_data_source.go new file mode 100644 index 000000000000..097da3483707 --- /dev/null +++ b/internal/services/dns/dns_a_record_data_source.go @@ -0,0 +1,106 @@ +package dns + +import ( + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" +) + +func dataSourceDnsARecord() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Read: dataSourceDnsARecordRead, + + Timeouts: &pluginsdk.ResourceTimeout{ + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "resource_group_name": commonschema.ResourceGroupNameForDataSource(), + + "zone_name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "records": { + Type: pluginsdk.TypeSet, + Computed: true, + Elem: &pluginsdk.Schema{Type: pluginsdk.TypeString}, + Set: pluginsdk.HashString, + }, + + "ttl": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "fqdn": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "target_resource_id": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "tags": commonschema.TagsDataSource(), + }, + } +} + +func dataSourceDnsARecordRead(d *pluginsdk.ResourceData, meta interface{}) error { + recordSetsClient := meta.(*clients.Client).Dns.RecordSets + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + + id := recordsets.NewRecordTypeID(subscriptionId, d.Get("resource_group_name").(string), d.Get("zone_name").(string), recordsets.RecordTypeA, d.Get("name").(string)) + + resp, err := recordSetsClient.Get(ctx, id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return fmt.Errorf("%s was not found", id) + } + return fmt.Errorf("reading %s: %+v", id, err) + } + + d.SetId(id.ID()) + + d.Set("name", id.RelativeRecordSetName) + d.Set("resource_group_name", id.ResourceGroupName) + d.Set("zone_name", id.ZoneName) + + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("ttl", props.TTL) + d.Set("fqdn", props.Fqdn) + + if err := d.Set("records", flattenAzureRmDnsARecords(props.ARecords)); err != nil { + return fmt.Errorf("setting `records`: %+v", err) + } + + targetResourceId := "" + if props.TargetResource != nil && props.TargetResource.Id != nil { + targetResourceId = *props.TargetResource.Id + } + d.Set("target_resource_id", targetResourceId) + + return tags.FlattenAndSet(d, props.Metadata) + } + } + + return nil +} diff --git a/internal/services/dns/dns_a_record_data_source_test.go b/internal/services/dns/dns_a_record_data_source_test.go new file mode 100644 index 000000000000..26f2d0631c37 --- /dev/null +++ b/internal/services/dns/dns_a_record_data_source_test.go @@ -0,0 +1,44 @@ +package dns_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" +) + +type TestAccDnsARecordDataSource struct{} + +func TestAccDataSourceDnsARecord_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_dns_a_record", "test") + r := TestAccDnsARecordDataSource{} + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("name").Exists(), + check.That(data.ResourceName).Key("resource_group_name").Exists(), + check.That(data.ResourceName).Key("zone_name").Exists(), + check.That(data.ResourceName).Key("records.#").HasValue("2"), + check.That(data.ResourceName).Key("ttl").Exists(), + check.That(data.ResourceName).Key("fqdn").Exists(), + check.That(data.ResourceName).Key("tags.%").HasValue("0"), + check.That(data.ResourceName).Key("target_resource_id").HasValue(""), + ), + }, + }) +} + +func (TestAccDnsARecordDataSource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +data "azurerm_dns_a_record" "test" { + name = azurerm_dns_a_record.test.name + resource_group_name = azurerm_resource_group.test.name + zone_name = azurerm_dns_zone.test.name +} +`, TestAccDnsARecordResource{}.basic(data)) +} diff --git a/internal/services/dns/dns_a_record_resource.go b/internal/services/dns/dns_a_record_resource.go index 12b55baeaff8..de9bf144acb3 100644 --- a/internal/services/dns/dns_a_record_resource.go +++ b/internal/services/dns/dns_a_record_resource.go @@ -2,15 +2,15 @@ package dns import ( "fmt" - "net/http" "time" - "github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2018-05-01/dns" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/parse" - "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" "github.com/hashicorp/terraform-provider-azurerm/utils" @@ -30,8 +30,14 @@ func resourceDnsARecord() *pluginsdk.Resource { Delete: pluginsdk.DefaultTimeout(30 * time.Minute), }, Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - _, err := parse.ARecordID(id) - return err + parsed, err := recordsets.ParseRecordTypeID(id) + if err != nil { + return err + } + if parsed.RecordType != recordsets.RecordTypeA { + return fmt.Errorf("this resource only supports 'A' records") + } + return nil }), Schema: map[string]*pluginsdk.Schema{ @@ -41,11 +47,12 @@ func resourceDnsARecord() *pluginsdk.Resource { ForceNew: true, }, - "resource_group_name": azure.SchemaResourceGroupName(), + "resource_group_name": commonschema.ResourceGroupName(), "zone_name": { Type: pluginsdk.TypeString, Required: true, + ForceNew: true, }, "records": { @@ -75,13 +82,13 @@ func resourceDnsARecord() *pluginsdk.Resource { // TODO: switch ConflictsWith for ExactlyOneOf when the Provider SDK's updated }, - "tags": tags.Schema(), + "tags": commonschema.Tags(), }, } } func resourceDnsARecordCreateUpdate(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Dns.RecordSetsClient + client := meta.(*clients.Client).Dns.RecordSets ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) subscriptionId := meta.(*clients.Client).Account.SubscriptionId defer cancel() @@ -90,18 +97,17 @@ func resourceDnsARecordCreateUpdate(d *pluginsdk.ResourceData, meta interface{}) resGroup := d.Get("resource_group_name").(string) zoneName := d.Get("zone_name").(string) - resourceId := parse.NewARecordID(subscriptionId, resGroup, zoneName, name) - + id := recordsets.NewRecordTypeID(subscriptionId, resGroup, zoneName, recordsets.RecordTypeA, name) if d.IsNewResource() { - existing, err := client.Get(ctx, resGroup, zoneName, name, dns.A) + existing, err := client.Get(ctx, id) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { - return fmt.Errorf("checking for presence of existing DNS A Record %q (Zone %q / Resource Group %q): %s", name, zoneName, resGroup, err) + if !response.WasNotFound(existing.HttpResponse) { + return fmt.Errorf("checking for presence of existing %s: %+v", id, err) } } - if !utils.ResponseWasNotFound(existing.Response) { - return tf.ImportAsExistsError("azurerm_dns_a_record", resourceId.ID()) + if !response.WasNotFound(existing.HttpResponse) { + return tf.ImportAsExistsError("azurerm_dns_a_record", id.ID()) } } @@ -110,18 +116,18 @@ func resourceDnsARecordCreateUpdate(d *pluginsdk.ResourceData, meta interface{}) targetResourceId := d.Get("target_resource_id").(string) recordsRaw := d.Get("records").(*pluginsdk.Set).List() - parameters := dns.RecordSet{ + parameters := recordsets.RecordSet{ Name: &name, - RecordSetProperties: &dns.RecordSetProperties{ + Properties: &recordsets.RecordSetProperties{ Metadata: tags.Expand(t), TTL: &ttl, ARecords: expandAzureRmDnsARecords(recordsRaw), - TargetResource: &dns.SubResource{}, + TargetResource: &recordsets.SubResource{}, }, } if targetResourceId != "" { - parameters.RecordSetProperties.TargetResource.ID = utils.String(targetResourceId) + parameters.Properties.TargetResource.Id = utils.String(targetResourceId) } // TODO: this can be removed when the provider SDK is upgraded @@ -129,99 +135,105 @@ func resourceDnsARecordCreateUpdate(d *pluginsdk.ResourceData, meta interface{}) return fmt.Errorf("One of either `records` or `target_resource_id` must be specified") } - eTag := "" - ifNoneMatch := "" // set to empty to allow updates to records after creation - if _, err := client.CreateOrUpdate(ctx, resGroup, zoneName, name, dns.A, parameters, eTag, ifNoneMatch); err != nil { + if _, err := client.CreateOrUpdate(ctx, id, parameters, recordsets.DefaultCreateOrUpdateOperationOptions()); err != nil { return fmt.Errorf("creating/updating DNS A Record %q (Zone %q / Resource Group %q): %s", name, zoneName, resGroup, err) } - d.SetId(resourceId.ID()) + d.SetId(id.ID()) return resourceDnsARecordRead(d, meta) } func resourceDnsARecordRead(d *pluginsdk.ResourceData, meta interface{}) error { - dnsClient := meta.(*clients.Client).Dns.RecordSetsClient + client := meta.(*clients.Client).Dns.RecordSets ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.ARecordID(d.Id()) + id, err := recordsets.ParseRecordTypeIDInsensitively(d.Id()) if err != nil { return err } - resp, err := dnsClient.Get(ctx, id.ResourceGroup, id.DnszoneName, id.AName, dns.A) + resp, err := client.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { d.SetId("") return nil } - return fmt.Errorf("reading DNS A record %s: %+v", id.AName, err) + return fmt.Errorf("retrieving %s: %+v", *id, err) } - d.Set("name", id.AName) - d.Set("resource_group_name", id.ResourceGroup) - d.Set("zone_name", id.DnszoneName) + d.Set("name", id.RelativeRecordSetName) + d.Set("resource_group_name", id.ResourceGroupName) + d.Set("zone_name", id.ZoneName) - d.Set("fqdn", resp.Fqdn) - d.Set("ttl", resp.TTL) + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("fqdn", props.Fqdn) + d.Set("ttl", props.TTL) - if err := d.Set("records", flattenAzureRmDnsARecords(resp.ARecords)); err != nil { - return fmt.Errorf("setting `records`: %+v", err) - } + if err := d.Set("records", flattenAzureRmDnsARecords(props.ARecords)); err != nil { + return fmt.Errorf("setting `records`: %+v", err) + } + + targetResourceId := "" + if props.TargetResource != nil && props.TargetResource.Id != nil { + targetResourceId = *props.TargetResource.Id + } + d.Set("target_resource_id", targetResourceId) + + if err := tags.FlattenAndSet(d, props.Metadata); err != nil { + return err + } + } - targetResourceId := "" - if resp.TargetResource != nil && resp.TargetResource.ID != nil { - targetResourceId = *resp.TargetResource.ID } - d.Set("target_resource_id", targetResourceId) - return tags.FlattenAndSet(d, resp.Metadata) + return nil } func resourceDnsARecordDelete(d *pluginsdk.ResourceData, meta interface{}) error { - dnsClient := meta.(*clients.Client).Dns.RecordSetsClient + client := meta.(*clients.Client).Dns.RecordSets ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.ARecordID(d.Id()) + id, err := recordsets.ParseRecordTypeID(d.Id()) if err != nil { return err } - resp, err := dnsClient.Delete(ctx, id.ResourceGroup, id.DnszoneName, id.AName, dns.A, "") - if resp.StatusCode != http.StatusOK { - return fmt.Errorf("deleting DNS A Record %s: %+v", id.AName, err) + if _, err := client.Delete(ctx, *id, recordsets.DefaultDeleteOperationOptions()); err != nil { + return fmt.Errorf("deleting %s: %+v", *id, err) } return nil } -func expandAzureRmDnsARecords(input []interface{}) *[]dns.ARecord { - records := make([]dns.ARecord, len(input)) +func expandAzureRmDnsARecords(input []interface{}) *[]recordsets.ARecord { + records := make([]recordsets.ARecord, len(input)) for i, v := range input { ipv4 := v.(string) - records[i] = dns.ARecord{ - Ipv4Address: &ipv4, + records[i] = recordsets.ARecord{ + IPv4Address: &ipv4, } } return &records } -func flattenAzureRmDnsARecords(records *[]dns.ARecord) []string { +func flattenAzureRmDnsARecords(records *[]recordsets.ARecord) []string { if records == nil { return []string{} } results := make([]string, 0) for _, record := range *records { - if record.Ipv4Address == nil { + if record.IPv4Address == nil { continue } - results = append(results, *record.Ipv4Address) + results = append(results, *record.IPv4Address) } return results diff --git a/internal/services/dns/dns_a_record_resource_test.go b/internal/services/dns/dns_a_record_resource_test.go index 56ac43d8ab7a..f6a7bafa402c 100644 --- a/internal/services/dns/dns_a_record_resource_test.go +++ b/internal/services/dns/dns_a_record_resource_test.go @@ -5,11 +5,10 @@ import ( "fmt" "testing" - "github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2018-05-01/dns" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -171,17 +170,17 @@ func TestAccAzureRMDnsARecord_AliasToRecords(t *testing.T) { } func (TestAccDnsARecordResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.ARecordID(state.ID) + id, err := recordsets.ParseRecordTypeID(state.ID) if err != nil { return nil, err } - resp, err := clients.Dns.RecordSetsClient.Get(ctx, id.ResourceGroup, id.DnszoneName, id.AName, dns.A) + resp, err := clients.Dns.RecordSets.Get(ctx, *id) if err != nil { - return nil, fmt.Errorf("retrieving DNS A record %s (resource group: %s): %v", id.AName, id.ResourceGroup, err) + return nil, fmt.Errorf("retrieving %s: %+v", *id, err) } - return utils.Bool(resp.RecordSetProperties != nil), nil + return utils.Bool(resp.Model != nil), nil } func (TestAccDnsARecordResource) basic(data acceptance.TestData) string { diff --git a/internal/services/dns/dns_aaaa_record_data_source.go b/internal/services/dns/dns_aaaa_record_data_source.go new file mode 100644 index 000000000000..ea1bc66b4c80 --- /dev/null +++ b/internal/services/dns/dns_aaaa_record_data_source.go @@ -0,0 +1,107 @@ +package dns + +import ( + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/set" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" +) + +func dataSourceDnsAAAARecord() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Read: dataSourceDnsAAAARecordRead, + + Timeouts: &pluginsdk.ResourceTimeout{ + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "resource_group_name": commonschema.ResourceGroupNameForDataSource(), + + "zone_name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "records": { + Type: pluginsdk.TypeSet, + Computed: true, + Elem: &pluginsdk.Schema{Type: pluginsdk.TypeString}, + Set: set.HashIPv6Address, + }, + + "ttl": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "fqdn": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "target_resource_id": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "tags": commonschema.TagsDataSource(), + }, + } +} + +func dataSourceDnsAAAARecordRead(d *pluginsdk.ResourceData, meta interface{}) error { + recordSetsClient := meta.(*clients.Client).Dns.RecordSets + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + + id := recordsets.NewRecordTypeID(subscriptionId, d.Get("resource_group_name").(string), d.Get("zone_name").(string), recordsets.RecordTypeAAAA, d.Get("name").(string)) + + resp, err := recordSetsClient.Get(ctx, id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return fmt.Errorf("%s was not found", id) + } + return fmt.Errorf("reading %s: %+v", id, err) + } + + d.SetId(id.ID()) + + d.Set("name", id.RelativeRecordSetName) + d.Set("resource_group_name", id.ResourceGroupName) + d.Set("zone_name", id.ZoneName) + + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("ttl", props.TTL) + d.Set("fqdn", props.Fqdn) + + if err := d.Set("records", flattenAzureRmDnsAaaaRecords(props.AAAARecords)); err != nil { + return fmt.Errorf("setting `records`: %+v", err) + } + + targetResourceId := "" + if props.TargetResource != nil && props.TargetResource.Id != nil { + targetResourceId = *props.TargetResource.Id + } + d.Set("target_resource_id", targetResourceId) + + return tags.FlattenAndSet(d, props.Metadata) + } + } + + return nil +} diff --git a/internal/services/dns/dns_aaaa_record_data_source_test.go b/internal/services/dns/dns_aaaa_record_data_source_test.go new file mode 100644 index 000000000000..5707601fe17f --- /dev/null +++ b/internal/services/dns/dns_aaaa_record_data_source_test.go @@ -0,0 +1,44 @@ +package dns_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" +) + +type DnsAAAARecordDataSource struct{} + +func TestAccDataSourceDnsAAAARecord_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_dns_aaaa_record", "test") + r := DnsAAAARecordDataSource{} + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("name").Exists(), + check.That(data.ResourceName).Key("resource_group_name").Exists(), + check.That(data.ResourceName).Key("zone_name").Exists(), + check.That(data.ResourceName).Key("records.#").HasValue("2"), + check.That(data.ResourceName).Key("ttl").Exists(), + check.That(data.ResourceName).Key("fqdn").Exists(), + check.That(data.ResourceName).Key("tags.%").HasValue("0"), + check.That(data.ResourceName).Key("target_resource_id").HasValue(""), + ), + }, + }) +} + +func (DnsAAAARecordDataSource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +data "azurerm_dns_aaaa_record" "test" { + name = azurerm_dns_aaaa_record.test.name + resource_group_name = azurerm_resource_group.test.name + zone_name = azurerm_dns_zone.test.name +} +`, DnsAAAARecordResource{}.basic(data)) +} diff --git a/internal/services/dns/dns_aaaa_record_resource.go b/internal/services/dns/dns_aaaa_record_resource.go index c8932efd587a..1d99936fb825 100644 --- a/internal/services/dns/dns_aaaa_record_resource.go +++ b/internal/services/dns/dns_aaaa_record_resource.go @@ -2,15 +2,15 @@ package dns import ( "fmt" - "net/http" "time" - "github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2018-05-01/dns" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/parse" - "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/set" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" @@ -33,8 +33,14 @@ func resourceDnsAAAARecord() *pluginsdk.Resource { }, Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - _, err := parse.AaaaRecordID(id) - return err + parsed, err := recordsets.ParseRecordTypeID(id) + if err != nil { + return err + } + if parsed.RecordType != recordsets.RecordTypeAAAA { + return fmt.Errorf("this resource only supports 'AAAA' records") + } + return nil }), Schema: map[string]*pluginsdk.Schema{ @@ -44,11 +50,12 @@ func resourceDnsAAAARecord() *pluginsdk.Resource { ForceNew: true, }, - "resource_group_name": azure.SchemaResourceGroupName(), + "resource_group_name": commonschema.ResourceGroupName(), "zone_name": { Type: pluginsdk.TypeString, Required: true, + ForceNew: true, }, "records": { @@ -72,7 +79,7 @@ func resourceDnsAAAARecord() *pluginsdk.Resource { Computed: true, }, - "tags": tags.Schema(), + "tags": commonschema.Tags(), "target_resource_id": { Type: pluginsdk.TypeString, @@ -85,7 +92,7 @@ func resourceDnsAAAARecord() *pluginsdk.Resource { } func resourceDnsAaaaRecordCreateUpdate(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Dns.RecordSetsClient + client := meta.(*clients.Client).Dns.RecordSets ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) subscriptionId := meta.(*clients.Client).Account.SubscriptionId defer cancel() @@ -94,18 +101,17 @@ func resourceDnsAaaaRecordCreateUpdate(d *pluginsdk.ResourceData, meta interface resGroup := d.Get("resource_group_name").(string) zoneName := d.Get("zone_name").(string) - resourceId := parse.NewAaaaRecordID(subscriptionId, resGroup, zoneName, name) - + id := recordsets.NewRecordTypeID(subscriptionId, resGroup, zoneName, recordsets.RecordTypeAAAA, name) if d.IsNewResource() { - existing, err := client.Get(ctx, resGroup, zoneName, name, dns.AAAA) + existing, err := client.Get(ctx, id) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { - return fmt.Errorf("checking for presence of existing DNS AAAA Record %q (Zone %q / Resource Group %q): %s", name, zoneName, resGroup, err) + if !response.WasNotFound(existing.HttpResponse) { + return fmt.Errorf("checking for presence of existing %s: %+v", id, err) } } - if !utils.ResponseWasNotFound(existing.Response) { - return tf.ImportAsExistsError("azurerm_dns_aaaa_record", resourceId.ID()) + if !response.WasNotFound(existing.HttpResponse) { + return tf.ImportAsExistsError("azurerm_dns_aaaa_record", id.ID()) } } @@ -114,18 +120,18 @@ func resourceDnsAaaaRecordCreateUpdate(d *pluginsdk.ResourceData, meta interface recordsRaw := d.Get("records").(*pluginsdk.Set).List() targetResourceId := d.Get("target_resource_id").(string) - parameters := dns.RecordSet{ + parameters := recordsets.RecordSet{ Name: &name, - RecordSetProperties: &dns.RecordSetProperties{ + Properties: &recordsets.RecordSetProperties{ Metadata: tags.Expand(t), TTL: &ttl, - AaaaRecords: expandAzureRmDnsAaaaRecords(recordsRaw), - TargetResource: &dns.SubResource{}, + AAAARecords: expandAzureRmDnsAaaaRecords(recordsRaw), + TargetResource: &recordsets.SubResource{}, }, } if targetResourceId != "" { - parameters.RecordSetProperties.TargetResource.ID = utils.String(targetResourceId) + parameters.Properties.TargetResource.Id = utils.String(targetResourceId) } // TODO: this can be removed when the provider SDK is upgraded @@ -133,99 +139,103 @@ func resourceDnsAaaaRecordCreateUpdate(d *pluginsdk.ResourceData, meta interface return fmt.Errorf("One of either `records` or `target_resource_id` must be specified") } - eTag := "" - ifNoneMatch := "" // set to empty to allow updates to records after creation - if _, err := client.CreateOrUpdate(ctx, resGroup, zoneName, name, dns.AAAA, parameters, eTag, ifNoneMatch); err != nil { - return fmt.Errorf("creating/updating DNS AAAA Record %q (Zone %q / Resource Group %q): %s", name, zoneName, resGroup, err) + if _, err := client.CreateOrUpdate(ctx, id, parameters, recordsets.DefaultCreateOrUpdateOperationOptions()); err != nil { + return fmt.Errorf("creating/updating %s: %+v", id, err) } - d.SetId(resourceId.ID()) - + d.SetId(id.ID()) return resourceDnsAaaaRecordRead(d, meta) } func resourceDnsAaaaRecordRead(d *pluginsdk.ResourceData, meta interface{}) error { - dnsClient := meta.(*clients.Client).Dns.RecordSetsClient + client := meta.(*clients.Client).Dns.RecordSets ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.AaaaRecordID(d.Id()) + id, err := recordsets.ParseRecordTypeIDInsensitively(d.Id()) if err != nil { return err } - resp, err := dnsClient.Get(ctx, id.ResourceGroup, id.DnszoneName, id.AAAAName, dns.AAAA) + resp, err := client.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { d.SetId("") return nil } - return fmt.Errorf("reading DNS AAAA record %s: %v", id.AAAAName, err) + return fmt.Errorf("retrieving %s: %+v", *id, err) } - d.Set("name", id.AAAAName) - d.Set("resource_group_name", id.ResourceGroup) - d.Set("zone_name", id.DnszoneName) + d.Set("name", id.RelativeRecordSetName) + d.Set("resource_group_name", id.ResourceGroupName) + d.Set("zone_name", id.ZoneName) - d.Set("fqdn", resp.Fqdn) - d.Set("ttl", resp.TTL) + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("fqdn", props.Fqdn) + d.Set("ttl", props.TTL) - if err := d.Set("records", flattenAzureRmDnsAaaaRecords(resp.AaaaRecords)); err != nil { - return fmt.Errorf("setting `records`: %+v", err) - } + if err := d.Set("records", flattenAzureRmDnsAaaaRecords(props.AAAARecords)); err != nil { + return fmt.Errorf("setting `records`: %+v", err) + } + + targetResourceId := "" + if props.TargetResource != nil && props.TargetResource.Id != nil { + targetResourceId = *props.TargetResource.Id + } + d.Set("target_resource_id", targetResourceId) - targetResourceId := "" - if resp.TargetResource != nil && resp.TargetResource.ID != nil { - targetResourceId = *resp.TargetResource.ID + if err := tags.FlattenAndSet(d, props.Metadata); err != nil { + return err + } + } } - d.Set("target_resource_id", targetResourceId) - return tags.FlattenAndSet(d, resp.Metadata) + return nil } func resourceDnsAaaaRecordDelete(d *pluginsdk.ResourceData, meta interface{}) error { - dnsClient := meta.(*clients.Client).Dns.RecordSetsClient + client := meta.(*clients.Client).Dns.RecordSets ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.AaaaRecordID(d.Id()) + id, err := recordsets.ParseRecordTypeID(d.Id()) if err != nil { return err } - resp, err := dnsClient.Delete(ctx, id.ResourceGroup, id.DnszoneName, id.AAAAName, dns.AAAA, "") - if resp.StatusCode != http.StatusOK { - return fmt.Errorf("deleting DNS AAAA Record %s: %+v", id.AAAAName, err) + if _, err := client.Delete(ctx, *id, recordsets.DefaultDeleteOperationOptions()); err != nil { + return fmt.Errorf("deleting %s: %+v", id.RelativeRecordSetName, err) } return nil } -func expandAzureRmDnsAaaaRecords(input []interface{}) *[]dns.AaaaRecord { - records := make([]dns.AaaaRecord, len(input)) +func expandAzureRmDnsAaaaRecords(input []interface{}) *[]recordsets.AaaaRecord { + records := make([]recordsets.AaaaRecord, len(input)) for i, v := range input { ipv6 := NormalizeIPv6Address(v) - records[i] = dns.AaaaRecord{ - Ipv6Address: &ipv6, + records[i] = recordsets.AaaaRecord{ + IPv6Address: &ipv6, } } return &records } -func flattenAzureRmDnsAaaaRecords(records *[]dns.AaaaRecord) []string { +func flattenAzureRmDnsAaaaRecords(records *[]recordsets.AaaaRecord) []string { if records == nil { return []string{} } results := make([]string, 0) for _, record := range *records { - if record.Ipv6Address == nil { + if record.IPv6Address == nil { continue } - results = append(results, NormalizeIPv6Address(*record.Ipv6Address)) + results = append(results, NormalizeIPv6Address(*record.IPv6Address)) } return results } diff --git a/internal/services/dns/dns_aaaa_record_resource_test.go b/internal/services/dns/dns_aaaa_record_resource_test.go index 30b4e4abfe5a..5185450d72fa 100644 --- a/internal/services/dns/dns_aaaa_record_resource_test.go +++ b/internal/services/dns/dns_aaaa_record_resource_test.go @@ -5,11 +5,10 @@ import ( "fmt" "testing" - "github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2018-05-01/dns" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -194,17 +193,17 @@ func TestAccAzureRMDnsAAAARecord_uncompressed(t *testing.T) { } func (DnsAAAARecordResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.AaaaRecordID(state.ID) + id, err := recordsets.ParseRecordTypeID(state.ID) if err != nil { return nil, err } - resp, err := clients.Dns.RecordSetsClient.Get(ctx, id.ResourceGroup, id.DnszoneName, id.AAAAName, dns.AAAA) + resp, err := clients.Dns.RecordSets.Get(ctx, *id) if err != nil { - return nil, fmt.Errorf("retrieving DNS AAAA record %s (resource group: %s): %v", id.AAAAName, id.ResourceGroup, err) + return nil, fmt.Errorf("retrieving %s: %+v", *id, err) } - return utils.Bool(resp.RecordSetProperties != nil), nil + return utils.Bool(resp.Model != nil), nil } func (DnsAAAARecordResource) basic(data acceptance.TestData) string { diff --git a/internal/services/dns/dns_caa_record_data_source.go b/internal/services/dns/dns_caa_record_data_source.go new file mode 100644 index 000000000000..a8eea460c0e9 --- /dev/null +++ b/internal/services/dns/dns_caa_record_data_source.go @@ -0,0 +1,112 @@ +package dns + +import ( + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" +) + +func dataSourceDnsCaaRecord() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Read: dataSourceDnsCaaRecordRead, + + Timeouts: &pluginsdk.ResourceTimeout{ + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "resource_group_name": commonschema.ResourceGroupNameForDataSource(), + + "zone_name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "record": { + Type: pluginsdk.TypeSet, + Computed: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "flags": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "tag": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "value": { + Type: pluginsdk.TypeString, + Computed: true, + }, + }, + }, + Set: resourceDnsCaaRecordHash, + }, + + "ttl": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "fqdn": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "tags": commonschema.TagsDataSource(), + }, + } +} + +func dataSourceDnsCaaRecordRead(d *pluginsdk.ResourceData, meta interface{}) error { + recordSetsClient := meta.(*clients.Client).Dns.RecordSets + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + + id := recordsets.NewRecordTypeID(subscriptionId, d.Get("resource_group_name").(string), d.Get("zone_name").(string), recordsets.RecordTypeCAA, d.Get("name").(string)) + + resp, err := recordSetsClient.Get(ctx, id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return fmt.Errorf("%s was not found", id) + } + return fmt.Errorf("reading %s: %+v", id, err) + } + + d.SetId(id.ID()) + + d.Set("name", id.RelativeRecordSetName) + d.Set("resource_group_name", id.ResourceGroupName) + d.Set("zone_name", id.ZoneName) + + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("ttl", props.TTL) + d.Set("fqdn", props.Fqdn) + + if err := d.Set("record", flattenAzureRmDnsCaaRecords(props.CaaRecords)); err != nil { + return err + } + + return tags.FlattenAndSet(d, props.Metadata) + } + } + + return nil +} diff --git a/internal/services/dns/dns_caa_record_data_source_test.go b/internal/services/dns/dns_caa_record_data_source_test.go new file mode 100644 index 000000000000..4d1574cf9961 --- /dev/null +++ b/internal/services/dns/dns_caa_record_data_source_test.go @@ -0,0 +1,43 @@ +package dns_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" +) + +type DnsCaaRecordDataSource struct{} + +func TestAccDataSourceDnsCaaRecord_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_dns_caa_record", "test") + r := DnsCaaRecordDataSource{} + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("name").Exists(), + check.That(data.ResourceName).Key("resource_group_name").Exists(), + check.That(data.ResourceName).Key("zone_name").Exists(), + check.That(data.ResourceName).Key("record.#").HasValue("4"), + check.That(data.ResourceName).Key("ttl").Exists(), + check.That(data.ResourceName).Key("fqdn").Exists(), + check.That(data.ResourceName).Key("tags.%").HasValue("0"), + ), + }, + }) +} + +func (DnsCaaRecordDataSource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +data "azurerm_dns_caa_record" "test" { + name = azurerm_dns_caa_record.test.name + resource_group_name = azurerm_resource_group.test.name + zone_name = azurerm_dns_zone.test.name +} +`, DnsCaaRecordResource{}.basic(data)) +} diff --git a/internal/services/dns/dns_caa_record_resource.go b/internal/services/dns/dns_caa_record_resource.go index f11e333de4cc..4482b9807760 100644 --- a/internal/services/dns/dns_caa_record_resource.go +++ b/internal/services/dns/dns_caa_record_resource.go @@ -3,19 +3,17 @@ package dns import ( "bytes" "fmt" - "net/http" "time" - "github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2018-05-01/dns" - "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/parse" - "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" - "github.com/hashicorp/terraform-provider-azurerm/utils" ) func resourceDnsCaaRecord() *pluginsdk.Resource { @@ -33,8 +31,14 @@ func resourceDnsCaaRecord() *pluginsdk.Resource { }, Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - _, err := parse.CaaRecordID(id) - return err + parsed, err := recordsets.ParseRecordTypeID(id) + if err != nil { + return err + } + if parsed.RecordType != recordsets.RecordTypeCAA { + return fmt.Errorf("this resource only supports 'CAA' records") + } + return nil }), Schema: map[string]*pluginsdk.Schema{ @@ -44,11 +48,12 @@ func resourceDnsCaaRecord() *pluginsdk.Resource { ForceNew: true, }, - "resource_group_name": azure.SchemaResourceGroupName(), + "resource_group_name": commonschema.ResourceGroupName(), "zone_name": { Type: pluginsdk.TypeString, Required: true, + ForceNew: true, }, "record": { @@ -90,13 +95,13 @@ func resourceDnsCaaRecord() *pluginsdk.Resource { Computed: true, }, - "tags": tags.Schema(), + "tags": commonschema.Tags(), }, } } func resourceDnsCaaRecordCreateUpdate(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Dns.RecordSetsClient + client := meta.(*clients.Client).Dns.RecordSets ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) subscriptionId := meta.(*clients.Client).Account.SubscriptionId defer cancel() @@ -105,103 +110,122 @@ func resourceDnsCaaRecordCreateUpdate(d *pluginsdk.ResourceData, meta interface{ resGroup := d.Get("resource_group_name").(string) zoneName := d.Get("zone_name").(string) - resourceId := parse.NewCaaRecordID(subscriptionId, resGroup, zoneName, name) - + id := recordsets.NewRecordTypeID(subscriptionId, resGroup, zoneName, recordsets.RecordTypeCAA, name) if d.IsNewResource() { - existing, err := client.Get(ctx, resGroup, zoneName, name, dns.CAA) + existing, err := client.Get(ctx, id) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return fmt.Errorf("checking for presence of existing DNS CAA Record %q (Zone %q / Resource Group %q): %s", name, zoneName, resGroup, err) } } - if !utils.ResponseWasNotFound(existing.Response) { - return tf.ImportAsExistsError("azurerm_dns_caa_record", resourceId.ID()) + if !response.WasNotFound(existing.HttpResponse) { + return tf.ImportAsExistsError("azurerm_dns_caa_record", id.ID()) } } ttl := int64(d.Get("ttl").(int)) t := d.Get("tags").(map[string]interface{}) - parameters := dns.RecordSet{ + parameters := recordsets.RecordSet{ Name: &name, - RecordSetProperties: &dns.RecordSetProperties{ + Properties: &recordsets.RecordSetProperties{ Metadata: tags.Expand(t), TTL: &ttl, CaaRecords: expandAzureRmDnsCaaRecords(d), }, } - eTag := "" - ifNoneMatch := "" // set to empty to allow updates to records after creation - if _, err := client.CreateOrUpdate(ctx, resGroup, zoneName, name, dns.CAA, parameters, eTag, ifNoneMatch); err != nil { - return fmt.Errorf("creating/updating DNS CAA Record %q (Zone %q / Resource Group %q): %s", name, zoneName, resGroup, err) + if _, err := client.CreateOrUpdate(ctx, id, parameters, recordsets.DefaultCreateOrUpdateOperationOptions()); err != nil { + return fmt.Errorf("creating/updating %s: %+v", id, err) } - d.SetId(resourceId.ID()) + d.SetId(id.ID()) return resourceDnsCaaRecordRead(d, meta) } func resourceDnsCaaRecordRead(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Dns.RecordSetsClient + client := meta.(*clients.Client).Dns.RecordSets ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.CaaRecordID(d.Id()) + id, err := recordsets.ParseRecordTypeIDInsensitively(d.Id()) if err != nil { return err } - resp, err := client.Get(ctx, id.ResourceGroup, id.DnszoneName, id.CAAName, dns.CAA) + resp, err := client.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { d.SetId("") return nil } - return fmt.Errorf("reading DNS CAA record %s: %v", id.CAAName, err) + return fmt.Errorf("retrieving %s: %+v", *id, err) } - d.Set("name", id.CAAName) - d.Set("resource_group_name", id.ResourceGroup) - d.Set("zone_name", id.DnszoneName) + d.Set("name", id.RelativeRecordSetName) + d.Set("resource_group_name", id.ResourceGroupName) + d.Set("zone_name", id.ZoneName) - d.Set("ttl", resp.TTL) - d.Set("fqdn", resp.Fqdn) + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("ttl", props.TTL) + d.Set("fqdn", props.Fqdn) - if err := d.Set("record", flattenAzureRmDnsCaaRecords(resp.CaaRecords)); err != nil { - return err + if err := d.Set("record", flattenAzureRmDnsCaaRecords(props.CaaRecords)); err != nil { + return err + } + if err := tags.FlattenAndSet(d, props.Metadata); err != nil { + return err + } + } } - return tags.FlattenAndSet(d, resp.Metadata) + + return nil } func resourceDnsCaaRecordDelete(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Dns.RecordSetsClient + client := meta.(*clients.Client).Dns.RecordSets ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.CaaRecordID(d.Id()) + id, err := recordsets.ParseRecordTypeID(d.Id()) if err != nil { return err } - resp, err := client.Delete(ctx, id.ResourceGroup, id.DnszoneName, id.CAAName, dns.CAA, "") - if resp.StatusCode != http.StatusOK { - return fmt.Errorf("deleting DNS CAA Record %s: %+v", id.CAAName, err) + if _, err := client.Delete(ctx, *id, recordsets.DefaultDeleteOperationOptions()); err != nil { + return fmt.Errorf("deleting %s: %+v", *id, err) } return nil } -func flattenAzureRmDnsCaaRecords(records *[]dns.CaaRecord) []map[string]interface{} { +func flattenAzureRmDnsCaaRecords(records *[]recordsets.CaaRecord) []map[string]interface{} { results := make([]map[string]interface{}, 0) if records != nil { for _, record := range *records { + flags := int64(0) + if record.Flags != nil { + flags = *record.Flags + } + + tag := "" + if record.Tag != nil { + tag = *record.Tag + } + + value := "" + if record.Value != nil { + value = *record.Value + } + results = append(results, map[string]interface{}{ - "flags": *record.Flags, - "tag": *record.Tag, - "value": *record.Value, + "flags": flags, + "tag": tag, + "value": value, }) } } @@ -209,23 +233,22 @@ func flattenAzureRmDnsCaaRecords(records *[]dns.CaaRecord) []map[string]interfac return results } -func expandAzureRmDnsCaaRecords(d *pluginsdk.ResourceData) *[]dns.CaaRecord { +func expandAzureRmDnsCaaRecords(d *pluginsdk.ResourceData) *[]recordsets.CaaRecord { recordStrings := d.Get("record").(*pluginsdk.Set).List() - records := make([]dns.CaaRecord, len(recordStrings)) + records := make([]recordsets.CaaRecord, 0) - for i, v := range recordStrings { + for _, v := range recordStrings { record := v.(map[string]interface{}) - flags := int32(record["flags"].(int)) + + flags := int64(record["flags"].(int)) tag := record["tag"].(string) value := record["value"].(string) - caaRecord := dns.CaaRecord{ + records = append(records, recordsets.CaaRecord{ Flags: &flags, Tag: &tag, Value: &value, - } - - records[i] = caaRecord + }) } return &records diff --git a/internal/services/dns/dns_caa_record_resource_test.go b/internal/services/dns/dns_caa_record_resource_test.go index d4733d22f3f5..e570d88b55ec 100644 --- a/internal/services/dns/dns_caa_record_resource_test.go +++ b/internal/services/dns/dns_caa_record_resource_test.go @@ -5,11 +5,10 @@ import ( "fmt" "testing" - "github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2018-05-01/dns" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -96,17 +95,17 @@ func TestAccDnsCaaRecord_withTags(t *testing.T) { } func (DnsCaaRecordResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.CaaRecordID(state.ID) + id, err := recordsets.ParseRecordTypeID(state.ID) if err != nil { return nil, err } - resp, err := clients.Dns.RecordSetsClient.Get(ctx, id.ResourceGroup, id.DnszoneName, id.CAAName, dns.CAA) + resp, err := clients.Dns.RecordSets.Get(ctx, *id) if err != nil { - return nil, fmt.Errorf("retrieving DNS CAA record %s (resource group: %s): %v", id.CAAName, id.ResourceGroup, err) + return nil, fmt.Errorf("retrieving %s: %v", *id, err) } - return utils.Bool(resp.RecordSetProperties != nil), nil + return utils.Bool(resp.Model != nil), nil } func (DnsCaaRecordResource) basic(data acceptance.TestData) string { diff --git a/internal/services/dns/dns_cname_record_data_source.go b/internal/services/dns/dns_cname_record_data_source.go new file mode 100644 index 000000000000..eb66db443b40 --- /dev/null +++ b/internal/services/dns/dns_cname_record_data_source.go @@ -0,0 +1,107 @@ +package dns + +import ( + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/response" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" +) + +func dataSourceDnsCNameRecord() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Read: dataSourceDnsCNameRecordRead, + + Timeouts: &pluginsdk.ResourceTimeout{ + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "resource_group_name": commonschema.ResourceGroupNameForDataSource(), + + "zone_name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "record": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "ttl": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "fqdn": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "target_resource_id": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "tags": commonschema.TagsDataSource(), + }, + } +} + +func dataSourceDnsCNameRecordRead(d *pluginsdk.ResourceData, meta interface{}) error { + recordSetsClient := meta.(*clients.Client).Dns.RecordSets + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + + id := recordsets.NewRecordTypeID(subscriptionId, d.Get("resource_group_name").(string), d.Get("zone_name").(string), recordsets.RecordTypeCNAME, d.Get("name").(string)) + + resp, err := recordSetsClient.Get(ctx, id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return fmt.Errorf("%s was not found", id) + } + return fmt.Errorf("reading %s: %+v", id, err) + } + + d.SetId(id.ID()) + + d.Set("name", id.RelativeRecordSetName) + d.Set("resource_group_name", id.ResourceGroupName) + d.Set("zone_name", id.ZoneName) + + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("ttl", props.TTL) + d.Set("fqdn", props.Fqdn) + + cname := "" + if props.CNAMERecord != nil && props.CNAMERecord.Cname != nil { + cname = *props.CNAMERecord.Cname + } + d.Set("record", cname) + + targetResourceId := "" + if props.TargetResource != nil && props.TargetResource.Id != nil { + targetResourceId = *props.TargetResource.Id + } + d.Set("target_resource_id", targetResourceId) + + return tags.FlattenAndSet(d, props.Metadata) + } + } + + return nil +} diff --git a/internal/services/dns/dns_cname_record_data_source_test.go b/internal/services/dns/dns_cname_record_data_source_test.go new file mode 100644 index 000000000000..aba24f4ed012 --- /dev/null +++ b/internal/services/dns/dns_cname_record_data_source_test.go @@ -0,0 +1,43 @@ +package dns_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" +) + +type DnsCNameRecordDataSource struct{} + +func TestAccDataSourceDnsCNameRecord_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_dns_cname_record", "test") + r := DnsCNameRecordDataSource{} + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("name").Exists(), + check.That(data.ResourceName).Key("resource_group_name").Exists(), + check.That(data.ResourceName).Key("zone_name").Exists(), + check.That(data.ResourceName).Key("record").HasValue("contoso.com"), + check.That(data.ResourceName).Key("ttl").Exists(), + check.That(data.ResourceName).Key("fqdn").Exists(), + check.That(data.ResourceName).Key("tags.%").HasValue("0"), + ), + }, + }) +} + +func (DnsCNameRecordDataSource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +data "azurerm_dns_cname_record" "test" { + name = azurerm_dns_cname_record.test.name + resource_group_name = azurerm_resource_group.test.name + zone_name = azurerm_dns_zone.test.name +} +`, DnsCNameRecordResource{}.basic(data)) +} diff --git a/internal/services/dns/dns_cname_record_resource.go b/internal/services/dns/dns_cname_record_resource.go index 7b9c40ac7d6d..69c823cf19ee 100644 --- a/internal/services/dns/dns_cname_record_resource.go +++ b/internal/services/dns/dns_cname_record_resource.go @@ -2,15 +2,15 @@ package dns import ( "fmt" - "net/http" "time" - "github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2018-05-01/dns" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/parse" - "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" "github.com/hashicorp/terraform-provider-azurerm/utils" @@ -31,8 +31,14 @@ func resourceDnsCNameRecord() *pluginsdk.Resource { }, Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - _, err := parse.CnameRecordID(id) - return err + parsed, err := recordsets.ParseRecordTypeID(id) + if err != nil { + return err + } + if parsed.RecordType != recordsets.RecordTypeCNAME { + return fmt.Errorf("this resource only supports 'CNAME' records") + } + return nil }), Schema: map[string]*pluginsdk.Schema{ @@ -42,11 +48,12 @@ func resourceDnsCNameRecord() *pluginsdk.Resource { ForceNew: true, }, - "resource_group_name": azure.SchemaResourceGroupName(), + "resource_group_name": commonschema.ResourceGroupName(), "zone_name": { Type: pluginsdk.TypeString, Required: true, + ForceNew: true, }, "record": { @@ -72,13 +79,13 @@ func resourceDnsCNameRecord() *pluginsdk.Resource { ConflictsWith: []string{"record"}, }, - "tags": tags.Schema(), + "tags": commonschema.Tags(), }, } } func resourceDnsCNameRecordCreateUpdate(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Dns.RecordSetsClient + client := meta.(*clients.Client).Dns.RecordSets ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) subscriptionId := meta.(*clients.Client).Account.SubscriptionId defer cancel() @@ -87,18 +94,17 @@ func resourceDnsCNameRecordCreateUpdate(d *pluginsdk.ResourceData, meta interfac resGroup := d.Get("resource_group_name").(string) zoneName := d.Get("zone_name").(string) - resourceId := parse.NewCnameRecordID(subscriptionId, resGroup, zoneName, name) - + id := recordsets.NewRecordTypeID(subscriptionId, resGroup, zoneName, recordsets.RecordTypeCNAME, name) if d.IsNewResource() { - existing, err := client.Get(ctx, resGroup, zoneName, name, dns.CNAME) + existing, err := client.Get(ctx, id) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { - return fmt.Errorf("checking for presence of existing DNS CNAME Record %q (Zone %q / Resource Group %q): %s", name, zoneName, resGroup, err) + if !response.WasNotFound(existing.HttpResponse) { + return fmt.Errorf("checking for presence of existing %s: %+v", id, err) } } - if !utils.ResponseWasNotFound(existing.Response) { - return tf.ImportAsExistsError("azurerm_dns_cname_record", resourceId.ID()) + if !response.WasNotFound(existing.HttpResponse) { + return tf.ImportAsExistsError("azurerm_dns_cname_record", id.ID()) } } @@ -107,22 +113,22 @@ func resourceDnsCNameRecordCreateUpdate(d *pluginsdk.ResourceData, meta interfac t := d.Get("tags").(map[string]interface{}) targetResourceId := d.Get("target_resource_id").(string) - parameters := dns.RecordSet{ + parameters := recordsets.RecordSet{ Name: &name, - RecordSetProperties: &dns.RecordSetProperties{ + Properties: &recordsets.RecordSetProperties{ Metadata: tags.Expand(t), TTL: &ttl, - CnameRecord: &dns.CnameRecord{}, - TargetResource: &dns.SubResource{}, + CNAMERecord: &recordsets.CnameRecord{}, + TargetResource: &recordsets.SubResource{}, }, } if record != "" { - parameters.RecordSetProperties.CnameRecord.Cname = utils.String(record) + parameters.Properties.CNAMERecord.Cname = utils.String(record) } if targetResourceId != "" { - parameters.RecordSetProperties.TargetResource.ID = utils.String(targetResourceId) + parameters.Properties.TargetResource.Id = utils.String(targetResourceId) } // TODO: this can be removed when the provider SDK is upgraded @@ -130,73 +136,76 @@ func resourceDnsCNameRecordCreateUpdate(d *pluginsdk.ResourceData, meta interfac return fmt.Errorf("One of either `record` or `target_resource_id` must be specified") } - eTag := "" - ifNoneMatch := "" // set to empty to allow updates to records after creation - if _, err := client.CreateOrUpdate(ctx, resGroup, zoneName, name, dns.CNAME, parameters, eTag, ifNoneMatch); err != nil { - return fmt.Errorf("creating/updating CNAME Record %q (DNS Zone %q / Resource Group %q): %s", name, zoneName, resGroup, err) + if _, err := client.CreateOrUpdate(ctx, id, parameters, recordsets.DefaultCreateOrUpdateOperationOptions()); err != nil { + return fmt.Errorf("creating/updating %s: %+v", id, err) } - d.SetId(resourceId.ID()) + d.SetId(id.ID()) return resourceDnsCNameRecordRead(d, meta) } func resourceDnsCNameRecordRead(d *pluginsdk.ResourceData, meta interface{}) error { - dnsClient := meta.(*clients.Client).Dns.RecordSetsClient + client := meta.(*clients.Client).Dns.RecordSets ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.CnameRecordID(d.Id()) + id, err := recordsets.ParseRecordTypeIDInsensitively(d.Id()) if err != nil { return err } - resp, err := dnsClient.Get(ctx, id.ResourceGroup, id.DnszoneName, id.CNAMEName, dns.CNAME) + resp, err := client.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { d.SetId("") return nil } - return fmt.Errorf("retrieving CNAME Record %s (DNS Zone %q / Resource Group %q): %+v", id.CNAMEName, id.DnszoneName, id.ResourceGroup, err) + return fmt.Errorf("retrieving %s: %+v", *id, err) } - d.Set("name", id.CNAMEName) - d.Set("resource_group_name", id.ResourceGroup) - d.Set("zone_name", id.DnszoneName) + d.Set("name", id.RelativeRecordSetName) + d.Set("resource_group_name", id.ResourceGroupName) + d.Set("zone_name", id.ZoneName) - d.Set("fqdn", resp.Fqdn) - d.Set("ttl", resp.TTL) + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("fqdn", props.Fqdn) + d.Set("ttl", props.TTL) - if props := resp.RecordSetProperties; props != nil { - cname := "" - if props.CnameRecord != nil && props.CnameRecord.Cname != nil { - cname = *props.CnameRecord.Cname - } - d.Set("record", cname) + cname := "" + if props.CNAMERecord != nil && props.CNAMERecord.Cname != nil { + cname = *props.CNAMERecord.Cname + } + d.Set("record", cname) + + targetResourceId := "" + if props.TargetResource != nil && props.TargetResource.Id != nil { + targetResourceId = *props.TargetResource.Id + } + d.Set("target_resource_id", targetResourceId) - targetResourceId := "" - if props.TargetResource != nil && props.TargetResource.ID != nil { - targetResourceId = *props.TargetResource.ID + if err := tags.FlattenAndSet(d, props.Metadata); err != nil { + return err + } } - d.Set("target_resource_id", targetResourceId) } - return tags.FlattenAndSet(d, resp.Metadata) + return nil } func resourceDnsCNameRecordDelete(d *pluginsdk.ResourceData, meta interface{}) error { - dnsClient := meta.(*clients.Client).Dns.RecordSetsClient + client := meta.(*clients.Client).Dns.RecordSets ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.CnameRecordID(d.Id()) + id, err := recordsets.ParseRecordTypeID(d.Id()) if err != nil { return err } - resp, err := dnsClient.Delete(ctx, id.ResourceGroup, id.DnszoneName, id.CNAMEName, dns.CNAME, "") - if resp.StatusCode != http.StatusOK { - return fmt.Errorf("deleting CNAME Record %q (DNS Zone %q / Resource Group %q): %+v", id.CNAMEName, id.DnszoneName, id.ResourceGroup, err) + if _, err := client.Delete(ctx, *id, recordsets.DefaultDeleteOperationOptions()); err != nil { + return fmt.Errorf("deleting %s: %+v", *id, err) } return nil diff --git a/internal/services/dns/dns_cname_record_resource_test.go b/internal/services/dns/dns_cname_record_resource_test.go index df4834378f41..352d278df48c 100644 --- a/internal/services/dns/dns_cname_record_resource_test.go +++ b/internal/services/dns/dns_cname_record_resource_test.go @@ -5,11 +5,10 @@ import ( "fmt" "testing" - "github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2018-05-01/dns" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -183,17 +182,17 @@ func TestAccAzureRMDnsCNameRecord_AliasToRecord(t *testing.T) { } func (DnsCNameRecordResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.CnameRecordID(state.ID) + id, err := recordsets.ParseRecordTypeID(state.ID) if err != nil { return nil, err } - resp, err := clients.Dns.RecordSetsClient.Get(ctx, id.ResourceGroup, id.DnszoneName, id.CNAMEName, dns.CNAME) + resp, err := clients.Dns.RecordSets.Get(ctx, *id) if err != nil { - return nil, fmt.Errorf("retrieving DNS CNAME record %s (resource group: %s): %v", id.CNAMEName, id.ResourceGroup, err) + return nil, fmt.Errorf("retrieving %s: %+v", *id, err) } - return utils.Bool(resp.RecordSetProperties != nil), nil + return utils.Bool(resp.Model != nil), nil } func (DnsCNameRecordResource) basic(data acceptance.TestData) string { diff --git a/internal/services/dns/dns_mx_record_data_source.go b/internal/services/dns/dns_mx_record_data_source.go new file mode 100644 index 000000000000..7905f5d600cb --- /dev/null +++ b/internal/services/dns/dns_mx_record_data_source.go @@ -0,0 +1,108 @@ +package dns + +import ( + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" +) + +func dataSourceDnsMxRecord() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Read: dataSourceDnsMxRecordRead, + + Timeouts: &pluginsdk.ResourceTimeout{ + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Optional: true, + }, + + "resource_group_name": commonschema.ResourceGroupNameForDataSource(), + + "zone_name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "record": { + Type: pluginsdk.TypeSet, + Computed: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "preference": { + // TODO: this should become an Int + Type: pluginsdk.TypeString, + Computed: true, + }, + + "exchange": { + Type: pluginsdk.TypeString, + Computed: true, + }, + }, + }, + Set: resourceDnsMxRecordHash, + }, + + "ttl": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "fqdn": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "tags": commonschema.TagsDataSource(), + }, + } +} + +func dataSourceDnsMxRecordRead(d *pluginsdk.ResourceData, meta interface{}) error { + recordSetsClient := meta.(*clients.Client).Dns.RecordSets + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + + id := recordsets.NewRecordTypeID(subscriptionId, d.Get("resource_group_name").(string), d.Get("zone_name").(string), recordsets.RecordTypeMX, d.Get("name").(string)) + + resp, err := recordSetsClient.Get(ctx, id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return fmt.Errorf("%s was not found", id) + } + return fmt.Errorf("reading %s: %+v", id, err) + } + + d.SetId(id.ID()) + + d.Set("name", id.RelativeRecordSetName) + d.Set("resource_group_name", id.ResourceGroupName) + d.Set("zone_name", id.ZoneName) + + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("ttl", props.TTL) + d.Set("fqdn", props.Fqdn) + + if err := d.Set("record", flattenAzureRmDnsMxRecords(props.MXRecords)); err != nil { + return err + } + + return tags.FlattenAndSet(d, props.Metadata) + } + } + + return nil +} diff --git a/internal/services/dns/dns_mx_record_data_source_test.go b/internal/services/dns/dns_mx_record_data_source_test.go new file mode 100644 index 000000000000..d9e2747a3cc5 --- /dev/null +++ b/internal/services/dns/dns_mx_record_data_source_test.go @@ -0,0 +1,43 @@ +package dns_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" +) + +type DnsMxRecordDataSource struct{} + +func TestAccDataSourceDnsMxRecord_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_dns_mx_record", "test") + r := DnsMxRecordDataSource{} + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("name").Exists(), + check.That(data.ResourceName).Key("resource_group_name").Exists(), + check.That(data.ResourceName).Key("zone_name").Exists(), + check.That(data.ResourceName).Key("record.#").HasValue("2"), + check.That(data.ResourceName).Key("ttl").Exists(), + check.That(data.ResourceName).Key("fqdn").Exists(), + check.That(data.ResourceName).Key("tags.%").HasValue("0"), + ), + }, + }) +} + +func (DnsMxRecordDataSource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +data "azurerm_dns_mx_record" "test" { + name = azurerm_dns_mx_record.test.name + resource_group_name = azurerm_resource_group.test.name + zone_name = azurerm_dns_zone.test.name +} +`, DnsMxRecordResource{}.basic(data)) +} diff --git a/internal/services/dns/dns_mx_record_resource.go b/internal/services/dns/dns_mx_record_resource.go index a74cd20754a5..277e0e13a219 100644 --- a/internal/services/dns/dns_mx_record_resource.go +++ b/internal/services/dns/dns_mx_record_resource.go @@ -3,19 +3,17 @@ package dns import ( "bytes" "fmt" - "net/http" "strconv" "time" - "github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2018-05-01/dns" - "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/parse" - "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" - "github.com/hashicorp/terraform-provider-azurerm/utils" ) func resourceDnsMxRecord() *pluginsdk.Resource { @@ -33,8 +31,14 @@ func resourceDnsMxRecord() *pluginsdk.Resource { }, Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - _, err := parse.MxRecordID(id) - return err + parsed, err := recordsets.ParseRecordTypeID(id) + if err != nil { + return err + } + if parsed.RecordType != recordsets.RecordTypeMX { + return fmt.Errorf("this resource only supports 'MX' records") + } + return nil }), Schema: map[string]*pluginsdk.Schema{ @@ -45,11 +49,12 @@ func resourceDnsMxRecord() *pluginsdk.Resource { Default: "@", }, - "resource_group_name": azure.SchemaResourceGroupName(), + "resource_group_name": commonschema.ResourceGroupName(), "zone_name": { Type: pluginsdk.TypeString, Required: true, + ForceNew: true, }, "record": { @@ -82,13 +87,13 @@ func resourceDnsMxRecord() *pluginsdk.Resource { Computed: true, }, - "tags": tags.Schema(), + "tags": commonschema.Tags(), }, } } func resourceDnsMxRecordCreateUpdate(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Dns.RecordSetsClient + client := meta.(*clients.Client).Dns.RecordSets ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) subscriptionId := meta.(*clients.Client).Account.SubscriptionId defer cancel() @@ -97,87 +102,92 @@ func resourceDnsMxRecordCreateUpdate(d *pluginsdk.ResourceData, meta interface{} resGroup := d.Get("resource_group_name").(string) zoneName := d.Get("zone_name").(string) - resourceId := parse.NewMxRecordID(subscriptionId, resGroup, zoneName, name) - + id := recordsets.NewRecordTypeID(subscriptionId, resGroup, zoneName, recordsets.RecordTypeMX, name) if d.IsNewResource() { - existing, err := client.Get(ctx, resGroup, zoneName, name, dns.MX) + existing, err := client.Get(ctx, id) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { - return fmt.Errorf("checking for presence of existing DNS MX Record %q (Zone %q / Resource Group %q): %s", name, zoneName, resGroup, err) + if !response.WasNotFound(existing.HttpResponse) { + return fmt.Errorf("checking for presence of existing %s: %+v", id, err) } } - if !utils.ResponseWasNotFound(existing.Response) { - return tf.ImportAsExistsError("azurerm_dns_mx_record", resourceId.ID()) + if !response.WasNotFound(existing.HttpResponse) { + return tf.ImportAsExistsError("azurerm_dns_mx_record", id.ID()) } } ttl := int64(d.Get("ttl").(int)) t := d.Get("tags").(map[string]interface{}) - parameters := dns.RecordSet{ + parameters := recordsets.RecordSet{ Name: &name, - RecordSetProperties: &dns.RecordSetProperties{ + Properties: &recordsets.RecordSetProperties{ Metadata: tags.Expand(t), TTL: &ttl, - MxRecords: expandAzureRmDnsMxRecords(d), + MXRecords: expandAzureRmDnsMxRecords(d), }, } - if _, err := client.CreateOrUpdate(ctx, resGroup, zoneName, name, dns.MX, parameters, "", ""); err != nil { - return fmt.Errorf("creating/updating DNS MX Record %q (Zone %q / Resource Group %q): %s", name, zoneName, resGroup, err) + if _, err := client.CreateOrUpdate(ctx, id, parameters, recordsets.DefaultCreateOrUpdateOperationOptions()); err != nil { + return fmt.Errorf("creating/updating %s: %+v", id, err) } - d.SetId(resourceId.ID()) - + d.SetId(id.ID()) return resourceDnsMxRecordRead(d, meta) } func resourceDnsMxRecordRead(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Dns.RecordSetsClient + client := meta.(*clients.Client).Dns.RecordSets ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.MxRecordID(d.Id()) + id, err := recordsets.ParseRecordTypeIDInsensitively(d.Id()) if err != nil { return err } - resp, err := client.Get(ctx, id.ResourceGroup, id.DnszoneName, id.MXName, dns.MX) + resp, err := client.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { d.SetId("") return nil } - return fmt.Errorf("reading DNS MX record %s: %v", id.MXName, err) + return fmt.Errorf("retrieving %s: %+v", *id, err) } - d.Set("name", id.MXName) - d.Set("resource_group_name", id.ResourceGroup) - d.Set("zone_name", id.DnszoneName) + d.Set("name", id.RelativeRecordSetName) + d.Set("resource_group_name", id.ResourceGroupName) + d.Set("zone_name", id.ZoneName) - d.Set("ttl", resp.TTL) - d.Set("fqdn", resp.Fqdn) + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("ttl", props.TTL) + d.Set("fqdn", props.Fqdn) - if err := d.Set("record", flattenAzureRmDnsMxRecords(resp.MxRecords)); err != nil { - return err + if err := d.Set("record", flattenAzureRmDnsMxRecords(props.MXRecords)); err != nil { + return err + } + if err := tags.FlattenAndSet(d, props.Metadata); err != nil { + return err + } + } } - return tags.FlattenAndSet(d, resp.Metadata) + + return nil } func resourceDnsMxRecordDelete(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Dns.RecordSetsClient + client := meta.(*clients.Client).Dns.RecordSets ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.MxRecordID(d.Id()) + id, err := recordsets.ParseRecordTypeID(d.Id()) if err != nil { return err } - resp, err := client.Delete(ctx, id.ResourceGroup, id.DnszoneName, id.MXName, dns.MX, "") - if resp.StatusCode != http.StatusOK { - return fmt.Errorf("deleting DNS MX Record %s: %+v", id.MXName, err) + if _, err := client.Delete(ctx, *id, recordsets.DefaultDeleteOperationOptions()); err != nil { + return fmt.Errorf("deleting %s: %+v", *id, err) } return nil @@ -186,16 +196,25 @@ func resourceDnsMxRecordDelete(d *pluginsdk.ResourceData, meta interface{}) erro // flatten creates an array of map where preference is a string to suit // the expectations of the ResourceData schema, so that this data can be // managed by Terradata state. -func flattenAzureRmDnsMxRecords(records *[]dns.MxRecord) []map[string]interface{} { +func flattenAzureRmDnsMxRecords(records *[]recordsets.MxRecord) []map[string]interface{} { results := make([]map[string]interface{}, 0) if records != nil { for _, record := range *records { - preferenceI32 := *record.Preference - preference := strconv.Itoa(int(preferenceI32)) + // TODO: convert this to use an int64 + preference := "" + if record.Preference != nil { + preference = strconv.Itoa(int(*record.Preference)) + } + + exchange := "" + if record.Exchange != nil { + exchange = *record.Exchange + } + results = append(results, map[string]interface{}{ "preference": preference, - "exchange": *record.Exchange, + "exchange": exchange, }) } } @@ -206,19 +225,18 @@ func flattenAzureRmDnsMxRecords(records *[]dns.MxRecord) []map[string]interface{ // expand creates an array of dns.MxRecord, that is, the array needed // by azure-sdk-for-go to manipulate azure resources, hence Preference // is an int32 -func expandAzureRmDnsMxRecords(d *pluginsdk.ResourceData) *[]dns.MxRecord { +func expandAzureRmDnsMxRecords(d *pluginsdk.ResourceData) *[]recordsets.MxRecord { recordStrings := d.Get("record").(*pluginsdk.Set).List() - records := make([]dns.MxRecord, len(recordStrings)) + records := make([]recordsets.MxRecord, len(recordStrings)) for i, v := range recordStrings { mxrecord := v.(map[string]interface{}) preference := mxrecord["preference"].(string) i64, _ := strconv.ParseInt(preference, 10, 32) - i32 := int32(i64) exchange := mxrecord["exchange"].(string) - records[i] = dns.MxRecord{ - Preference: &i32, + records[i] = recordsets.MxRecord{ + Preference: &i64, Exchange: &exchange, } } diff --git a/internal/services/dns/dns_mx_record_resource_test.go b/internal/services/dns/dns_mx_record_resource_test.go index 1faacae7c566..3488d59c47f7 100644 --- a/internal/services/dns/dns_mx_record_resource_test.go +++ b/internal/services/dns/dns_mx_record_resource_test.go @@ -5,11 +5,10 @@ import ( "fmt" "testing" - "github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2018-05-01/dns" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -112,17 +111,17 @@ func TestAccAzureRMDnsMxRecord_withTags(t *testing.T) { } func (DnsMxRecordResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.MxRecordID(state.ID) + id, err := recordsets.ParseRecordTypeID(state.ID) if err != nil { return nil, err } - resp, err := clients.Dns.RecordSetsClient.Get(ctx, id.ResourceGroup, id.DnszoneName, id.MXName, dns.MX) + resp, err := clients.Dns.RecordSets.Get(ctx, *id) if err != nil { - return nil, fmt.Errorf("retrieving DNS MX record %s (resource group: %s): %v", id.MXName, id.ResourceGroup, err) + return nil, fmt.Errorf("retrieving %s: %+v", id, err) } - return utils.Bool(resp.RecordSetProperties != nil), nil + return utils.Bool(resp.Model != nil), nil } func (DnsMxRecordResource) basic(data acceptance.TestData) string { diff --git a/internal/services/dns/dns_ns_record_data_source.go b/internal/services/dns/dns_ns_record_data_source.go new file mode 100644 index 000000000000..e2a2cfc6fe85 --- /dev/null +++ b/internal/services/dns/dns_ns_record_data_source.go @@ -0,0 +1,96 @@ +package dns + +import ( + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" +) + +func dataSourceDnsNsRecord() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Read: dataSourceDnsNsRecordRead, + + Timeouts: &pluginsdk.ResourceTimeout{ + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "resource_group_name": commonschema.ResourceGroupNameForDataSource(), + + "zone_name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "records": { + Type: pluginsdk.TypeList, + Computed: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + }, + }, + + "ttl": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "fqdn": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "tags": commonschema.TagsDataSource(), + }, + } +} + +func dataSourceDnsNsRecordRead(d *pluginsdk.ResourceData, meta interface{}) error { + recordSetsClient := meta.(*clients.Client).Dns.RecordSets + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + + id := recordsets.NewRecordTypeID(subscriptionId, d.Get("resource_group_name").(string), d.Get("zone_name").(string), recordsets.RecordTypeNS, d.Get("name").(string)) + + resp, err := recordSetsClient.Get(ctx, id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return fmt.Errorf("%s was not found", id) + } + return fmt.Errorf("reading %s: %+v", id, err) + } + + d.SetId(id.ID()) + + d.Set("name", id.RelativeRecordSetName) + d.Set("resource_group_name", id.ResourceGroupName) + d.Set("zone_name", id.ZoneName) + + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("ttl", props.TTL) + d.Set("fqdn", props.Fqdn) + + if err := d.Set("records", flattenAzureRmDnsNsRecords(props.NSRecords)); err != nil { + return fmt.Errorf("settings `records`: %+v", err) + } + + return tags.FlattenAndSet(d, props.Metadata) + } + } + + return nil +} diff --git a/internal/services/dns/dns_ns_record_data_source_test.go b/internal/services/dns/dns_ns_record_data_source_test.go new file mode 100644 index 000000000000..2c19ae637224 --- /dev/null +++ b/internal/services/dns/dns_ns_record_data_source_test.go @@ -0,0 +1,43 @@ +package dns_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" +) + +type DnsNsRecordDataSource struct{} + +func TestAccDataSourceDnsNsRecord_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_dns_ns_record", "test") + r := DnsNsRecordDataSource{} + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("name").Exists(), + check.That(data.ResourceName).Key("resource_group_name").Exists(), + check.That(data.ResourceName).Key("zone_name").Exists(), + check.That(data.ResourceName).Key("records.#").HasValue("2"), + check.That(data.ResourceName).Key("ttl").Exists(), + check.That(data.ResourceName).Key("fqdn").Exists(), + check.That(data.ResourceName).Key("tags.%").HasValue("0"), + ), + }, + }) +} + +func (DnsNsRecordDataSource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +data "azurerm_dns_ns_record" "test" { + name = azurerm_dns_ns_record.test.name + resource_group_name = azurerm_resource_group.test.name + zone_name = azurerm_dns_zone.test.name +} +`, DnsNsRecordResource{}.basic(data)) +} diff --git a/internal/services/dns/dns_ns_record_resource.go b/internal/services/dns/dns_ns_record_resource.go index afe07c4ba3b3..d68c4415ed84 100644 --- a/internal/services/dns/dns_ns_record_resource.go +++ b/internal/services/dns/dns_ns_record_resource.go @@ -2,15 +2,14 @@ package dns import ( "fmt" - "net/http" "time" - "github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2018-05-01/dns" - "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/parse" - "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" "github.com/hashicorp/terraform-provider-azurerm/utils" @@ -30,8 +29,14 @@ func resourceDnsNsRecord() *pluginsdk.Resource { Delete: pluginsdk.DefaultTimeout(30 * time.Minute), }, Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - _, err := parse.NsRecordID(id) - return err + parsed, err := recordsets.ParseRecordTypeID(id) + if err != nil { + return err + } + if parsed.RecordType != recordsets.RecordTypeNS { + return fmt.Errorf("this resource only supports 'NS' records") + } + return nil }), Schema: map[string]*pluginsdk.Schema{ @@ -41,7 +46,7 @@ func resourceDnsNsRecord() *pluginsdk.Resource { ForceNew: true, }, - "resource_group_name": azure.SchemaResourceGroupName(), + "resource_group_name": commonschema.ResourceGroupName(), "zone_name": { Type: pluginsdk.TypeString, @@ -67,13 +72,13 @@ func resourceDnsNsRecord() *pluginsdk.Resource { Computed: true, }, - "tags": tags.Schema(), + "tags": commonschema.Tags(), }, } } func resourceDnsNsRecordCreate(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Dns.RecordSetsClient + client := meta.(*clients.Client).Dns.RecordSets ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) subscriptionId := meta.(*clients.Client).Account.SubscriptionId defer cancel() @@ -82,17 +87,16 @@ func resourceDnsNsRecordCreate(d *pluginsdk.ResourceData, meta interface{}) erro resGroup := d.Get("resource_group_name").(string) zoneName := d.Get("zone_name").(string) - resourceId := parse.NewNsRecordID(subscriptionId, resGroup, zoneName, name) - - existing, err := client.Get(ctx, resGroup, zoneName, name, dns.NS) + id := recordsets.NewRecordTypeID(subscriptionId, resGroup, zoneName, recordsets.RecordTypeNS, name) + existing, err := client.Get(ctx, id) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { - return fmt.Errorf("checking for presence of existing DNS NS Record %q (Zone %q / Resource Group %q): %s", name, zoneName, resGroup, err) + if !response.WasNotFound(existing.HttpResponse) { + return fmt.Errorf("checking for presence of existing %s: %+v", id, err) } } - if !utils.ResponseWasNotFound(existing.Response) { - return tf.ImportAsExistsError("azurerm_dns_ns_record", resourceId.ID()) + if !response.WasNotFound(existing.HttpResponse) { + return tf.ImportAsExistsError("azurerm_dns_ns_record", id.ID()) } ttl := int64(d.Get("ttl").(int)) @@ -101,123 +105,125 @@ func resourceDnsNsRecordCreate(d *pluginsdk.ResourceData, meta interface{}) erro recordsRaw := d.Get("records").([]interface{}) records := expandAzureRmDnsNsRecords(recordsRaw) - parameters := dns.RecordSet{ + parameters := recordsets.RecordSet{ Name: &name, - RecordSetProperties: &dns.RecordSetProperties{ + Properties: &recordsets.RecordSetProperties{ Metadata: tags.Expand(t), TTL: &ttl, - NsRecords: records, + NSRecords: records, }, } - eTag := "" - ifNoneMatch := "" // set to empty to allow updates to records after creation - if _, err := client.CreateOrUpdate(ctx, resGroup, zoneName, name, dns.NS, parameters, eTag, ifNoneMatch); err != nil { - return fmt.Errorf("creating DNS NS Record %q (Zone %q / Resource Group %q): %s", name, zoneName, resGroup, err) + if _, err := client.CreateOrUpdate(ctx, id, parameters, recordsets.DefaultCreateOrUpdateOperationOptions()); err != nil { + return fmt.Errorf("creating %s: %+v", id, err) } - d.SetId(resourceId.ID()) - + d.SetId(id.ID()) return resourceDnsNsRecordRead(d, meta) } func resourceDnsNsRecordUpdate(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Dns.RecordSetsClient + client := meta.(*clients.Client).Dns.RecordSets ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.NsRecordID(d.Id()) + id, err := recordsets.ParseRecordTypeID(d.Id()) if err != nil { return err } - existing, err := client.Get(ctx, id.ResourceGroup, id.DnszoneName, id.NSName, dns.NS) + existing, err := client.Get(ctx, *id) if err != nil { - return fmt.Errorf("retrieving NS %q (DNS Zone %q / Resource Group %q): %+v", id.NSName, id.DnszoneName, id.ResourceGroup, err) + return fmt.Errorf("retrieving %s: %+v", *id, err) } - - if existing.RecordSetProperties == nil { - return fmt.Errorf("retrieving NS %q (DNS Zone %q / Resource Group %q): `properties` was nil", id.NSName, id.DnszoneName, id.ResourceGroup) + if existing.Model == nil { + return fmt.Errorf("retrieving %s: `model` was nil", *id) + } + if existing.Model.Properties == nil { + return fmt.Errorf("retrieving %s: `properties` was nil", *id) } if d.HasChange("records") { recordsRaw := d.Get("records").([]interface{}) records := expandAzureRmDnsNsRecords(recordsRaw) - existing.RecordSetProperties.NsRecords = records + existing.Model.Properties.NSRecords = records } if d.HasChange("tags") { t := d.Get("tags").(map[string]interface{}) - existing.RecordSetProperties.Metadata = tags.Expand(t) + existing.Model.Properties.Metadata = tags.Expand(t) } if d.HasChange("ttl") { - existing.RecordSetProperties.TTL = utils.Int64(int64(d.Get("ttl").(int))) + existing.Model.Properties.TTL = utils.Int64(int64(d.Get("ttl").(int))) } - eTag := "" - ifNoneMatch := "" // set to empty to allow updates to records after creation - if _, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.DnszoneName, id.NSName, dns.NS, existing, eTag, ifNoneMatch); err != nil { - return fmt.Errorf("updating DNS NS Record %q (Zone %q / Resource Group %q): %s", id.NSName, id.DnszoneName, id.ResourceGroup, err) + if _, err := client.Update(ctx, *id, *existing.Model, recordsets.DefaultUpdateOperationOptions()); err != nil { + return fmt.Errorf("updating %s: %+v", *id, err) } return resourceDnsNsRecordRead(d, meta) } func resourceDnsNsRecordRead(d *pluginsdk.ResourceData, meta interface{}) error { - dnsClient := meta.(*clients.Client).Dns.RecordSetsClient + client := meta.(*clients.Client).Dns.RecordSets ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.NsRecordID(d.Id()) + id, err := recordsets.ParseRecordTypeIDInsensitively(d.Id()) if err != nil { return err } - resp, err := dnsClient.Get(ctx, id.ResourceGroup, id.DnszoneName, id.NSName, dns.NS) + resp, err := client.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { d.SetId("") return nil } - return fmt.Errorf("reading DNS NS record %s: %+v", id.NSName, err) + return fmt.Errorf("retrieving %s: %+v", *id, err) } - d.Set("name", id.NSName) - d.Set("resource_group_name", id.ResourceGroup) - d.Set("zone_name", id.DnszoneName) + d.Set("name", id.RelativeRecordSetName) + d.Set("resource_group_name", id.ResourceGroupName) + d.Set("zone_name", id.ZoneName) - d.Set("ttl", resp.TTL) - d.Set("fqdn", resp.Fqdn) + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("ttl", props.TTL) + d.Set("fqdn", props.Fqdn) - if props := resp.RecordSetProperties; props != nil { - if err := d.Set("records", flattenAzureRmDnsNsRecords(props.NsRecords)); err != nil { - return fmt.Errorf("settings `records`: %+v", err) + if err := d.Set("records", flattenAzureRmDnsNsRecords(props.NSRecords)); err != nil { + return fmt.Errorf("settings `records`: %+v", err) + } + + if err := tags.FlattenAndSet(d, props.Metadata); err != nil { + return err + } } } - return tags.FlattenAndSet(d, resp.Metadata) + return nil } func resourceDnsNsRecordDelete(d *pluginsdk.ResourceData, meta interface{}) error { - dnsClient := meta.(*clients.Client).Dns.RecordSetsClient + client := meta.(*clients.Client).Dns.RecordSets ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.NsRecordID(d.Id()) + id, err := recordsets.ParseRecordTypeID(d.Id()) if err != nil { return err } - resp, err := dnsClient.Delete(ctx, id.ResourceGroup, id.DnszoneName, id.NSName, dns.NS, "") - if resp.StatusCode != http.StatusOK { - return fmt.Errorf("deleting DNS NS Record %s: %+v", id.NSName, err) + if _, err := client.Delete(ctx, *id, recordsets.DefaultDeleteOperationOptions()); err != nil { + return fmt.Errorf("deleting %s: %+v", *id, err) } return nil } -func flattenAzureRmDnsNsRecords(records *[]dns.NsRecord) []interface{} { +func flattenAzureRmDnsNsRecords(records *[]recordsets.NsRecord) []interface{} { if records == nil { return []interface{}{} } @@ -234,16 +240,14 @@ func flattenAzureRmDnsNsRecords(records *[]dns.NsRecord) []interface{} { return results } -func expandAzureRmDnsNsRecords(input []interface{}) *[]dns.NsRecord { - records := make([]dns.NsRecord, len(input)) - for i, v := range input { +func expandAzureRmDnsNsRecords(input []interface{}) *[]recordsets.NsRecord { + records := make([]recordsets.NsRecord, 0) + for _, v := range input { record := v.(string) - nsRecord := dns.NsRecord{ + records = append(records, recordsets.NsRecord{ Nsdname: &record, - } - - records[i] = nsRecord + }) } return &records } diff --git a/internal/services/dns/dns_ns_record_resource_test.go b/internal/services/dns/dns_ns_record_resource_test.go index 4fb91dc6d7c2..a07dd24a9f27 100644 --- a/internal/services/dns/dns_ns_record_resource_test.go +++ b/internal/services/dns/dns_ns_record_resource_test.go @@ -5,11 +5,10 @@ import ( "fmt" "testing" - "github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2018-05-01/dns" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -96,17 +95,17 @@ func TestAccDnsNsRecord_withTags(t *testing.T) { } func (DnsNsRecordResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.NsRecordID(state.ID) + id, err := recordsets.ParseRecordTypeID(state.ID) if err != nil { return nil, err } - resp, err := clients.Dns.RecordSetsClient.Get(ctx, id.ResourceGroup, id.DnszoneName, id.NSName, dns.NS) + resp, err := clients.Dns.RecordSets.Get(ctx, *id) if err != nil { - return nil, fmt.Errorf("retrieving DNS NS record %s (resource group: %s): %v", id.NSName, id.ResourceGroup, err) + return nil, fmt.Errorf("retrieving %s: %+v", *id, err) } - return utils.Bool(resp.RecordSetProperties != nil), nil + return utils.Bool(resp.Model != nil), nil } func (DnsNsRecordResource) basic(data acceptance.TestData) string { diff --git a/internal/services/dns/dns_ptr_record_data_source.go b/internal/services/dns/dns_ptr_record_data_source.go new file mode 100644 index 000000000000..b323c1a19069 --- /dev/null +++ b/internal/services/dns/dns_ptr_record_data_source.go @@ -0,0 +1,95 @@ +package dns + +import ( + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" +) + +func dataSourceDnsPtrRecord() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Read: dataSourceDnsPtrRecordRead, + + Timeouts: &pluginsdk.ResourceTimeout{ + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "resource_group_name": commonschema.ResourceGroupNameForDataSource(), + + "zone_name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "records": { + Type: pluginsdk.TypeSet, + Computed: true, + Elem: &pluginsdk.Schema{Type: pluginsdk.TypeString}, + Set: pluginsdk.HashString, + }, + + "ttl": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "fqdn": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "tags": commonschema.TagsDataSource(), + }, + } +} + +func dataSourceDnsPtrRecordRead(d *pluginsdk.ResourceData, meta interface{}) error { + recordSetsClient := meta.(*clients.Client).Dns.RecordSets + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + + id := recordsets.NewRecordTypeID(subscriptionId, d.Get("resource_group_name").(string), d.Get("zone_name").(string), recordsets.RecordTypePTR, d.Get("name").(string)) + + resp, err := recordSetsClient.Get(ctx, id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return fmt.Errorf("%s was not found", id) + } + return fmt.Errorf("reading %s: %+v", id, err) + } + + d.SetId(id.ID()) + + d.Set("name", id.RelativeRecordSetName) + d.Set("resource_group_name", id.ResourceGroupName) + d.Set("zone_name", id.ZoneName) + + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("ttl", props.TTL) + d.Set("fqdn", props.Fqdn) + + if err := d.Set("records", flattenAzureRmDnsPtrRecords(props.PTRRecords)); err != nil { + return err + } + + return tags.FlattenAndSet(d, props.Metadata) + } + } + + return nil +} diff --git a/internal/services/dns/dns_ptr_record_data_source_test.go b/internal/services/dns/dns_ptr_record_data_source_test.go new file mode 100644 index 000000000000..289069ad6dac --- /dev/null +++ b/internal/services/dns/dns_ptr_record_data_source_test.go @@ -0,0 +1,43 @@ +package dns_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" +) + +type DnsPtrRecordDataSource struct{} + +func TestAccDataSourceDnsPtrRecord_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_dns_ptr_record", "test") + r := DnsPtrRecordDataSource{} + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("name").Exists(), + check.That(data.ResourceName).Key("resource_group_name").Exists(), + check.That(data.ResourceName).Key("zone_name").Exists(), + check.That(data.ResourceName).Key("records.#").HasValue("2"), + check.That(data.ResourceName).Key("ttl").Exists(), + check.That(data.ResourceName).Key("fqdn").Exists(), + check.That(data.ResourceName).Key("tags.%").HasValue("0"), + ), + }, + }) +} + +func (DnsPtrRecordDataSource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +data "azurerm_dns_ptr_record" "test" { + name = azurerm_dns_ptr_record.test.name + resource_group_name = azurerm_resource_group.test.name + zone_name = azurerm_dns_zone.test.name +} +`, DnsPtrRecordResource{}.basic(data)) +} diff --git a/internal/services/dns/dns_ptr_record_resource.go b/internal/services/dns/dns_ptr_record_resource.go index de7e5c38e829..8b69bf27b4e4 100644 --- a/internal/services/dns/dns_ptr_record_resource.go +++ b/internal/services/dns/dns_ptr_record_resource.go @@ -2,18 +2,16 @@ package dns import ( "fmt" - "net/http" "time" - "github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2018-05-01/dns" - "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/parse" - "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" - "github.com/hashicorp/terraform-provider-azurerm/utils" ) func resourceDnsPtrRecord() *pluginsdk.Resource { @@ -31,8 +29,14 @@ func resourceDnsPtrRecord() *pluginsdk.Resource { }, Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - _, err := parse.PtrRecordID(id) - return err + parsed, err := recordsets.ParseRecordTypeID(id) + if err != nil { + return err + } + if parsed.RecordType != recordsets.RecordTypePTR { + return fmt.Errorf("this resource only supports 'PTR' records") + } + return nil }), Schema: map[string]*pluginsdk.Schema{ "name": { @@ -41,11 +45,12 @@ func resourceDnsPtrRecord() *pluginsdk.Resource { ForceNew: true, }, - "resource_group_name": azure.SchemaResourceGroupName(), + "resource_group_name": commonschema.ResourceGroupName(), "zone_name": { Type: pluginsdk.TypeString, Required: true, + ForceNew: true, }, "records": { @@ -65,13 +70,13 @@ func resourceDnsPtrRecord() *pluginsdk.Resource { Computed: true, }, - "tags": tags.Schema(), + "tags": commonschema.Tags(), }, } } func resourceDnsPtrRecordCreateUpdate(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Dns.RecordSetsClient + client := meta.(*clients.Client).Dns.RecordSets ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) subscriptionId := meta.(*clients.Client).Account.SubscriptionId defer cancel() @@ -80,104 +85,106 @@ func resourceDnsPtrRecordCreateUpdate(d *pluginsdk.ResourceData, meta interface{ resGroup := d.Get("resource_group_name").(string) zoneName := d.Get("zone_name").(string) - resourceId := parse.NewPtrRecordID(subscriptionId, resGroup, zoneName, name) - + id := recordsets.NewRecordTypeID(subscriptionId, resGroup, zoneName, recordsets.RecordTypePTR, name) if d.IsNewResource() { - existing, err := client.Get(ctx, resGroup, zoneName, name, dns.PTR) + existing, err := client.Get(ctx, id) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { - return fmt.Errorf("checking for presence of existing DNS PTR Record %q (Zone %q / Resource Group %q): %s", name, zoneName, resGroup, err) + if !response.WasNotFound(existing.HttpResponse) { + return fmt.Errorf("checking for presence of existing %s: %+v", id, err) } } - if !utils.ResponseWasNotFound(existing.Response) { - return tf.ImportAsExistsError("azurerm_dns_ptr_record", resourceId.ID()) + if !response.WasNotFound(existing.HttpResponse) { + return tf.ImportAsExistsError("azurerm_dns_ptr_record", id.ID()) } } ttl := int64(d.Get("ttl").(int)) t := d.Get("tags").(map[string]interface{}) - parameters := dns.RecordSet{ - RecordSetProperties: &dns.RecordSetProperties{ + parameters := recordsets.RecordSet{ + Properties: &recordsets.RecordSetProperties{ Metadata: tags.Expand(t), TTL: &ttl, - PtrRecords: expandAzureRmDnsPtrRecords(d), + PTRRecords: expandAzureRmDnsPtrRecords(d), }, } - eTag := "" - ifNoneMatch := "" // set to empty to allow updates to records after creation - if _, err := client.CreateOrUpdate(ctx, resGroup, zoneName, name, dns.PTR, parameters, eTag, ifNoneMatch); err != nil { - return fmt.Errorf("creating/updating DNS PTR Record %q (Zone %q / Resource Group %q): %s", name, zoneName, resGroup, err) + if _, err := client.CreateOrUpdate(ctx, id, parameters, recordsets.DefaultCreateOrUpdateOperationOptions()); err != nil { + return fmt.Errorf("creating/updating %s: %+v", id, err) } - d.SetId(resourceId.ID()) - + d.SetId(id.ID()) return resourceDnsPtrRecordRead(d, meta) } func resourceDnsPtrRecordRead(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client) - dnsClient := client.Dns.RecordSetsClient + client := meta.(*clients.Client).Dns.RecordSets ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.PtrRecordID(d.Id()) + id, err := recordsets.ParseRecordTypeIDInsensitively(d.Id()) if err != nil { return err } - resp, err := dnsClient.Get(ctx, id.ResourceGroup, id.DnszoneName, id.PTRName, dns.PTR) + resp, err := client.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { d.SetId("") return nil } - return fmt.Errorf("reading DNS PTR record %s: %+v", id.PTRName, err) + return fmt.Errorf("retrieving %s: %+v", *id, err) } - d.Set("name", id.PTRName) - d.Set("resource_group_name", id.ResourceGroup) - d.Set("zone_name", id.DnszoneName) - d.Set("ttl", resp.TTL) - d.Set("fqdn", resp.Fqdn) + d.Set("name", id.RelativeRecordSetName) + d.Set("resource_group_name", id.ResourceGroupName) + d.Set("zone_name", id.ZoneName) - if err := d.Set("records", flattenAzureRmDnsPtrRecords(resp.PtrRecords)); err != nil { - return err + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("ttl", props.TTL) + d.Set("fqdn", props.Fqdn) + + if err := d.Set("records", flattenAzureRmDnsPtrRecords(props.PTRRecords)); err != nil { + return err + } + if err := tags.FlattenAndSet(d, props.Metadata); err != nil { + return err + } + } } - return tags.FlattenAndSet(d, resp.Metadata) + + return nil } func resourceDnsPtrRecordDelete(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client) - dnsClient := client.Dns.RecordSetsClient + client := meta.(*clients.Client).Dns.RecordSets ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.PtrRecordID(d.Id()) + id, err := recordsets.ParseRecordTypeID(d.Id()) if err != nil { return err } - resp, err := dnsClient.Delete(ctx, id.ResourceGroup, id.DnszoneName, id.PTRName, dns.PTR, "") - if err != nil { - if resp.StatusCode == http.StatusNotFound { - return nil - } - - return fmt.Errorf("deleting DNS PTR Record %s: %+v", id.PTRName, err) + if _, err := client.Delete(ctx, *id, recordsets.DefaultDeleteOperationOptions()); err != nil { + return fmt.Errorf("deleting %s: %+v", *id, err) } return nil } -func flattenAzureRmDnsPtrRecords(records *[]dns.PtrRecord) []string { +func flattenAzureRmDnsPtrRecords(records *[]recordsets.PtrRecord) []string { results := make([]string, 0) if records != nil { for _, record := range *records { + if record.Ptrdname == nil { + continue + } + results = append(results, *record.Ptrdname) } } @@ -185,15 +192,15 @@ func flattenAzureRmDnsPtrRecords(records *[]dns.PtrRecord) []string { return results } -func expandAzureRmDnsPtrRecords(d *pluginsdk.ResourceData) *[]dns.PtrRecord { +func expandAzureRmDnsPtrRecords(d *pluginsdk.ResourceData) *[]recordsets.PtrRecord { recordStrings := d.Get("records").(*pluginsdk.Set).List() - records := make([]dns.PtrRecord, len(recordStrings)) + records := make([]recordsets.PtrRecord, 0) - for i, v := range recordStrings { + for _, v := range recordStrings { fqdn := v.(string) - records[i] = dns.PtrRecord{ + records = append(records, recordsets.PtrRecord{ Ptrdname: &fqdn, - } + }) } return &records diff --git a/internal/services/dns/dns_ptr_record_resource_test.go b/internal/services/dns/dns_ptr_record_resource_test.go index 37e964e91c96..433002f635ed 100644 --- a/internal/services/dns/dns_ptr_record_resource_test.go +++ b/internal/services/dns/dns_ptr_record_resource_test.go @@ -5,11 +5,10 @@ import ( "fmt" "testing" - "github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2018-05-01/dns" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -98,17 +97,17 @@ func TestAccDnsPtrRecord_withTags(t *testing.T) { } func (DnsPtrRecordResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.PtrRecordID(state.ID) + id, err := recordsets.ParseRecordTypeID(state.ID) if err != nil { return nil, err } - resp, err := clients.Dns.RecordSetsClient.Get(ctx, id.ResourceGroup, id.DnszoneName, id.PTRName, dns.PTR) + resp, err := clients.Dns.RecordSets.Get(ctx, *id) if err != nil { - return nil, fmt.Errorf("retrieving DNS PTR record %s (resource group: %s): %v", id.PTRName, id.ResourceGroup, err) + return nil, fmt.Errorf("retrieving %s: %+v", *id, err) } - return utils.Bool(resp.RecordSetProperties != nil), nil + return utils.Bool(resp.Model != nil), nil } func (DnsPtrRecordResource) basic(data acceptance.TestData) string { diff --git a/internal/services/dns/dns_soa_record_data_source.go b/internal/services/dns/dns_soa_record_data_source.go new file mode 100644 index 000000000000..119408e67a5d --- /dev/null +++ b/internal/services/dns/dns_soa_record_data_source.go @@ -0,0 +1,129 @@ +package dns + +import ( + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" +) + +func dataSourceDnsSoaRecord() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Read: dataSourceDnsSoaRecordRead, + + Timeouts: &pluginsdk.ResourceTimeout{ + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Optional: true, + Default: "@", + }, + + "resource_group_name": commonschema.ResourceGroupNameForDataSource(), + + "zone_name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "email": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "host_name": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "expire_time": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "minimum_ttl": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "refresh_time": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "retry_time": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "serial_number": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "ttl": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "fqdn": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "tags": commonschema.TagsDataSource(), + }, + } +} + +func dataSourceDnsSoaRecordRead(d *pluginsdk.ResourceData, meta interface{}) error { + recordSetsClient := meta.(*clients.Client).Dns.RecordSets + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + + id := recordsets.NewRecordTypeID(subscriptionId, d.Get("resource_group_name").(string), d.Get("zone_name").(string), recordsets.RecordTypeSOA, "@") + resp, err := recordSetsClient.Get(ctx, id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return fmt.Errorf("%s was not found", id) + } + return fmt.Errorf("reading %s: %+v", id, err) + } + + d.SetId(id.ID()) + + d.Set("resource_group_name", id.ResourceGroupName) + d.Set("zone_name", id.ZoneName) + + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("ttl", props.TTL) + d.Set("fqdn", props.Fqdn) + + if soaRecord := props.SOARecord; soaRecord != nil { + d.Set("email", soaRecord.Email) + d.Set("host_name", soaRecord.Host) + d.Set("expire_time", soaRecord.ExpireTime) + d.Set("minimum_ttl", soaRecord.MinimumTTL) + d.Set("refresh_time", soaRecord.RefreshTime) + d.Set("retry_time", soaRecord.RetryTime) + d.Set("serial_number", soaRecord.SerialNumber) + } + + return tags.FlattenAndSet(d, props.Metadata) + } + + } + + return nil +} diff --git a/internal/services/dns/dns_soa_record_data_source_test.go b/internal/services/dns/dns_soa_record_data_source_test.go new file mode 100644 index 000000000000..21272538a98d --- /dev/null +++ b/internal/services/dns/dns_soa_record_data_source_test.go @@ -0,0 +1,72 @@ +package dns_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" +) + +type DnsSoaRecordDataSource struct{} + +func TestAccDataSourceDnsSoaRecord_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_dns_soa_record", "test") + r := DnsSoaRecordDataSource{} + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: r.basicWithDataSource(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("resource_group_name").Exists(), + check.That(data.ResourceName).Key("zone_name").Exists(), + check.That(data.ResourceName).Key("fqdn").Exists(), + check.That(data.ResourceName).Key("name").HasValue("@"), + check.That(data.ResourceName).Key("email").HasValue("testemail.com"), + check.That(data.ResourceName).Key("host_name").HasValue("testhost.contoso.com"), + check.That(data.ResourceName).Key("expire_time").HasValue("2419200"), + check.That(data.ResourceName).Key("minimum_ttl").HasValue("300"), + check.That(data.ResourceName).Key("refresh_time").HasValue("3600"), + check.That(data.ResourceName).Key("retry_time").HasValue("300"), + check.That(data.ResourceName).Key("serial_number").HasValue("1"), + check.That(data.ResourceName).Key("ttl").HasValue("3600"), + check.That(data.ResourceName).Key("tags.%").HasValue("0"), + ), + }, + }) +} + +func (DnsSoaRecordDataSource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_dns_zone" "test" { + name = "acctestzone%d.com" + resource_group_name = azurerm_resource_group.test.name + + soa_record { + email = "testemail.com" + host_name = "testhost.contoso.com" + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger) +} + +func (d DnsSoaRecordDataSource) basicWithDataSource(data acceptance.TestData) string { + config := d.basic(data) + return fmt.Sprintf(` +%s + +data "azurerm_dns_soa_record" "test" { + resource_group_name = azurerm_resource_group.test.name + zone_name = azurerm_dns_zone.test.name +} +`, config) +} diff --git a/internal/services/dns/dns_srv_record_data_source.go b/internal/services/dns/dns_srv_record_data_source.go new file mode 100644 index 000000000000..504f8597c610 --- /dev/null +++ b/internal/services/dns/dns_srv_record_data_source.go @@ -0,0 +1,116 @@ +package dns + +import ( + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" +) + +func dataSourceDnsSrvRecord() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Read: dataSourceDnsSrvRecordRead, + + Timeouts: &pluginsdk.ResourceTimeout{ + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "resource_group_name": commonschema.ResourceGroupNameForDataSource(), + + "zone_name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "record": { + Type: pluginsdk.TypeSet, + Computed: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "priority": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "weight": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "port": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "target": { + Type: pluginsdk.TypeString, + Computed: true, + }, + }, + }, + Set: resourceDnsSrvRecordHash, + }, + + "ttl": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "fqdn": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "tags": commonschema.TagsDataSource(), + }, + } +} + +func dataSourceDnsSrvRecordRead(d *pluginsdk.ResourceData, meta interface{}) error { + recordSetsClient := meta.(*clients.Client).Dns.RecordSets + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + + id := recordsets.NewRecordTypeID(subscriptionId, d.Get("resource_group_name").(string), d.Get("zone_name").(string), recordsets.RecordTypeSRV, d.Get("name").(string)) + resp, err := recordSetsClient.Get(ctx, id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return fmt.Errorf("%s was not found", id) + } + return fmt.Errorf("reading %s: %+v", id, err) + } + + d.SetId(id.ID()) + + d.Set("name", id.RelativeRecordSetName) + d.Set("resource_group_name", id.ResourceGroupName) + d.Set("zone_name", id.ZoneName) + + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("ttl", props.TTL) + d.Set("fqdn", props.Fqdn) + + if err := d.Set("record", flattenAzureRmDnsSrvRecords(props.SRVRecords)); err != nil { + return err + } + + return tags.FlattenAndSet(d, props.Metadata) + } + } + + return nil +} diff --git a/internal/services/dns/dns_srv_record_data_source_test.go b/internal/services/dns/dns_srv_record_data_source_test.go new file mode 100644 index 000000000000..0383638279b9 --- /dev/null +++ b/internal/services/dns/dns_srv_record_data_source_test.go @@ -0,0 +1,43 @@ +package dns_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" +) + +type DnsSrvRecordDataSource struct{} + +func TestAccDataSourceDnsSrvRecord_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_dns_srv_record", "test") + r := DnsSrvRecordDataSource{} + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("name").Exists(), + check.That(data.ResourceName).Key("resource_group_name").Exists(), + check.That(data.ResourceName).Key("zone_name").Exists(), + check.That(data.ResourceName).Key("record.#").HasValue("2"), + check.That(data.ResourceName).Key("ttl").Exists(), + check.That(data.ResourceName).Key("fqdn").Exists(), + check.That(data.ResourceName).Key("tags.%").HasValue("0"), + ), + }, + }) +} + +func (DnsSrvRecordDataSource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +data "azurerm_dns_srv_record" "test" { + name = azurerm_dns_srv_record.test.name + resource_group_name = azurerm_resource_group.test.name + zone_name = azurerm_dns_zone.test.name +} +`, DnsSrvRecordResource{}.basic(data)) +} diff --git a/internal/services/dns/dns_srv_record_resource.go b/internal/services/dns/dns_srv_record_resource.go index 5616eaeb8047..025fd126fd52 100644 --- a/internal/services/dns/dns_srv_record_resource.go +++ b/internal/services/dns/dns_srv_record_resource.go @@ -3,18 +3,16 @@ package dns import ( "bytes" "fmt" - "net/http" "time" - "github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2018-05-01/dns" - "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/parse" - "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" - "github.com/hashicorp/terraform-provider-azurerm/utils" ) func resourceDnsSrvRecord() *pluginsdk.Resource { @@ -31,8 +29,14 @@ func resourceDnsSrvRecord() *pluginsdk.Resource { Delete: pluginsdk.DefaultTimeout(30 * time.Minute), }, Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - _, err := parse.SrvRecordID(id) - return err + parsed, err := recordsets.ParseRecordTypeID(id) + if err != nil { + return err + } + if parsed.RecordType != recordsets.RecordTypeSRV { + return fmt.Errorf("this resource only supports 'SRV' records") + } + return nil }), Schema: map[string]*pluginsdk.Schema{ "name": { @@ -41,11 +45,12 @@ func resourceDnsSrvRecord() *pluginsdk.Resource { ForceNew: true, }, - "resource_group_name": azure.SchemaResourceGroupName(), + "resource_group_name": commonschema.ResourceGroupName(), "zone_name": { Type: pluginsdk.TypeString, Required: true, + ForceNew: true, }, "record": { @@ -87,13 +92,13 @@ func resourceDnsSrvRecord() *pluginsdk.Resource { Computed: true, }, - "tags": tags.Schema(), + "tags": commonschema.Tags(), }, } } func resourceDnsSrvRecordCreateUpdate(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Dns.RecordSetsClient + client := meta.(*clients.Client).Dns.RecordSets ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) subscriptionId := meta.(*clients.Client).Account.SubscriptionId defer cancel() @@ -102,103 +107,129 @@ func resourceDnsSrvRecordCreateUpdate(d *pluginsdk.ResourceData, meta interface{ resGroup := d.Get("resource_group_name").(string) zoneName := d.Get("zone_name").(string) - resourceId := parse.NewSrvRecordID(subscriptionId, resGroup, zoneName, name) - + id := recordsets.NewRecordTypeID(subscriptionId, resGroup, zoneName, recordsets.RecordTypeSRV, name) if d.IsNewResource() { - existing, err := client.Get(ctx, resGroup, zoneName, name, dns.SRV) + existing, err := client.Get(ctx, id) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { - return fmt.Errorf("checking for presence of existing DNS SRV Record %q (Zone %q / Resource Group %q): %s", name, zoneName, resGroup, err) + if !response.WasNotFound(existing.HttpResponse) { + return fmt.Errorf("checking for presence of existing %s: %+v", id, err) } } - if !utils.ResponseWasNotFound(existing.Response) { - return tf.ImportAsExistsError("azurerm_dns_srv_record", resourceId.ID()) + if !response.WasNotFound(existing.HttpResponse) { + return tf.ImportAsExistsError("azurerm_dns_srv_record", id.ID()) } } ttl := int64(d.Get("ttl").(int)) t := d.Get("tags").(map[string]interface{}) - parameters := dns.RecordSet{ + parameters := recordsets.RecordSet{ Name: &name, - RecordSetProperties: &dns.RecordSetProperties{ + Properties: &recordsets.RecordSetProperties{ Metadata: tags.Expand(t), TTL: &ttl, - SrvRecords: expandAzureRmDnsSrvRecords(d), + SRVRecords: expandAzureRmDnsSrvRecords(d), }, } - eTag := "" - ifNoneMatch := "" // set to empty to allow updates to records after creation - if _, err := client.CreateOrUpdate(ctx, resGroup, zoneName, name, dns.SRV, parameters, eTag, ifNoneMatch); err != nil { + if _, err := client.CreateOrUpdate(ctx, id, parameters, recordsets.DefaultCreateOrUpdateOperationOptions()); err != nil { return fmt.Errorf("creating/updating DNS SRV Record %q (Zone %q / Resource Group %q): %s", name, zoneName, resGroup, err) } - d.SetId(resourceId.ID()) + d.SetId(id.ID()) return resourceDnsSrvRecordRead(d, meta) } func resourceDnsSrvRecordRead(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Dns.RecordSetsClient + client := meta.(*clients.Client).Dns.RecordSets ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.SrvRecordID(d.Id()) + id, err := recordsets.ParseRecordTypeIDInsensitively(d.Id()) if err != nil { return err } - resp, err := client.Get(ctx, id.ResourceGroup, id.DnszoneName, id.SRVName, dns.SRV) + resp, err := client.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { d.SetId("") return nil } - return fmt.Errorf("reading DNS SRV record %s: %v", id.SRVName, err) + + return fmt.Errorf("retrieving %s: %+v", *id, err) } - d.Set("name", id.SRVName) - d.Set("resource_group_name", id.ResourceGroup) - d.Set("zone_name", id.DnszoneName) - d.Set("ttl", resp.TTL) - d.Set("fqdn", resp.Fqdn) + d.Set("name", id.RelativeRecordSetName) + d.Set("resource_group_name", id.ResourceGroupName) + d.Set("zone_name", id.ZoneName) - if err := d.Set("record", flattenAzureRmDnsSrvRecords(resp.SrvRecords)); err != nil { - return err + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("ttl", props.TTL) + d.Set("fqdn", props.Fqdn) + + if err := d.Set("record", flattenAzureRmDnsSrvRecords(props.SRVRecords)); err != nil { + return err + } + if err := tags.FlattenAndSet(d, props.Metadata); err != nil { + return err + } + } } - return tags.FlattenAndSet(d, resp.Metadata) + + return nil } func resourceDnsSrvRecordDelete(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Dns.RecordSetsClient + client := meta.(*clients.Client).Dns.RecordSets ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.SrvRecordID(d.Id()) + id, err := recordsets.ParseRecordTypeID(d.Id()) if err != nil { return err } - resp, err := client.Delete(ctx, id.ResourceGroup, id.DnszoneName, id.SRVName, dns.SRV, "") - if resp.StatusCode != http.StatusOK { - return fmt.Errorf("deleting DNS SRV Record %s: %+v", id.SRVName, err) + if _, err := client.Delete(ctx, *id, recordsets.DefaultDeleteOperationOptions()); err != nil { + return fmt.Errorf("deleting %s: %+v", *id, err) } return nil } -func flattenAzureRmDnsSrvRecords(records *[]dns.SrvRecord) []map[string]interface{} { +func flattenAzureRmDnsSrvRecords(records *[]recordsets.SrvRecord) []map[string]interface{} { results := make([]map[string]interface{}, 0) if records != nil { for _, record := range *records { + port := int64(0) + if record.Port != nil { + port = *record.Port + } + + priority := int64(0) + if record.Priority != nil { + priority = *record.Priority + } + + target := "" + if record.Target != nil { + target = *record.Target + } + + weight := int64(0) + if record.Weight != nil { + weight = *record.Weight + } + results = append(results, map[string]interface{}{ - "priority": *record.Priority, - "weight": *record.Weight, - "port": *record.Port, - "target": *record.Target, + "port": port, + "priority": priority, + "target": target, + "weight": weight, }) } } @@ -206,25 +237,23 @@ func flattenAzureRmDnsSrvRecords(records *[]dns.SrvRecord) []map[string]interfac return results } -func expandAzureRmDnsSrvRecords(d *pluginsdk.ResourceData) *[]dns.SrvRecord { +func expandAzureRmDnsSrvRecords(d *pluginsdk.ResourceData) *[]recordsets.SrvRecord { recordStrings := d.Get("record").(*pluginsdk.Set).List() - records := make([]dns.SrvRecord, len(recordStrings)) + records := make([]recordsets.SrvRecord, 0) - for i, v := range recordStrings { + for _, v := range recordStrings { record := v.(map[string]interface{}) - priority := int32(record["priority"].(int)) - weight := int32(record["weight"].(int)) - port := int32(record["port"].(int)) + priority := int64(record["priority"].(int)) + weight := int64(record["weight"].(int)) + port := int64(record["port"].(int)) target := record["target"].(string) - srvRecord := dns.SrvRecord{ + records = append(records, recordsets.SrvRecord{ Priority: &priority, Weight: &weight, Port: &port, Target: &target, - } - - records[i] = srvRecord + }) } return &records diff --git a/internal/services/dns/dns_srv_record_resource_test.go b/internal/services/dns/dns_srv_record_resource_test.go index bbf0f360dc1e..dcda2b2c4e0f 100644 --- a/internal/services/dns/dns_srv_record_resource_test.go +++ b/internal/services/dns/dns_srv_record_resource_test.go @@ -5,11 +5,10 @@ import ( "fmt" "testing" - "github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2018-05-01/dns" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -96,17 +95,17 @@ func TestAccDnsSrvRecord_withTags(t *testing.T) { } func (DnsSrvRecordResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.SrvRecordID(state.ID) + id, err := recordsets.ParseRecordTypeID(state.ID) if err != nil { return nil, err } - resp, err := clients.Dns.RecordSetsClient.Get(ctx, id.ResourceGroup, id.DnszoneName, id.SRVName, dns.SRV) + resp, err := clients.Dns.RecordSets.Get(ctx, *id) if err != nil { - return nil, fmt.Errorf("retrieving DNS SRV record %s (resource group: %s): %v", id.SRVName, id.ResourceGroup, err) + return nil, fmt.Errorf("retrieving %s: %+v", *id, err) } - return utils.Bool(resp.RecordSetProperties != nil), nil + return utils.Bool(resp.Model != nil), nil } func (DnsSrvRecordResource) basic(data acceptance.TestData) string { diff --git a/internal/services/dns/dns_txt_record_data_source.go b/internal/services/dns/dns_txt_record_data_source.go new file mode 100644 index 000000000000..1168e6e66af5 --- /dev/null +++ b/internal/services/dns/dns_txt_record_data_source.go @@ -0,0 +1,102 @@ +package dns + +import ( + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" +) + +func dataSourceDnsTxtRecord() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Read: dataSourceDnsTxtRecordRead, + + Timeouts: &pluginsdk.ResourceTimeout{ + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "resource_group_name": commonschema.ResourceGroupNameForDataSource(), + + "zone_name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "record": { + Type: pluginsdk.TypeSet, + Computed: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "value": { + Type: pluginsdk.TypeString, + Computed: true, + }, + }, + }, + }, + + "ttl": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "fqdn": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "tags": commonschema.TagsDataSource(), + }, + } +} + +func dataSourceDnsTxtRecordRead(d *pluginsdk.ResourceData, meta interface{}) error { + recordSetsClient := meta.(*clients.Client).Dns.RecordSets + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + + id := recordsets.NewRecordTypeID(subscriptionId, d.Get("resource_group_name").(string), d.Get("zone_name").(string), recordsets.RecordTypeTXT, d.Get("name").(string)) + + resp, err := recordSetsClient.Get(ctx, id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return fmt.Errorf("%s was not found", id) + } + return fmt.Errorf("reading %s: %+v", id, err) + } + + d.SetId(id.ID()) + + d.Set("name", id.RelativeRecordSetName) + d.Set("resource_group_name", id.ResourceGroupName) + d.Set("zone_name", id.ZoneName) + + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("ttl", props.TTL) + d.Set("fqdn", props.Fqdn) + + if err := d.Set("record", flattenAzureRmDnsTxtRecords(props.TXTRecords)); err != nil { + return err + } + + return tags.FlattenAndSet(d, props.Metadata) + + } + } + + return nil +} diff --git a/internal/services/dns/dns_txt_record_data_source_test.go b/internal/services/dns/dns_txt_record_data_source_test.go new file mode 100644 index 000000000000..34937ee4f2ab --- /dev/null +++ b/internal/services/dns/dns_txt_record_data_source_test.go @@ -0,0 +1,43 @@ +package dns_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" +) + +type DnsTxtRecordDataSource struct{} + +func TestAccDataSourceDnsTxtRecord_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_dns_txt_record", "test") + r := DnsTxtRecordDataSource{} + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("name").Exists(), + check.That(data.ResourceName).Key("resource_group_name").Exists(), + check.That(data.ResourceName).Key("zone_name").Exists(), + check.That(data.ResourceName).Key("record.#").HasValue("2"), + check.That(data.ResourceName).Key("ttl").Exists(), + check.That(data.ResourceName).Key("fqdn").Exists(), + check.That(data.ResourceName).Key("tags.%").HasValue("0"), + ), + }, + }) +} + +func (DnsTxtRecordDataSource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +data "azurerm_dns_txt_record" "test" { + name = azurerm_dns_txt_record.test.name + resource_group_name = azurerm_resource_group.test.name + zone_name = azurerm_dns_zone.test.name +} +`, DnsTxtRecordResource{}.basic(data)) +} diff --git a/internal/services/dns/dns_txt_record_resource.go b/internal/services/dns/dns_txt_record_resource.go index 3d53d2cf318c..24633b8627cc 100644 --- a/internal/services/dns/dns_txt_record_resource.go +++ b/internal/services/dns/dns_txt_record_resource.go @@ -2,20 +2,18 @@ package dns import ( "fmt" - "net/http" "strings" "time" - "github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2018-05-01/dns" - "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/parse" - "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" - "github.com/hashicorp/terraform-provider-azurerm/utils" ) func resourceDnsTxtRecord() *pluginsdk.Resource { @@ -32,8 +30,14 @@ func resourceDnsTxtRecord() *pluginsdk.Resource { Delete: pluginsdk.DefaultTimeout(30 * time.Minute), }, Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - _, err := parse.TxtRecordID(id) - return err + parsed, err := recordsets.ParseRecordTypeID(id) + if err != nil { + return err + } + if parsed.RecordType != recordsets.RecordTypeTXT { + return fmt.Errorf("this resource only supports 'TXT' records") + } + return nil }), Schema: map[string]*pluginsdk.Schema{ "name": { @@ -42,11 +46,12 @@ func resourceDnsTxtRecord() *pluginsdk.Resource { ForceNew: true, }, - "resource_group_name": azure.SchemaResourceGroupName(), + "resource_group_name": commonschema.ResourceGroupName(), "zone_name": { Type: pluginsdk.TypeString, Required: true, + ForceNew: true, }, "record": { @@ -73,13 +78,13 @@ func resourceDnsTxtRecord() *pluginsdk.Resource { Computed: true, }, - "tags": tags.Schema(), + "tags": commonschema.Tags(), }, } } func resourceDnsTxtRecordCreateUpdate(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Dns.RecordSetsClient + client := meta.(*clients.Client).Dns.RecordSets ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) subscriptionId := meta.(*clients.Client).Account.SubscriptionId defer cancel() @@ -88,115 +93,120 @@ func resourceDnsTxtRecordCreateUpdate(d *pluginsdk.ResourceData, meta interface{ resGroup := d.Get("resource_group_name").(string) zoneName := d.Get("zone_name").(string) - resourceId := parse.NewTxtRecordID(subscriptionId, resGroup, zoneName, name) - + id := recordsets.NewRecordTypeID(subscriptionId, resGroup, zoneName, recordsets.RecordTypeTXT, name) if d.IsNewResource() { - existing, err := client.Get(ctx, resGroup, zoneName, name, dns.TXT) + existing, err := client.Get(ctx, id) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { - return fmt.Errorf("checking for presence of existing DNS TXT Record %q (Zone %q / Resource Group %q): %s", name, zoneName, resGroup, err) + if !response.WasNotFound(existing.HttpResponse) { + return fmt.Errorf("checking for presence of existing %s: %+v", id, err) } } - if !utils.ResponseWasNotFound(existing.Response) { - return tf.ImportAsExistsError("azurerm_dns_txt_record", resourceId.ID()) + if !response.WasNotFound(existing.HttpResponse) { + return tf.ImportAsExistsError("azurerm_dns_txt_record", id.ID()) } } ttl := int64(d.Get("ttl").(int)) t := d.Get("tags").(map[string]interface{}) - parameters := dns.RecordSet{ + parameters := recordsets.RecordSet{ Name: &name, - RecordSetProperties: &dns.RecordSetProperties{ + Properties: &recordsets.RecordSetProperties{ Metadata: tags.Expand(t), TTL: &ttl, - TxtRecords: expandAzureRmDnsTxtRecords(d), + TXTRecords: expandAzureRmDnsTxtRecords(d), }, } - eTag := "" - ifNoneMatch := "" // set to empty to allow updates to records after creation - if _, err := client.CreateOrUpdate(ctx, resGroup, zoneName, name, dns.TXT, parameters, eTag, ifNoneMatch); err != nil { - return fmt.Errorf("creating/updating DNS TXT Record %q (Zone %q / Resource Group %q): %s", name, zoneName, resGroup, err) + if _, err := client.CreateOrUpdate(ctx, id, parameters, recordsets.DefaultCreateOrUpdateOperationOptions()); err != nil { + return fmt.Errorf("creating/updating %s: %+v", id, err) } - d.SetId(resourceId.ID()) + d.SetId(id.ID()) return resourceDnsTxtRecordRead(d, meta) } func resourceDnsTxtRecordRead(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Dns.RecordSetsClient + client := meta.(*clients.Client).Dns.RecordSets ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.TxtRecordID(d.Id()) + id, err := recordsets.ParseRecordTypeIDInsensitively(d.Id()) if err != nil { return err } - resp, err := client.Get(ctx, id.ResourceGroup, id.DnszoneName, id.TXTName, dns.TXT) + resp, err := client.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { d.SetId("") return nil } - return fmt.Errorf("reading DNS TXT record %s: %+v", id.TXTName, err) + return fmt.Errorf("retrieving %s: %+v", *id, err) } - d.Set("name", id.TXTName) - d.Set("resource_group_name", id.ResourceGroup) - d.Set("zone_name", id.DnszoneName) - d.Set("ttl", resp.TTL) - d.Set("fqdn", resp.Fqdn) + d.Set("name", id.RelativeRecordSetName) + d.Set("resource_group_name", id.ResourceGroupName) + d.Set("zone_name", id.ZoneName) - if err := d.Set("record", flattenAzureRmDnsTxtRecords(resp.TxtRecords)); err != nil { - return err + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("ttl", props.TTL) + d.Set("fqdn", props.Fqdn) + + if err := d.Set("record", flattenAzureRmDnsTxtRecords(props.TXTRecords)); err != nil { + return err + } + if err := tags.FlattenAndSet(d, props.Metadata); err != nil { + return err + } + } } - return tags.FlattenAndSet(d, resp.Metadata) + + return nil } func resourceDnsTxtRecordDelete(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Dns.RecordSetsClient + client := meta.(*clients.Client).Dns.RecordSets ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.TxtRecordID(d.Id()) + id, err := recordsets.ParseRecordTypeID(d.Id()) if err != nil { return err } - resp, err := client.Delete(ctx, id.ResourceGroup, id.DnszoneName, id.TXTName, dns.TXT, "") - if resp.StatusCode != http.StatusOK { - return fmt.Errorf("deleting DNS TXT Record %s: %+v", id.TXTName, err) + if _, err := client.Delete(ctx, *id, recordsets.DefaultDeleteOperationOptions()); err != nil { + return fmt.Errorf("deleting %s: %+v", *id, err) } return nil } -func flattenAzureRmDnsTxtRecords(records *[]dns.TxtRecord) []map[string]interface{} { +func flattenAzureRmDnsTxtRecords(records *[]recordsets.TxtRecord) []map[string]interface{} { results := make([]map[string]interface{}, 0) if records != nil { for _, record := range *records { - txtRecord := make(map[string]interface{}) - + value := "" if v := record.Value; v != nil { - value := strings.Join(*v, "") - txtRecord["value"] = value + value = strings.Join(*v, "") } - results = append(results, txtRecord) + results = append(results, map[string]interface{}{ + "value": value, + }) } } return results } -func expandAzureRmDnsTxtRecords(d *pluginsdk.ResourceData) *[]dns.TxtRecord { +func expandAzureRmDnsTxtRecords(d *pluginsdk.ResourceData) *[]recordsets.TxtRecord { recordStrings := d.Get("record").(*pluginsdk.Set).List() - records := make([]dns.TxtRecord, len(recordStrings)) + records := make([]recordsets.TxtRecord, len(recordStrings)) segmentLen := 254 for i, v := range recordStrings { @@ -210,11 +220,9 @@ func expandAzureRmDnsTxtRecords(d *pluginsdk.ResourceData) *[]dns.TxtRecord { } value = append(value, v) - txtRecord := dns.TxtRecord{ + records[i] = recordsets.TxtRecord{ Value: &value, } - - records[i] = txtRecord } return &records diff --git a/internal/services/dns/dns_txt_record_resource_test.go b/internal/services/dns/dns_txt_record_resource_test.go index 48bac60156fd..a1ddfef1fbc7 100644 --- a/internal/services/dns/dns_txt_record_resource_test.go +++ b/internal/services/dns/dns_txt_record_resource_test.go @@ -5,11 +5,10 @@ import ( "fmt" "testing" - "github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2018-05-01/dns" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -96,17 +95,17 @@ func TestAccDnsTxtRecord_withTags(t *testing.T) { } func (DnsTxtRecordResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.TxtRecordID(state.ID) + id, err := recordsets.ParseRecordTypeID(state.ID) if err != nil { return nil, err } - resp, err := clients.Dns.RecordSetsClient.Get(ctx, id.ResourceGroup, id.DnszoneName, id.TXTName, dns.TXT) + resp, err := clients.Dns.RecordSets.Get(ctx, *id) if err != nil { - return nil, fmt.Errorf("retrieving DNS TXT record %s (resource group: %s): %v", id.TXTName, id.ResourceGroup, err) + return nil, fmt.Errorf("retrieving %s: %+v", *id, err) } - return utils.Bool(resp.RecordSetProperties != nil), nil + return utils.Bool(resp.Model != nil), nil } func (DnsTxtRecordResource) basic(data acceptance.TestData) string { diff --git a/internal/services/dns/dns_zone_data_source.go b/internal/services/dns/dns_zone_data_source.go index b931520edc88..bdd483ad11d5 100644 --- a/internal/services/dns/dns_zone_data_source.go +++ b/internal/services/dns/dns_zone_data_source.go @@ -5,13 +5,14 @@ import ( "fmt" "time" - "github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2018-05-01/dns" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/zones" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/parse" - "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" - "github.com/hashicorp/terraform-provider-azurerm/utils" ) func dataSourceDnsZone() *pluginsdk.Resource { @@ -29,6 +30,7 @@ func dataSourceDnsZone() *pluginsdk.Resource { }, "resource_group_name": { + // TODO: we need a CommonSchema type for this which doesn't have ForceNew Type: pluginsdk.TypeString, Optional: true, Computed: true, @@ -51,54 +53,53 @@ func dataSourceDnsZone() *pluginsdk.Resource { Set: pluginsdk.HashString, }, - "tags": tags.SchemaDataSource(), + "tags": commonschema.TagsDataSource(), }, } } func dataSourceDnsZoneRead(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Dns.ZonesClient - ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + client := meta.(*clients.Client).Dns.Zones subscriptionId := meta.(*clients.Client).Account.SubscriptionId - + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - name := d.Get("name").(string) - resourceGroup := d.Get("resource_group_name").(string) - - var ( - resp dns.Zone - err error - ) - if resourceGroup != "" { - resp, err = client.Get(ctx, resourceGroup, name) + id := zones.NewDnsZoneID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) + var zone *zones.Zone + if id.ResourceGroupName != "" { + resp, err := client.Get(ctx, id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { - return fmt.Errorf("Error: DNS Zone %q (Resource Group %q) was not found", name, resourceGroup) + if response.WasNotFound(resp.HttpResponse) { + return fmt.Errorf("%s was not found", id) } - return fmt.Errorf("reading DNS Zone %q (Resource Group %q): %+v", name, resourceGroup, err) + return fmt.Errorf("retrieving %s: %+v", id, err) } + + zone = resp.Model } else { - var zone *dns.Zone - zone, resourceGroup, err = findZone(client, ctx, name) + result, resourceGroupName, err := findZone(ctx, client, id.SubscriptionId, id.ZoneName) if err != nil { return err } - if zone == nil { - return fmt.Errorf("Error: DNS Zone %q was not found", name) + if resourceGroupName == nil { + return fmt.Errorf("unable to locate the Resource Group for DNS Zone %q in Subscription %q", id.ResourceGroupName, subscriptionId) } - resp = *zone + zone = result + id.ResourceGroupName = *resourceGroupName } - resourceId := parse.NewDnsZoneID(subscriptionId, resourceGroup, name) - d.SetId(resourceId.ID()) + if zone == nil { + return fmt.Errorf("retrieving %s: `model` was nil", id) + } + + d.SetId(id.ID()) - d.Set("name", name) - d.Set("resource_group_name", resourceGroup) + d.Set("name", id.ZoneName) + d.Set("resource_group_name", id.ResourceGroupName) - if props := resp.ZoneProperties; props != nil { + if props := zone.Properties; props != nil { d.Set("number_of_record_sets", props.NumberOfRecordSets) d.Set("max_number_of_record_sets", props.MaxNumberOfRecordSets) @@ -111,36 +112,37 @@ func dataSourceDnsZoneRead(d *pluginsdk.ResourceData, meta interface{}) error { } } - return tags.FlattenAndSet(d, resp.Tags) + if err := tags.FlattenAndSet(d, zone.Tags); err != nil { + return err + } + + return nil } -func findZone(client *dns.ZonesClient, ctx context.Context, name string) (*dns.Zone, string, error) { - zonesIterator, err := client.ListComplete(ctx, nil) +func findZone(ctx context.Context, client *zones.ZonesClient, subscriptionId, name string) (*zones.Zone, *string, error) { + subscriptionResourceId := commonids.NewSubscriptionID(subscriptionId) + zonesIterator, err := client.ListComplete(ctx, subscriptionResourceId, zones.DefaultListOperationOptions()) if err != nil { - return nil, "", fmt.Errorf("listing DNS Zones: %+v", err) + return nil, nil, fmt.Errorf("listing DNS Zones: %+v", err) } - var found *dns.Zone - for zonesIterator.NotDone() { - zone := zonesIterator.Value() + var found zones.Zone + for _, zone := range zonesIterator.Items { if zone.Name != nil && *zone.Name == name { - if found != nil { - return nil, "", fmt.Errorf("found multiple DNS zones with name %q, please specify the resource group", name) + if found.Id != nil { + return nil, nil, fmt.Errorf("found multiple DNS zones with name %q, please specify the resource group", name) } - found = &zone - } - if err := zonesIterator.NextWithContext(ctx); err != nil { - return nil, "", fmt.Errorf("listing DNS Zones: %+v", err) + found = zone } } - if found == nil || found.ID == nil { - return nil, "", fmt.Errorf("could not find DNS zone with name: %q", name) + if found.Id == nil { + return nil, nil, fmt.Errorf("could not find DNS zone with name: %q", name) } - id, err := parse.DnsZoneID(*found.ID) + id, err := zones.ParseDnsZoneIDInsensitively(*found.Id) if err != nil { - return nil, "", fmt.Errorf("DNS zone id not valid: %+v", err) + return nil, nil, fmt.Errorf("parsing %q as a DNS Zone ID: %+v", *found.Id, err) } - return found, id.ResourceGroup, nil + return &found, &id.ResourceGroupName, nil } diff --git a/internal/services/dns/dns_zone_resource.go b/internal/services/dns/dns_zone_resource.go index 729fe806dc91..eccba9569d7a 100644 --- a/internal/services/dns/dns_zone_resource.go +++ b/internal/services/dns/dns_zone_resource.go @@ -5,14 +5,16 @@ import ( "strings" "time" - "github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2018-05-01/dns" - "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/recordsets" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/zones" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/migration" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/validate" - "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" @@ -39,7 +41,7 @@ func resourceDnsZone() *pluginsdk.Resource { }, Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - _, err := parse.DnsZoneID(id) + _, err := zones.ParseDnsZoneID(id) return err }), Schema: map[string]*pluginsdk.Schema{ @@ -49,7 +51,7 @@ func resourceDnsZone() *pluginsdk.Resource { ForceNew: true, }, - "resource_group_name": azure.SchemaResourceGroupNameDiffSuppress(), + "resource_group_name": commonschema.ResourceGroupName(), "number_of_record_sets": { Type: pluginsdk.TypeInt, @@ -130,7 +132,7 @@ func resourceDnsZone() *pluginsdk.Resource { ValidateFunc: validation.IntBetween(0, 2147483647), }, - "tags": tags.Schema(), + "tags": commonschema.Tags(), "fqdn": { Type: pluginsdk.TypeString, @@ -140,145 +142,142 @@ func resourceDnsZone() *pluginsdk.Resource { }, }, - "tags": tags.Schema(), + "tags": commonschema.Tags(), }, } } func resourceDnsZoneCreateUpdate(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Dns.ZonesClient - recordSetsClient := meta.(*clients.Client).Dns.RecordSetsClient + client := meta.(*clients.Client).Dns.Zones + recordSetsClient := meta.(*clients.Client).Dns.RecordSets subscriptionId := meta.(*clients.Client).Account.SubscriptionId ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - name := d.Get("name").(string) - resGroup := d.Get("resource_group_name").(string) - - resourceId := parse.NewDnsZoneID(subscriptionId, resGroup, name) - + id := zones.NewDnsZoneID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) if d.IsNewResource() { - existing, err := client.Get(ctx, resGroup, name) + existing, err := client.Get(ctx, id) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { - return fmt.Errorf("checking for presence of existing DNS Zone %q (Resource Group %q): %s", name, resGroup, err) + if !response.WasNotFound(existing.HttpResponse) { + return fmt.Errorf("checking for presence of existing %s: %+v", id, err) } } - if !utils.ResponseWasNotFound(existing.Response) { - return tf.ImportAsExistsError("azurerm_dns_zone", resourceId.ID()) + if !response.WasNotFound(existing.HttpResponse) { + return tf.ImportAsExistsError("azurerm_dns_zone", id.ID()) } } - location := "global" t := d.Get("tags").(map[string]interface{}) - parameters := dns.Zone{ - Location: &location, + parameters := zones.Zone{ + Location: location.Normalize("global"), Tags: tags.Expand(t), } - etag := "" - ifNoneMatch := "" // set to empty to allow updates to records after creation - if _, err := client.CreateOrUpdate(ctx, resGroup, name, parameters, etag, ifNoneMatch); err != nil { - return fmt.Errorf("creating/updating DNS Zone %q (Resource Group %q): %s", name, resGroup, err) + if _, err := client.CreateOrUpdate(ctx, id, parameters, zones.DefaultCreateOrUpdateOperationOptions()); err != nil { + return fmt.Errorf("creating/updating %s: %+v", id, err) } if v, ok := d.GetOk("soa_record"); ok { soaRecord := v.([]interface{})[0].(map[string]interface{}) - rsParameters := dns.RecordSet{ - RecordSetProperties: &dns.RecordSetProperties{ + rsParameters := recordsets.RecordSet{ + Properties: &recordsets.RecordSetProperties{ TTL: utils.Int64(int64(soaRecord["ttl"].(int))), Metadata: tags.Expand(soaRecord["tags"].(map[string]interface{})), - SoaRecord: expandArmDNSZoneSOARecord(soaRecord), + SOARecord: expandArmDNSZoneSOARecord(soaRecord), }, } - if len(name+strings.TrimSuffix(*rsParameters.RecordSetProperties.SoaRecord.Email, ".")) > 253 { + if len(id.ZoneName+strings.TrimSuffix(*rsParameters.Properties.SOARecord.Email, ".")) > 253 { return fmt.Errorf("`email` which is concatenated with DNS Zone `name` cannot exceed 253 characters excluding a trailing period") } - if _, err := recordSetsClient.CreateOrUpdate(ctx, resGroup, name, "@", dns.SOA, rsParameters, etag, ifNoneMatch); err != nil { - return fmt.Errorf("creating/updating DNS SOA Record @ (Zone %q / Resource Group %q): %s", name, resGroup, err) + soaRecordId := recordsets.NewRecordTypeID(id.SubscriptionId, id.ResourceGroupName, id.ZoneName, recordsets.RecordTypeSOA, "@") + if _, err := recordSetsClient.CreateOrUpdate(ctx, soaRecordId, rsParameters, recordsets.DefaultCreateOrUpdateOperationOptions()); err != nil { + return fmt.Errorf("creating/updating %s: %+v", soaRecordId, err) } } - d.SetId(resourceId.ID()) + d.SetId(id.ID()) return resourceDnsZoneRead(d, meta) } func resourceDnsZoneRead(d *pluginsdk.ResourceData, meta interface{}) error { - zonesClient := meta.(*clients.Client).Dns.ZonesClient - recordSetsClient := meta.(*clients.Client).Dns.RecordSetsClient + zonesClient := meta.(*clients.Client).Dns.Zones + recordSetsClient := meta.(*clients.Client).Dns.RecordSets ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.DnsZoneID(d.Id()) + id, err := zones.ParseDnsZoneIDInsensitively(d.Id()) if err != nil { return err } - resp, err := zonesClient.Get(ctx, id.ResourceGroup, id.Name) + resp, err := zonesClient.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { d.SetId("") return nil } - return fmt.Errorf("reading DNS Zone %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + return fmt.Errorf("retrieving %s: %+v", *id, err) } - d.Set("name", id.Name) - d.Set("resource_group_name", id.ResourceGroup) - - d.Set("number_of_record_sets", resp.NumberOfRecordSets) - d.Set("max_number_of_record_sets", resp.MaxNumberOfRecordSets) - - nameServers := make([]string, 0) - if s := resp.NameServers; s != nil { - nameServers = *s - } - if err := d.Set("name_servers", nameServers); err != nil { - return err - } - - rsResp, err := recordSetsClient.Get(ctx, id.ResourceGroup, id.Name, "@", dns.SOA) + soaRecord := recordsets.NewRecordTypeID(id.SubscriptionId, id.ResourceGroupName, id.ZoneName, recordsets.RecordTypeSOA, "@") + soaRecordResp, err := recordSetsClient.Get(ctx, soaRecord) if err != nil { - return fmt.Errorf("reading DNS SOA record @: %v", err) + return fmt.Errorf("retrieving %s: %+v", id, err) } - if err := d.Set("soa_record", flattenArmDNSZoneSOARecord(&rsResp)); err != nil { + if err := d.Set("soa_record", flattenArmDNSZoneSOARecord(soaRecordResp.Model)); err != nil { return fmt.Errorf("setting `soa_record`: %+v", err) } - return tags.FlattenAndSet(d, resp.Tags) + d.Set("name", id.ZoneName) + d.Set("resource_group_name", id.ResourceGroupName) + + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("number_of_record_sets", props.NumberOfRecordSets) + d.Set("max_number_of_record_sets", props.MaxNumberOfRecordSets) + + nameServers := make([]string, 0) + if s := props.NameServers; s != nil { + nameServers = *s + } + if err := d.Set("name_servers", nameServers); err != nil { + return err + } + } + + if err := tags.FlattenAndSet(d, model.Tags); err != nil { + return err + } + } + + return nil } func resourceDnsZoneDelete(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Dns.ZonesClient + client := meta.(*clients.Client).Dns.Zones ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.DnsZoneID(d.Id()) + id, err := zones.ParseDnsZoneID(d.Id()) if err != nil { return err } - etag := "" - future, err := client.Delete(ctx, id.ResourceGroup, id.Name, etag) - if err != nil { - return fmt.Errorf("deleting DNS Zone %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) - } - - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for the deletion of DNS Zone %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + if err := client.DeleteThenPoll(ctx, *id, zones.DefaultDeleteOperationOptions()); err != nil { + return fmt.Errorf("deleting %s: %+v", *id, err) } return nil } -func expandArmDNSZoneSOARecord(input map[string]interface{}) *dns.SoaRecord { - return &dns.SoaRecord{ +func expandArmDNSZoneSOARecord(input map[string]interface{}) *recordsets.SoaRecord { + return &recordsets.SoaRecord{ Email: utils.String(input["email"].(string)), Host: utils.String(input["host_name"].(string)), ExpireTime: utils.Int64(int64(input["expire_time"].(int))), @@ -289,75 +288,76 @@ func expandArmDNSZoneSOARecord(input map[string]interface{}) *dns.SoaRecord { } } -func flattenArmDNSZoneSOARecord(input *dns.RecordSet) []interface{} { - if input == nil { - return make([]interface{}, 0) - } - - ttl := 0 - if input.TTL != nil { - ttl = int(*input.TTL) - } - - metaData := make(map[string]interface{}) - if input.Metadata != nil { - metaData = tags.Flatten(input.Metadata) - } - - fqdn := "" - if input.Fqdn != nil { - fqdn = *input.Fqdn - } - - email := "" - hostName := "" - expireTime := 0 - minimumTTL := 0 - refreshTime := 0 - retryTime := 0 - serialNumber := 0 - if input.SoaRecord != nil { - if input.SoaRecord.Email != nil { - email = *input.SoaRecord.Email - } - - if input.SoaRecord.Host != nil { - hostName = *input.SoaRecord.Host - } - - if input.SoaRecord.ExpireTime != nil { - expireTime = int(*input.SoaRecord.ExpireTime) - } +func flattenArmDNSZoneSOARecord(input *recordsets.RecordSet) []interface{} { + output := make([]interface{}, 0) + if input != nil { + if props := input.Properties; props != nil { + ttl := 0 + if props.TTL != nil { + ttl = int(*props.TTL) + } - if input.SoaRecord.MinimumTTL != nil { - minimumTTL = int(*input.SoaRecord.MinimumTTL) - } + metaData := make(map[string]interface{}) + if props.Metadata != nil { + metaData = tags.Flatten(props.Metadata) + } - if input.SoaRecord.RefreshTime != nil { - refreshTime = int(*input.SoaRecord.RefreshTime) - } + fqdn := "" + if props.Fqdn != nil { + fqdn = *props.Fqdn + } - if input.SoaRecord.RetryTime != nil { - retryTime = int(*input.SoaRecord.RetryTime) - } + email := "" + hostName := "" + expireTime := 0 + minimumTTL := 0 + refreshTime := 0 + retryTime := 0 + serialNumber := 0 + if record := props.SOARecord; record != nil { + if record.Email != nil { + email = *record.Email + } + + if record.Host != nil { + hostName = *record.Host + } + + if record.ExpireTime != nil { + expireTime = int(*record.ExpireTime) + } + + if record.MinimumTTL != nil { + minimumTTL = int(*record.MinimumTTL) + } + + if record.RefreshTime != nil { + refreshTime = int(*record.RefreshTime) + } + + if record.RetryTime != nil { + retryTime = int(*record.RetryTime) + } + + if record.SerialNumber != nil { + serialNumber = int(*record.SerialNumber) + } + } - if input.SoaRecord.SerialNumber != nil { - serialNumber = int(*input.SoaRecord.SerialNumber) + output = append(output, map[string]interface{}{ + "email": email, + "host_name": hostName, + "expire_time": expireTime, + "minimum_ttl": minimumTTL, + "refresh_time": refreshTime, + "retry_time": retryTime, + "serial_number": serialNumber, + "ttl": ttl, + "tags": metaData, + "fqdn": fqdn, + }) } } - return []interface{}{ - map[string]interface{}{ - "email": email, - "host_name": hostName, - "expire_time": expireTime, - "minimum_ttl": minimumTTL, - "refresh_time": refreshTime, - "retry_time": retryTime, - "serial_number": serialNumber, - "ttl": ttl, - "tags": metaData, - "fqdn": fqdn, - }, - } + return output } diff --git a/internal/services/dns/dns_zone_resource_test.go b/internal/services/dns/dns_zone_resource_test.go index db0dc4d6baa7..bd1f167892fd 100644 --- a/internal/services/dns/dns_zone_resource_test.go +++ b/internal/services/dns/dns_zone_resource_test.go @@ -5,10 +5,10 @@ import ( "fmt" "testing" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/zones" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -101,17 +101,17 @@ func TestAccDnsZone_withSOARecord(t *testing.T) { } func (DnsZoneResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.DnsZoneID(state.ID) + id, err := zones.ParseDnsZoneID(state.ID) if err != nil { return nil, err } - resp, err := clients.Dns.ZonesClient.Get(ctx, id.ResourceGroup, id.Name) + resp, err := clients.Dns.Zones.Get(ctx, *id) if err != nil { - return nil, fmt.Errorf("retrieving DNS zone %s (resource group: %s): %v", id.Name, id.ResourceGroup, err) + return nil, fmt.Errorf("retrieving %s: %+v", id, err) } - return utils.Bool(resp.ZoneProperties != nil), nil + return utils.Bool(resp.Model != nil), nil } func (DnsZoneResource) basic(data acceptance.TestData) string { diff --git a/internal/services/dns/migration/dns_zone_V0_to_V1.go b/internal/services/dns/migration/dns_zone_V0_to_V1.go index 9222e7d66d47..d67a5af9c083 100644 --- a/internal/services/dns/migration/dns_zone_V0_to_V1.go +++ b/internal/services/dns/migration/dns_zone_V0_to_V1.go @@ -5,8 +5,8 @@ import ( "fmt" "log" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2018-05-01/zones" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" ) @@ -129,20 +129,20 @@ func (DnsZoneV0ToV1) UpgradeFunc() pluginsdk.StateUpgraderFunc { return func(ctx context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) { groupsClient := meta.(*clients.Client).Resource.GroupsClient oldId := rawState["id"].(string) - id, err := parse.DnsZoneID(oldId) + id, err := zones.ParseDnsZoneID(oldId) if err != nil { return rawState, err } - resGroup, err := groupsClient.Get(ctx, id.ResourceGroup) + resGroup, err := groupsClient.Get(ctx, id.ResourceGroupName) if err != nil { return rawState, err } if resGroup.Name == nil { - return rawState, fmt.Errorf("`name` was nil for Resource Group %q", id.ResourceGroup) + return rawState, fmt.Errorf("`name` was nil for Resource Group %q", id.ResourceGroupName) } resourceGroup := *resGroup.Name name := rawState["name"].(string) - newId := parse.NewDnsZoneID(id.SubscriptionId, resourceGroup, name).ID() + newId := zones.NewDnsZoneID(id.SubscriptionId, resourceGroup, name).ID() log.Printf("Updating `id` from %q to %q", oldId, newId) rawState["id"] = newId return rawState, nil diff --git a/internal/services/dns/parse/a_record.go b/internal/services/dns/parse/a_record.go deleted file mode 100644 index cc22cfdc3cde..000000000000 --- a/internal/services/dns/parse/a_record.go +++ /dev/null @@ -1,75 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - "strings" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -type ARecordId struct { - SubscriptionId string - ResourceGroup string - DnszoneName string - AName string -} - -func NewARecordID(subscriptionId, resourceGroup, dnszoneName, aName string) ARecordId { - return ARecordId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourceGroup, - DnszoneName: dnszoneName, - AName: aName, - } -} - -func (id ARecordId) String() string { - segments := []string{ - fmt.Sprintf("A Name %q", id.AName), - fmt.Sprintf("Dnszone Name %q", id.DnszoneName), - fmt.Sprintf("Resource Group %q", id.ResourceGroup), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "A Record", segmentsStr) -} - -func (id ARecordId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/dnszones/%s/A/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.DnszoneName, id.AName) -} - -// ARecordID parses a ARecord ID into an ARecordId struct -func ARecordID(input string) (*ARecordId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := ARecordId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - if resourceId.DnszoneName, err = id.PopSegment("dnszones"); err != nil { - return nil, err - } - if resourceId.AName, err = id.PopSegment("A"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/dns/parse/a_record_test.go b/internal/services/dns/parse/a_record_test.go deleted file mode 100644 index d7d2894fb685..000000000000 --- a/internal/services/dns/parse/a_record_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "testing" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -var _ resourceids.Id = ARecordId{} - -func TestARecordIDFormatter(t *testing.T) { - actual := NewARecordID("12345678-1234-9876-4563-123456789012", "resGroup1", "zone1", "eh1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/A/eh1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestARecordID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *ARecordId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - - { - // missing DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/", - Error: true, - }, - - { - // missing value for DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/", - Error: true, - }, - - { - // missing AName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/", - Error: true, - }, - - { - // missing value for AName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/A/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/A/eh1", - Expected: &ARecordId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - DnszoneName: "zone1", - AName: "eh1", - }, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.NETWORK/DNSZONES/ZONE1/A/EH1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := ARecordID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - if actual.DnszoneName != v.Expected.DnszoneName { - t.Fatalf("Expected %q but got %q for DnszoneName", v.Expected.DnszoneName, actual.DnszoneName) - } - if actual.AName != v.Expected.AName { - t.Fatalf("Expected %q but got %q for AName", v.Expected.AName, actual.AName) - } - } -} diff --git a/internal/services/dns/parse/aaaa_record.go b/internal/services/dns/parse/aaaa_record.go deleted file mode 100644 index 4c05e28108ca..000000000000 --- a/internal/services/dns/parse/aaaa_record.go +++ /dev/null @@ -1,75 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - "strings" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -type AaaaRecordId struct { - SubscriptionId string - ResourceGroup string - DnszoneName string - AAAAName string -} - -func NewAaaaRecordID(subscriptionId, resourceGroup, dnszoneName, aAAAName string) AaaaRecordId { - return AaaaRecordId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourceGroup, - DnszoneName: dnszoneName, - AAAAName: aAAAName, - } -} - -func (id AaaaRecordId) String() string { - segments := []string{ - fmt.Sprintf("A A A A Name %q", id.AAAAName), - fmt.Sprintf("Dnszone Name %q", id.DnszoneName), - fmt.Sprintf("Resource Group %q", id.ResourceGroup), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Aaaa Record", segmentsStr) -} - -func (id AaaaRecordId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/dnszones/%s/AAAA/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.DnszoneName, id.AAAAName) -} - -// AaaaRecordID parses a AaaaRecord ID into an AaaaRecordId struct -func AaaaRecordID(input string) (*AaaaRecordId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := AaaaRecordId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - if resourceId.DnszoneName, err = id.PopSegment("dnszones"); err != nil { - return nil, err - } - if resourceId.AAAAName, err = id.PopSegment("AAAA"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/dns/parse/aaaa_record_test.go b/internal/services/dns/parse/aaaa_record_test.go deleted file mode 100644 index 0f630220e9cc..000000000000 --- a/internal/services/dns/parse/aaaa_record_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "testing" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -var _ resourceids.Id = AaaaRecordId{} - -func TestAaaaRecordIDFormatter(t *testing.T) { - actual := NewAaaaRecordID("12345678-1234-9876-4563-123456789012", "resGroup1", "zone1", "eheh1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/AAAA/eheh1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestAaaaRecordID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *AaaaRecordId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - - { - // missing DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/", - Error: true, - }, - - { - // missing value for DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/", - Error: true, - }, - - { - // missing AAAAName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/", - Error: true, - }, - - { - // missing value for AAAAName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/AAAA/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/AAAA/eheh1", - Expected: &AaaaRecordId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - DnszoneName: "zone1", - AAAAName: "eheh1", - }, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.NETWORK/DNSZONES/ZONE1/AAAA/EHEH1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := AaaaRecordID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - if actual.DnszoneName != v.Expected.DnszoneName { - t.Fatalf("Expected %q but got %q for DnszoneName", v.Expected.DnszoneName, actual.DnszoneName) - } - if actual.AAAAName != v.Expected.AAAAName { - t.Fatalf("Expected %q but got %q for AAAAName", v.Expected.AAAAName, actual.AAAAName) - } - } -} diff --git a/internal/services/dns/parse/caa_record.go b/internal/services/dns/parse/caa_record.go deleted file mode 100644 index 156be086f698..000000000000 --- a/internal/services/dns/parse/caa_record.go +++ /dev/null @@ -1,75 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - "strings" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -type CaaRecordId struct { - SubscriptionId string - ResourceGroup string - DnszoneName string - CAAName string -} - -func NewCaaRecordID(subscriptionId, resourceGroup, dnszoneName, cAAName string) CaaRecordId { - return CaaRecordId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourceGroup, - DnszoneName: dnszoneName, - CAAName: cAAName, - } -} - -func (id CaaRecordId) String() string { - segments := []string{ - fmt.Sprintf("C A A Name %q", id.CAAName), - fmt.Sprintf("Dnszone Name %q", id.DnszoneName), - fmt.Sprintf("Resource Group %q", id.ResourceGroup), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Caa Record", segmentsStr) -} - -func (id CaaRecordId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/dnszones/%s/CAA/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.DnszoneName, id.CAAName) -} - -// CaaRecordID parses a CaaRecord ID into an CaaRecordId struct -func CaaRecordID(input string) (*CaaRecordId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := CaaRecordId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - if resourceId.DnszoneName, err = id.PopSegment("dnszones"); err != nil { - return nil, err - } - if resourceId.CAAName, err = id.PopSegment("CAA"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/dns/parse/caa_record_test.go b/internal/services/dns/parse/caa_record_test.go deleted file mode 100644 index 80da422f8ec9..000000000000 --- a/internal/services/dns/parse/caa_record_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "testing" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -var _ resourceids.Id = CaaRecordId{} - -func TestCaaRecordIDFormatter(t *testing.T) { - actual := NewCaaRecordID("12345678-1234-9876-4563-123456789012", "resGroup1", "zone1", "caa1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/CAA/caa1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestCaaRecordID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *CaaRecordId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - - { - // missing DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/", - Error: true, - }, - - { - // missing value for DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/", - Error: true, - }, - - { - // missing CAAName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/", - Error: true, - }, - - { - // missing value for CAAName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/CAA/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/CAA/caa1", - Expected: &CaaRecordId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - DnszoneName: "zone1", - CAAName: "caa1", - }, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.NETWORK/DNSZONES/ZONE1/CAA/CAA1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := CaaRecordID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - if actual.DnszoneName != v.Expected.DnszoneName { - t.Fatalf("Expected %q but got %q for DnszoneName", v.Expected.DnszoneName, actual.DnszoneName) - } - if actual.CAAName != v.Expected.CAAName { - t.Fatalf("Expected %q but got %q for CAAName", v.Expected.CAAName, actual.CAAName) - } - } -} diff --git a/internal/services/dns/parse/cname_record.go b/internal/services/dns/parse/cname_record.go deleted file mode 100644 index 1cdf96189e6c..000000000000 --- a/internal/services/dns/parse/cname_record.go +++ /dev/null @@ -1,75 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - "strings" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -type CnameRecordId struct { - SubscriptionId string - ResourceGroup string - DnszoneName string - CNAMEName string -} - -func NewCnameRecordID(subscriptionId, resourceGroup, dnszoneName, cNAMEName string) CnameRecordId { - return CnameRecordId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourceGroup, - DnszoneName: dnszoneName, - CNAMEName: cNAMEName, - } -} - -func (id CnameRecordId) String() string { - segments := []string{ - fmt.Sprintf("C N A M E Name %q", id.CNAMEName), - fmt.Sprintf("Dnszone Name %q", id.DnszoneName), - fmt.Sprintf("Resource Group %q", id.ResourceGroup), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Cname Record", segmentsStr) -} - -func (id CnameRecordId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/dnszones/%s/CNAME/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.DnszoneName, id.CNAMEName) -} - -// CnameRecordID parses a CnameRecord ID into an CnameRecordId struct -func CnameRecordID(input string) (*CnameRecordId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := CnameRecordId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - if resourceId.DnszoneName, err = id.PopSegment("dnszones"); err != nil { - return nil, err - } - if resourceId.CNAMEName, err = id.PopSegment("CNAME"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/dns/parse/cname_record_test.go b/internal/services/dns/parse/cname_record_test.go deleted file mode 100644 index ce81768189b3..000000000000 --- a/internal/services/dns/parse/cname_record_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "testing" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -var _ resourceids.Id = CnameRecordId{} - -func TestCnameRecordIDFormatter(t *testing.T) { - actual := NewCnameRecordID("12345678-1234-9876-4563-123456789012", "resGroup1", "zone1", "name1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/CNAME/name1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestCnameRecordID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *CnameRecordId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - - { - // missing DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/", - Error: true, - }, - - { - // missing value for DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/", - Error: true, - }, - - { - // missing CNAMEName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/", - Error: true, - }, - - { - // missing value for CNAMEName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/CNAME/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/CNAME/name1", - Expected: &CnameRecordId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - DnszoneName: "zone1", - CNAMEName: "name1", - }, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.NETWORK/DNSZONES/ZONE1/CNAME/NAME1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := CnameRecordID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - if actual.DnszoneName != v.Expected.DnszoneName { - t.Fatalf("Expected %q but got %q for DnszoneName", v.Expected.DnszoneName, actual.DnszoneName) - } - if actual.CNAMEName != v.Expected.CNAMEName { - t.Fatalf("Expected %q but got %q for CNAMEName", v.Expected.CNAMEName, actual.CNAMEName) - } - } -} diff --git a/internal/services/dns/parse/dns_zone.go b/internal/services/dns/parse/dns_zone.go deleted file mode 100644 index 8f4564b18e99..000000000000 --- a/internal/services/dns/parse/dns_zone.go +++ /dev/null @@ -1,69 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - "strings" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -type DnsZoneId struct { - SubscriptionId string - ResourceGroup string - Name string -} - -func NewDnsZoneID(subscriptionId, resourceGroup, name string) DnsZoneId { - return DnsZoneId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourceGroup, - Name: name, - } -} - -func (id DnsZoneId) String() string { - segments := []string{ - fmt.Sprintf("Name %q", id.Name), - fmt.Sprintf("Resource Group %q", id.ResourceGroup), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Dns Zone", segmentsStr) -} - -func (id DnsZoneId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/dnszones/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.Name) -} - -// DnsZoneID parses a DnsZone ID into an DnsZoneId struct -func DnsZoneID(input string) (*DnsZoneId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := DnsZoneId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - if resourceId.Name, err = id.PopSegment("dnszones"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/dns/parse/dns_zone_test.go b/internal/services/dns/parse/dns_zone_test.go deleted file mode 100644 index a60db762ba38..000000000000 --- a/internal/services/dns/parse/dns_zone_test.go +++ /dev/null @@ -1,112 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "testing" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -var _ resourceids.Id = DnsZoneId{} - -func TestDnsZoneIDFormatter(t *testing.T) { - actual := NewDnsZoneID("12345678-1234-9876-4563-123456789012", "resGroup1", "zone1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestDnsZoneID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *DnsZoneId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - - { - // missing Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/", - Error: true, - }, - - { - // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1", - Expected: &DnsZoneId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - Name: "zone1", - }, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.NETWORK/DNSZONES/ZONE1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := DnsZoneID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - if actual.Name != v.Expected.Name { - t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name) - } - } -} diff --git a/internal/services/dns/parse/mx_record.go b/internal/services/dns/parse/mx_record.go deleted file mode 100644 index b1c6aa955c50..000000000000 --- a/internal/services/dns/parse/mx_record.go +++ /dev/null @@ -1,75 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - "strings" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -type MxRecordId struct { - SubscriptionId string - ResourceGroup string - DnszoneName string - MXName string -} - -func NewMxRecordID(subscriptionId, resourceGroup, dnszoneName, mXName string) MxRecordId { - return MxRecordId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourceGroup, - DnszoneName: dnszoneName, - MXName: mXName, - } -} - -func (id MxRecordId) String() string { - segments := []string{ - fmt.Sprintf("M X Name %q", id.MXName), - fmt.Sprintf("Dnszone Name %q", id.DnszoneName), - fmt.Sprintf("Resource Group %q", id.ResourceGroup), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Mx Record", segmentsStr) -} - -func (id MxRecordId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/dnszones/%s/MX/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.DnszoneName, id.MXName) -} - -// MxRecordID parses a MxRecord ID into an MxRecordId struct -func MxRecordID(input string) (*MxRecordId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := MxRecordId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - if resourceId.DnszoneName, err = id.PopSegment("dnszones"); err != nil { - return nil, err - } - if resourceId.MXName, err = id.PopSegment("MX"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/dns/parse/mx_record_test.go b/internal/services/dns/parse/mx_record_test.go deleted file mode 100644 index cf4fe1630841..000000000000 --- a/internal/services/dns/parse/mx_record_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "testing" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -var _ resourceids.Id = MxRecordId{} - -func TestMxRecordIDFormatter(t *testing.T) { - actual := NewMxRecordID("12345678-1234-9876-4563-123456789012", "resGroup1", "zone1", "mx1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/MX/mx1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestMxRecordID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *MxRecordId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - - { - // missing DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/", - Error: true, - }, - - { - // missing value for DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/", - Error: true, - }, - - { - // missing MXName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/", - Error: true, - }, - - { - // missing value for MXName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/MX/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/MX/mx1", - Expected: &MxRecordId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - DnszoneName: "zone1", - MXName: "mx1", - }, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.NETWORK/DNSZONES/ZONE1/MX/MX1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := MxRecordID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - if actual.DnszoneName != v.Expected.DnszoneName { - t.Fatalf("Expected %q but got %q for DnszoneName", v.Expected.DnszoneName, actual.DnszoneName) - } - if actual.MXName != v.Expected.MXName { - t.Fatalf("Expected %q but got %q for MXName", v.Expected.MXName, actual.MXName) - } - } -} diff --git a/internal/services/dns/parse/ns_record.go b/internal/services/dns/parse/ns_record.go deleted file mode 100644 index dd8399f70f59..000000000000 --- a/internal/services/dns/parse/ns_record.go +++ /dev/null @@ -1,75 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - "strings" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -type NsRecordId struct { - SubscriptionId string - ResourceGroup string - DnszoneName string - NSName string -} - -func NewNsRecordID(subscriptionId, resourceGroup, dnszoneName, nSName string) NsRecordId { - return NsRecordId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourceGroup, - DnszoneName: dnszoneName, - NSName: nSName, - } -} - -func (id NsRecordId) String() string { - segments := []string{ - fmt.Sprintf("N S Name %q", id.NSName), - fmt.Sprintf("Dnszone Name %q", id.DnszoneName), - fmt.Sprintf("Resource Group %q", id.ResourceGroup), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Ns Record", segmentsStr) -} - -func (id NsRecordId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/dnszones/%s/NS/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.DnszoneName, id.NSName) -} - -// NsRecordID parses a NsRecord ID into an NsRecordId struct -func NsRecordID(input string) (*NsRecordId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := NsRecordId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - if resourceId.DnszoneName, err = id.PopSegment("dnszones"); err != nil { - return nil, err - } - if resourceId.NSName, err = id.PopSegment("NS"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/dns/parse/ns_record_test.go b/internal/services/dns/parse/ns_record_test.go deleted file mode 100644 index 694bf6359516..000000000000 --- a/internal/services/dns/parse/ns_record_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "testing" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -var _ resourceids.Id = NsRecordId{} - -func TestNsRecordIDFormatter(t *testing.T) { - actual := NewNsRecordID("12345678-1234-9876-4563-123456789012", "resGroup1", "zone1", "ns1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/NS/ns1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestNsRecordID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *NsRecordId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - - { - // missing DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/", - Error: true, - }, - - { - // missing value for DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/", - Error: true, - }, - - { - // missing NSName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/", - Error: true, - }, - - { - // missing value for NSName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/NS/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/NS/ns1", - Expected: &NsRecordId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - DnszoneName: "zone1", - NSName: "ns1", - }, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.NETWORK/DNSZONES/ZONE1/NS/NS1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := NsRecordID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - if actual.DnszoneName != v.Expected.DnszoneName { - t.Fatalf("Expected %q but got %q for DnszoneName", v.Expected.DnszoneName, actual.DnszoneName) - } - if actual.NSName != v.Expected.NSName { - t.Fatalf("Expected %q but got %q for NSName", v.Expected.NSName, actual.NSName) - } - } -} diff --git a/internal/services/dns/parse/ptr_record.go b/internal/services/dns/parse/ptr_record.go deleted file mode 100644 index e0b4965f0bd3..000000000000 --- a/internal/services/dns/parse/ptr_record.go +++ /dev/null @@ -1,75 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - "strings" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -type PtrRecordId struct { - SubscriptionId string - ResourceGroup string - DnszoneName string - PTRName string -} - -func NewPtrRecordID(subscriptionId, resourceGroup, dnszoneName, pTRName string) PtrRecordId { - return PtrRecordId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourceGroup, - DnszoneName: dnszoneName, - PTRName: pTRName, - } -} - -func (id PtrRecordId) String() string { - segments := []string{ - fmt.Sprintf("P T R Name %q", id.PTRName), - fmt.Sprintf("Dnszone Name %q", id.DnszoneName), - fmt.Sprintf("Resource Group %q", id.ResourceGroup), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Ptr Record", segmentsStr) -} - -func (id PtrRecordId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/dnszones/%s/PTR/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.DnszoneName, id.PTRName) -} - -// PtrRecordID parses a PtrRecord ID into an PtrRecordId struct -func PtrRecordID(input string) (*PtrRecordId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := PtrRecordId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - if resourceId.DnszoneName, err = id.PopSegment("dnszones"); err != nil { - return nil, err - } - if resourceId.PTRName, err = id.PopSegment("PTR"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/dns/parse/ptr_record_test.go b/internal/services/dns/parse/ptr_record_test.go deleted file mode 100644 index f5f0a3fd7ec3..000000000000 --- a/internal/services/dns/parse/ptr_record_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "testing" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -var _ resourceids.Id = PtrRecordId{} - -func TestPtrRecordIDFormatter(t *testing.T) { - actual := NewPtrRecordID("12345678-1234-9876-4563-123456789012", "resGroup1", "zone1", "ptr1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/PTR/ptr1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestPtrRecordID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *PtrRecordId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - - { - // missing DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/", - Error: true, - }, - - { - // missing value for DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/", - Error: true, - }, - - { - // missing PTRName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/", - Error: true, - }, - - { - // missing value for PTRName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/PTR/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/PTR/ptr1", - Expected: &PtrRecordId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - DnszoneName: "zone1", - PTRName: "ptr1", - }, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.NETWORK/DNSZONES/ZONE1/PTR/PTR1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := PtrRecordID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - if actual.DnszoneName != v.Expected.DnszoneName { - t.Fatalf("Expected %q but got %q for DnszoneName", v.Expected.DnszoneName, actual.DnszoneName) - } - if actual.PTRName != v.Expected.PTRName { - t.Fatalf("Expected %q but got %q for PTRName", v.Expected.PTRName, actual.PTRName) - } - } -} diff --git a/internal/services/dns/parse/soa_record.go b/internal/services/dns/parse/soa_record.go new file mode 100644 index 000000000000..350c5604a64a --- /dev/null +++ b/internal/services/dns/parse/soa_record.go @@ -0,0 +1,75 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + "strings" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +type SoaRecordId struct { + SubscriptionId string + ResourceGroup string + DnszoneName string + SOAName string +} + +func NewSoaRecordID(subscriptionId, resourceGroup, dnszoneName, sOAName string) SoaRecordId { + return SoaRecordId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + DnszoneName: dnszoneName, + SOAName: sOAName, + } +} + +func (id SoaRecordId) String() string { + segments := []string{ + fmt.Sprintf("SOA Name %q", id.SOAName), + fmt.Sprintf("Dnszone Name %q", id.DnszoneName), + fmt.Sprintf("Resource Group %q", id.ResourceGroup), + } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "SOA Record", segmentsStr) +} + +func (id SoaRecordId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/dnszones/%s/SOA/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.DnszoneName, id.SOAName) +} + +// SoaRecordID parses a SOARecord ID into an SoaRecordId struct +func SoaRecordID(input string) (*SoaRecordId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := SoaRecordId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + if resourceId.DnszoneName, err = id.PopSegment("dnszones"); err != nil { + return nil, err + } + if resourceId.SOAName, err = id.PopSegment("SOA"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} diff --git a/internal/services/dns/parse/srv_record.go b/internal/services/dns/parse/srv_record.go deleted file mode 100644 index 2006f14bbd63..000000000000 --- a/internal/services/dns/parse/srv_record.go +++ /dev/null @@ -1,75 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - "strings" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -type SrvRecordId struct { - SubscriptionId string - ResourceGroup string - DnszoneName string - SRVName string -} - -func NewSrvRecordID(subscriptionId, resourceGroup, dnszoneName, sRVName string) SrvRecordId { - return SrvRecordId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourceGroup, - DnszoneName: dnszoneName, - SRVName: sRVName, - } -} - -func (id SrvRecordId) String() string { - segments := []string{ - fmt.Sprintf("S R V Name %q", id.SRVName), - fmt.Sprintf("Dnszone Name %q", id.DnszoneName), - fmt.Sprintf("Resource Group %q", id.ResourceGroup), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Srv Record", segmentsStr) -} - -func (id SrvRecordId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/dnszones/%s/SRV/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.DnszoneName, id.SRVName) -} - -// SrvRecordID parses a SrvRecord ID into an SrvRecordId struct -func SrvRecordID(input string) (*SrvRecordId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := SrvRecordId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - if resourceId.DnszoneName, err = id.PopSegment("dnszones"); err != nil { - return nil, err - } - if resourceId.SRVName, err = id.PopSegment("SRV"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/dns/parse/srv_record_test.go b/internal/services/dns/parse/srv_record_test.go deleted file mode 100644 index 14d3f25dab55..000000000000 --- a/internal/services/dns/parse/srv_record_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "testing" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -var _ resourceids.Id = SrvRecordId{} - -func TestSrvRecordIDFormatter(t *testing.T) { - actual := NewSrvRecordID("12345678-1234-9876-4563-123456789012", "resGroup1", "zone1", "srv1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/SRV/srv1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestSrvRecordID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *SrvRecordId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - - { - // missing DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/", - Error: true, - }, - - { - // missing value for DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/", - Error: true, - }, - - { - // missing SRVName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/", - Error: true, - }, - - { - // missing value for SRVName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/SRV/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/SRV/srv1", - Expected: &SrvRecordId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - DnszoneName: "zone1", - SRVName: "srv1", - }, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.NETWORK/DNSZONES/ZONE1/SRV/SRV1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := SrvRecordID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - if actual.DnszoneName != v.Expected.DnszoneName { - t.Fatalf("Expected %q but got %q for DnszoneName", v.Expected.DnszoneName, actual.DnszoneName) - } - if actual.SRVName != v.Expected.SRVName { - t.Fatalf("Expected %q but got %q for SRVName", v.Expected.SRVName, actual.SRVName) - } - } -} diff --git a/internal/services/dns/parse/txt_record.go b/internal/services/dns/parse/txt_record.go deleted file mode 100644 index 57b0bae23501..000000000000 --- a/internal/services/dns/parse/txt_record.go +++ /dev/null @@ -1,75 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - "strings" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -type TxtRecordId struct { - SubscriptionId string - ResourceGroup string - DnszoneName string - TXTName string -} - -func NewTxtRecordID(subscriptionId, resourceGroup, dnszoneName, tXTName string) TxtRecordId { - return TxtRecordId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourceGroup, - DnszoneName: dnszoneName, - TXTName: tXTName, - } -} - -func (id TxtRecordId) String() string { - segments := []string{ - fmt.Sprintf("T X T Name %q", id.TXTName), - fmt.Sprintf("Dnszone Name %q", id.DnszoneName), - fmt.Sprintf("Resource Group %q", id.ResourceGroup), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Txt Record", segmentsStr) -} - -func (id TxtRecordId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/dnszones/%s/TXT/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.DnszoneName, id.TXTName) -} - -// TxtRecordID parses a TxtRecord ID into an TxtRecordId struct -func TxtRecordID(input string) (*TxtRecordId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := TxtRecordId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - if resourceId.DnszoneName, err = id.PopSegment("dnszones"); err != nil { - return nil, err - } - if resourceId.TXTName, err = id.PopSegment("TXT"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/dns/parse/txt_record_test.go b/internal/services/dns/parse/txt_record_test.go deleted file mode 100644 index 37b0d53ec2bc..000000000000 --- a/internal/services/dns/parse/txt_record_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "testing" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -var _ resourceids.Id = TxtRecordId{} - -func TestTxtRecordIDFormatter(t *testing.T) { - actual := NewTxtRecordID("12345678-1234-9876-4563-123456789012", "resGroup1", "zone1", "txt1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/TXT/txt1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestTxtRecordID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *TxtRecordId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - - { - // missing DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/", - Error: true, - }, - - { - // missing value for DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/", - Error: true, - }, - - { - // missing TXTName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/", - Error: true, - }, - - { - // missing value for TXTName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/TXT/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/TXT/txt1", - Expected: &TxtRecordId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - DnszoneName: "zone1", - TXTName: "txt1", - }, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.NETWORK/DNSZONES/ZONE1/TXT/TXT1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := TxtRecordID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - if actual.DnszoneName != v.Expected.DnszoneName { - t.Fatalf("Expected %q but got %q for DnszoneName", v.Expected.DnszoneName, actual.DnszoneName) - } - if actual.TXTName != v.Expected.TXTName { - t.Fatalf("Expected %q but got %q for TXTName", v.Expected.TXTName, actual.TXTName) - } - } -} diff --git a/internal/services/dns/registration.go b/internal/services/dns/registration.go index 4316c2bb110b..34bd173367d4 100644 --- a/internal/services/dns/registration.go +++ b/internal/services/dns/registration.go @@ -28,7 +28,17 @@ func (r Registration) WebsiteCategories() []string { // SupportedDataSources returns the supported Data Sources supported by this Service func (r Registration) SupportedDataSources() map[string]*pluginsdk.Resource { return map[string]*pluginsdk.Resource{ - "azurerm_dns_zone": dataSourceDnsZone(), + "azurerm_dns_a_record": dataSourceDnsARecord(), + "azurerm_dns_aaaa_record": dataSourceDnsAAAARecord(), + "azurerm_dns_caa_record": dataSourceDnsCaaRecord(), + "azurerm_dns_cname_record": dataSourceDnsCNameRecord(), + "azurerm_dns_mx_record": dataSourceDnsMxRecord(), + "azurerm_dns_ns_record": dataSourceDnsNsRecord(), + "azurerm_dns_ptr_record": dataSourceDnsPtrRecord(), + "azurerm_dns_soa_record": dataSourceDnsSoaRecord(), + "azurerm_dns_srv_record": dataSourceDnsSrvRecord(), + "azurerm_dns_txt_record": dataSourceDnsTxtRecord(), + "azurerm_dns_zone": dataSourceDnsZone(), } } diff --git a/internal/services/dns/resourceids.go b/internal/services/dns/resourceids.go deleted file mode 100644 index 4ad419bec34f..000000000000 --- a/internal/services/dns/resourceids.go +++ /dev/null @@ -1,12 +0,0 @@ -package dns - -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=DnsZone -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ARecord -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/A/eh1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=AaaaRecord -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/AAAA/eheh1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=CaaRecord -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/CAA/caa1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=CnameRecord -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/CNAME/name1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=MxRecord -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/MX/mx1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=NsRecord -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/NS/ns1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=PtrRecord -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/PTR/ptr1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=SrvRecord -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/SRV/srv1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=TxtRecord -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/TXT/txt1 diff --git a/internal/services/dns/validate/a_record_id.go b/internal/services/dns/validate/a_record_id.go deleted file mode 100644 index 6d70f11164a0..000000000000 --- a/internal/services/dns/validate/a_record_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/parse" -) - -func ARecordID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.ARecordID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/dns/validate/a_record_id_test.go b/internal/services/dns/validate/a_record_id_test.go deleted file mode 100644 index f6ccc517f5d5..000000000000 --- a/internal/services/dns/validate/a_record_id_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestARecordID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - - { - // empty - Input: "", - Valid: false, - }, - - { - // missing SubscriptionId - Input: "/", - Valid: false, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Valid: false, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Valid: false, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Valid: false, - }, - - { - // missing DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/", - Valid: false, - }, - - { - // missing value for DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/", - Valid: false, - }, - - { - // missing AName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/", - Valid: false, - }, - - { - // missing value for AName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/A/", - Valid: false, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/A/eh1", - Valid: true, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.NETWORK/DNSZONES/ZONE1/A/EH1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := ARecordID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/dns/validate/aaaa_record_id.go b/internal/services/dns/validate/aaaa_record_id.go deleted file mode 100644 index dd75910b3a70..000000000000 --- a/internal/services/dns/validate/aaaa_record_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/parse" -) - -func AaaaRecordID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.AaaaRecordID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/dns/validate/aaaa_record_id_test.go b/internal/services/dns/validate/aaaa_record_id_test.go deleted file mode 100644 index 89378cfceaf9..000000000000 --- a/internal/services/dns/validate/aaaa_record_id_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestAaaaRecordID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - - { - // empty - Input: "", - Valid: false, - }, - - { - // missing SubscriptionId - Input: "/", - Valid: false, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Valid: false, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Valid: false, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Valid: false, - }, - - { - // missing DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/", - Valid: false, - }, - - { - // missing value for DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/", - Valid: false, - }, - - { - // missing AAAAName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/", - Valid: false, - }, - - { - // missing value for AAAAName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/AAAA/", - Valid: false, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/AAAA/eheh1", - Valid: true, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.NETWORK/DNSZONES/ZONE1/AAAA/EHEH1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := AaaaRecordID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/dns/validate/caa_record_id.go b/internal/services/dns/validate/caa_record_id.go deleted file mode 100644 index 4fd6b17485f7..000000000000 --- a/internal/services/dns/validate/caa_record_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/parse" -) - -func CaaRecordID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.CaaRecordID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/dns/validate/caa_record_id_test.go b/internal/services/dns/validate/caa_record_id_test.go deleted file mode 100644 index aa05cd29ef88..000000000000 --- a/internal/services/dns/validate/caa_record_id_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestCaaRecordID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - - { - // empty - Input: "", - Valid: false, - }, - - { - // missing SubscriptionId - Input: "/", - Valid: false, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Valid: false, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Valid: false, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Valid: false, - }, - - { - // missing DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/", - Valid: false, - }, - - { - // missing value for DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/", - Valid: false, - }, - - { - // missing CAAName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/", - Valid: false, - }, - - { - // missing value for CAAName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/CAA/", - Valid: false, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/CAA/caa1", - Valid: true, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.NETWORK/DNSZONES/ZONE1/CAA/CAA1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := CaaRecordID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/dns/validate/cname_record_id.go b/internal/services/dns/validate/cname_record_id.go deleted file mode 100644 index a0a20845f322..000000000000 --- a/internal/services/dns/validate/cname_record_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/parse" -) - -func CnameRecordID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.CnameRecordID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/dns/validate/cname_record_id_test.go b/internal/services/dns/validate/cname_record_id_test.go deleted file mode 100644 index 23c4075e7ccf..000000000000 --- a/internal/services/dns/validate/cname_record_id_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestCnameRecordID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - - { - // empty - Input: "", - Valid: false, - }, - - { - // missing SubscriptionId - Input: "/", - Valid: false, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Valid: false, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Valid: false, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Valid: false, - }, - - { - // missing DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/", - Valid: false, - }, - - { - // missing value for DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/", - Valid: false, - }, - - { - // missing CNAMEName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/", - Valid: false, - }, - - { - // missing value for CNAMEName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/CNAME/", - Valid: false, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/CNAME/name1", - Valid: true, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.NETWORK/DNSZONES/ZONE1/CNAME/NAME1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := CnameRecordID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/dns/validate/dns_zone_id.go b/internal/services/dns/validate/dns_zone_id.go deleted file mode 100644 index 32e9b7d30b17..000000000000 --- a/internal/services/dns/validate/dns_zone_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/parse" -) - -func DnsZoneID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.DnsZoneID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/dns/validate/dns_zone_id_test.go b/internal/services/dns/validate/dns_zone_id_test.go deleted file mode 100644 index e98912a40947..000000000000 --- a/internal/services/dns/validate/dns_zone_id_test.go +++ /dev/null @@ -1,76 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestDnsZoneID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - - { - // empty - Input: "", - Valid: false, - }, - - { - // missing SubscriptionId - Input: "/", - Valid: false, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Valid: false, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Valid: false, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Valid: false, - }, - - { - // missing Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/", - Valid: false, - }, - - { - // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/", - Valid: false, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1", - Valid: true, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.NETWORK/DNSZONES/ZONE1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := DnsZoneID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/dns/validate/mx_record_id.go b/internal/services/dns/validate/mx_record_id.go deleted file mode 100644 index 5bea8660e56e..000000000000 --- a/internal/services/dns/validate/mx_record_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/parse" -) - -func MxRecordID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.MxRecordID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/dns/validate/mx_record_id_test.go b/internal/services/dns/validate/mx_record_id_test.go deleted file mode 100644 index ec999a7d517a..000000000000 --- a/internal/services/dns/validate/mx_record_id_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestMxRecordID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - - { - // empty - Input: "", - Valid: false, - }, - - { - // missing SubscriptionId - Input: "/", - Valid: false, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Valid: false, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Valid: false, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Valid: false, - }, - - { - // missing DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/", - Valid: false, - }, - - { - // missing value for DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/", - Valid: false, - }, - - { - // missing MXName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/", - Valid: false, - }, - - { - // missing value for MXName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/MX/", - Valid: false, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/MX/mx1", - Valid: true, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.NETWORK/DNSZONES/ZONE1/MX/MX1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := MxRecordID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/dns/validate/ns_record_id.go b/internal/services/dns/validate/ns_record_id.go deleted file mode 100644 index 6b808841c897..000000000000 --- a/internal/services/dns/validate/ns_record_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/parse" -) - -func NsRecordID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.NsRecordID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/dns/validate/ns_record_id_test.go b/internal/services/dns/validate/ns_record_id_test.go deleted file mode 100644 index c9710d386833..000000000000 --- a/internal/services/dns/validate/ns_record_id_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestNsRecordID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - - { - // empty - Input: "", - Valid: false, - }, - - { - // missing SubscriptionId - Input: "/", - Valid: false, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Valid: false, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Valid: false, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Valid: false, - }, - - { - // missing DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/", - Valid: false, - }, - - { - // missing value for DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/", - Valid: false, - }, - - { - // missing NSName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/", - Valid: false, - }, - - { - // missing value for NSName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/NS/", - Valid: false, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/NS/ns1", - Valid: true, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.NETWORK/DNSZONES/ZONE1/NS/NS1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := NsRecordID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/dns/validate/ptr_record_id.go b/internal/services/dns/validate/ptr_record_id.go deleted file mode 100644 index 444679b22c17..000000000000 --- a/internal/services/dns/validate/ptr_record_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/parse" -) - -func PtrRecordID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.PtrRecordID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/dns/validate/ptr_record_id_test.go b/internal/services/dns/validate/ptr_record_id_test.go deleted file mode 100644 index 7e526241c55c..000000000000 --- a/internal/services/dns/validate/ptr_record_id_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestPtrRecordID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - - { - // empty - Input: "", - Valid: false, - }, - - { - // missing SubscriptionId - Input: "/", - Valid: false, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Valid: false, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Valid: false, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Valid: false, - }, - - { - // missing DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/", - Valid: false, - }, - - { - // missing value for DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/", - Valid: false, - }, - - { - // missing PTRName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/", - Valid: false, - }, - - { - // missing value for PTRName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/PTR/", - Valid: false, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/PTR/ptr1", - Valid: true, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.NETWORK/DNSZONES/ZONE1/PTR/PTR1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := PtrRecordID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/dns/validate/srv_record_id.go b/internal/services/dns/validate/srv_record_id.go deleted file mode 100644 index 988b99abfc23..000000000000 --- a/internal/services/dns/validate/srv_record_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/parse" -) - -func SrvRecordID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.SrvRecordID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/dns/validate/srv_record_id_test.go b/internal/services/dns/validate/srv_record_id_test.go deleted file mode 100644 index d48d19c45af8..000000000000 --- a/internal/services/dns/validate/srv_record_id_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestSrvRecordID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - - { - // empty - Input: "", - Valid: false, - }, - - { - // missing SubscriptionId - Input: "/", - Valid: false, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Valid: false, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Valid: false, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Valid: false, - }, - - { - // missing DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/", - Valid: false, - }, - - { - // missing value for DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/", - Valid: false, - }, - - { - // missing SRVName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/", - Valid: false, - }, - - { - // missing value for SRVName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/SRV/", - Valid: false, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/SRV/srv1", - Valid: true, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.NETWORK/DNSZONES/ZONE1/SRV/SRV1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := SrvRecordID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/dns/validate/txt_record_id.go b/internal/services/dns/validate/txt_record_id.go deleted file mode 100644 index d4d2b6abad51..000000000000 --- a/internal/services/dns/validate/txt_record_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/dns/parse" -) - -func TxtRecordID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.TxtRecordID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/dns/validate/txt_record_id_test.go b/internal/services/dns/validate/txt_record_id_test.go deleted file mode 100644 index eb23b2b72f55..000000000000 --- a/internal/services/dns/validate/txt_record_id_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestTxtRecordID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - - { - // empty - Input: "", - Valid: false, - }, - - { - // missing SubscriptionId - Input: "/", - Valid: false, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Valid: false, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Valid: false, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Valid: false, - }, - - { - // missing DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/", - Valid: false, - }, - - { - // missing value for DnszoneName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/", - Valid: false, - }, - - { - // missing TXTName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/", - Valid: false, - }, - - { - // missing value for TXTName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/TXT/", - Valid: false, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/dnszones/zone1/TXT/txt1", - Valid: true, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.NETWORK/DNSZONES/ZONE1/TXT/TXT1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := TxtRecordID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/domainservices/active_directory_domain_service_data_source.go b/internal/services/domainservices/active_directory_domain_service_data_source.go index 0785b42199ab..d31b0bb164a4 100644 --- a/internal/services/domainservices/active_directory_domain_service_data_source.go +++ b/internal/services/domainservices/active_directory_domain_service_data_source.go @@ -4,15 +4,15 @@ import ( "fmt" "time" - "github.com/Azure/azure-sdk-for-go/services/domainservices/mgmt/2020-01-01/aad" + "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/aad/2021-05-01/domainservices" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" - "github.com/hashicorp/terraform-provider-azurerm/utils" ) func dataSourceActiveDirectoryDomainService() *pluginsdk.Resource { @@ -129,6 +129,16 @@ func dataSourceActiveDirectoryDomainService() *pluginsdk.Resource { Computed: true, Elem: &pluginsdk.Resource{ Schema: map[string]*pluginsdk.Schema{ + "kerberos_armoring_enabled": { + Type: pluginsdk.TypeBool, + Computed: true, + }, + + "kerberos_rc4_encryption_enabled": { + Type: pluginsdk.TypeBool, + Computed: true, + }, + "ntlm_v1_enabled": { Type: pluginsdk.TypeBool, Computed: true, @@ -167,7 +177,7 @@ func dataSourceActiveDirectoryDomainService() *pluginsdk.Resource { Computed: true, }, - "tags": tags.SchemaDataSource(), + "tags": commonschema.Tags(), "tenant_id": { Type: pluginsdk.TypeString, @@ -220,32 +230,43 @@ func dataSourceActiveDirectoryDomainServiceReplicaSetSchema() map[string]*plugin func dataSourceActiveDirectoryDomainServiceRead(d *pluginsdk.ResourceData, meta interface{}) error { client := meta.(*clients.Client).DomainServices.DomainServicesClient + subscrptionId := meta.(*clients.Client).Account.SubscriptionId ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() name := d.Get("name").(string) resourceGroup := d.Get("resource_group_name").(string) - resp, err := client.Get(ctx, resourceGroup, name) + idsdk := domainservices.NewDomainServiceID(subscrptionId, resourceGroup, name) + + resp, err := client.Get(ctx, idsdk) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { return nil } return err } - if resp.ID == nil { + model := resp.Model + if model == nil { + return fmt.Errorf("reading Domain Service: model was returned nil") + } + + if model.Id == nil { return fmt.Errorf("reading Domain Service: ID was returned nil") } - d.SetId(*resp.ID) + + d.SetId(idsdk.ID()) d.Set("name", name) d.Set("resource_group_name", resourceGroup) + d.Set("location", location.NormalizeNilable(model.Location)) + if err := tags.FlattenAndSet(d, model.Tags); err != nil { + return err + } - d.Set("location", location.NormalizeNilable(resp.Location)) - - if props := resp.DomainServiceProperties; props != nil { - d.Set("deployment_id", props.DeploymentID) + if props := model.Properties; props != nil { + d.Set("deployment_id", props.DeploymentId) domainConfigType := "" if v := props.DomainConfigurationType; v != nil { @@ -256,14 +277,14 @@ func dataSourceActiveDirectoryDomainServiceRead(d *pluginsdk.ResourceData, meta d.Set("domain_name", props.DomainName) d.Set("filtered_sync_enabled", false) - if props.FilteredSync == aad.FilteredSyncEnabled { + if props.FilteredSync != nil && *props.FilteredSync == domainservices.FilteredSyncEnabled { d.Set("filtered_sync_enabled", true) } - d.Set("resource_id", resp.ID) + d.Set("resource_id", model.Id) d.Set("sku", props.Sku) d.Set("sync_owner", props.SyncOwner) - d.Set("tenant_id", props.TenantID) + d.Set("tenant_id", props.TenantId) d.Set("version", props.Version) if err := d.Set("notifications", flattenDomainServiceNotifications(props.NotificationSettings)); err != nil { @@ -284,5 +305,5 @@ func dataSourceActiveDirectoryDomainServiceRead(d *pluginsdk.ResourceData, meta } } - return tags.FlattenAndSet(d, resp.Tags) + return nil } diff --git a/internal/services/domainservices/active_directory_domain_service_replica_set_resource.go b/internal/services/domainservices/active_directory_domain_service_replica_set_resource.go index 9059a63e5fbe..9d5a88fe02f5 100644 --- a/internal/services/domainservices/active_directory_domain_service_replica_set_resource.go +++ b/internal/services/domainservices/active_directory_domain_service_replica_set_resource.go @@ -5,8 +5,9 @@ import ( "strings" "time" - "github.com/Azure/azure-sdk-for-go/services/domainservices/mgmt/2020-01-01/aad" + "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/go-azure-sdk/resource-manager/aad/2021-05-01/domainservices" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" @@ -88,82 +89,90 @@ func resourceActiveDirectoryDomainServiceReplicaSetCreate(d *pluginsdk.ResourceD return fmt.Errorf("parsing ID for Domain Service Replica Set") } + idsdk := domainservices.NewDomainServiceID(domainServiceId.SubscriptionId, domainServiceId.ResourceGroup, domainServiceId.Name) + locks.ByName(domainServiceId.Name, DomainServiceResourceName) defer locks.UnlockByName(domainServiceId.Name, DomainServiceResourceName) - domainService, err := client.Get(ctx, domainServiceId.ResourceGroup, domainServiceId.Name) + domainService, err := client.Get(ctx, idsdk) if err != nil { - if utils.ResponseWasNotFound(domainService.Response) { + if response.WasNotFound(domainService.HttpResponse) { return fmt.Errorf("could not find %s: %s", domainServiceId, err) } return fmt.Errorf("reading %s: %s", domainServiceId, err) } - if domainService.DomainServiceProperties.ReplicaSets == nil || len(*domainService.DomainServiceProperties.ReplicaSets) == 0 { - return fmt.Errorf("reading %s: returned with missing replica set information, expected at least 1 replica set: %s", domainServiceId, err) + model := domainService.Model + if model == nil { + return fmt.Errorf("reading %s: returned with null model", domainServiceId) + } + + if model.Properties == nil || model.Properties.ReplicaSets == nil || len(*model.Properties.ReplicaSets) == 0 { + return fmt.Errorf("reading %s: returned with missing replica set information, expected at least 1 replica set", domainServiceId) } subnetId := d.Get("subnet_id").(string) - replicaSets := *domainService.DomainServiceProperties.ReplicaSets + replicaSets := *model.Properties.ReplicaSets for _, r := range replicaSets { - if r.ReplicaSetID == nil { + if r.ReplicaSetId == nil { return fmt.Errorf("reading %s: a replica set was returned with a missing ReplicaSetID", domainServiceId) } - if r.SubnetID == nil { + if r.SubnetId == nil { return fmt.Errorf("reading %s: a replica set was returned with a missing SubnetID", domainServiceId) } // We assume that two replica sets cannot coexist in the same subnet - if strings.EqualFold(subnetId, *r.SubnetID) { + if strings.EqualFold(subnetId, *r.SubnetId) { // Generate an ID here since we only know it once we know the ReplicaSetID - id := parse.NewDomainServiceReplicaSetID(domainServiceId.SubscriptionId, domainServiceId.ResourceGroup, domainServiceId.Name, *r.ReplicaSetID) + id := parse.NewDomainServiceReplicaSetID(domainServiceId.SubscriptionId, domainServiceId.ResourceGroup, domainServiceId.Name, *r.ReplicaSetId) return tf.ImportAsExistsError("azurerm_active_directory_domain_service_replica_set", id.ID()) } } loc := location.Normalize(d.Get("location").(string)) - replicaSets = append(replicaSets, aad.ReplicaSet{ + replicaSets = append(replicaSets, domainservices.ReplicaSet{ Location: utils.String(loc), - SubnetID: utils.String(subnetId), + SubnetId: utils.String(subnetId), }) - domainService.DomainServiceProperties.ReplicaSets = &replicaSets + model.Properties.ReplicaSets = &replicaSets - future, err := client.CreateOrUpdate(ctx, domainServiceId.ResourceGroup, domainServiceId.Name, domainService) - if err != nil { + if err := client.CreateOrUpdateThenPoll(ctx, idsdk, *model); err != nil { return fmt.Errorf("creating/updating Replica Sets for %s: %+v", domainServiceId, err) } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for Replica Sets for %s: %+v", domainServiceId, err) - } // We need to retrieve the domain service again to find out the new replica set ID - domainService, err = client.Get(ctx, domainServiceId.ResourceGroup, domainServiceId.Name) + domainService, err = client.Get(ctx, idsdk) if err != nil { - if utils.ResponseWasNotFound(domainService.Response) { + if response.WasNotFound(domainService.HttpResponse) { return fmt.Errorf("could not find %s: %s", domainServiceId, err) } return fmt.Errorf("reading %s: %s", domainServiceId, err) } - if domainService.DomainServiceProperties.ReplicaSets == nil || len(*domainService.DomainServiceProperties.ReplicaSets) == 0 { - return fmt.Errorf("reading %s: returned with missing replica set information, expected at least 1 replica set: %s", domainServiceId, err) + model = domainService.Model + if model == nil { + return fmt.Errorf("reading %s: returned with null model", domainServiceId) + } + + if model.Properties == nil || model.Properties.ReplicaSets == nil || len(*model.Properties.ReplicaSets) == 0 { + return fmt.Errorf("reading %s: returned with missing replica set information, expected at least 1 replica set", domainServiceId) } var id parse.DomainServiceReplicaSetId // Assuming that two replica sets cannot coexist in the same subnet, we identify our new replica set by its SubnetID - for _, r := range *domainService.DomainServiceProperties.ReplicaSets { - if r.ReplicaSetID == nil { + for _, r := range *model.Properties.ReplicaSets { + if r.ReplicaSetId == nil { return fmt.Errorf("reading %s: a replica set was returned with a missing ReplicaSetID", domainServiceId) } - if r.SubnetID == nil { + if r.SubnetId == nil { return fmt.Errorf("reading %s: a replica set was returned with a missing SubnetID", domainServiceId) } - if strings.EqualFold(subnetId, *r.SubnetID) { + if strings.EqualFold(subnetId, *r.SubnetId) { // We found it! - id = parse.NewDomainServiceReplicaSetID(domainServiceId.SubscriptionId, domainServiceId.ResourceGroup, domainServiceId.Name, *r.ReplicaSetID) + id = parse.NewDomainServiceReplicaSetID(domainServiceId.SubscriptionId, domainServiceId.ResourceGroup, domainServiceId.Name, *r.ReplicaSetId) } } @@ -201,41 +210,48 @@ func resourceActiveDirectoryDomainServiceReplicaSetRead(d *pluginsdk.ResourceDat return err } - domainService, err := client.Get(ctx, id.ResourceGroup, id.DomainServiceName) + idsdk := domainservices.NewDomainServiceID(id.SubscriptionId, id.ResourceGroup, id.DomainServiceName) + + domainService, err := client.Get(ctx, idsdk) if err != nil { - if utils.ResponseWasNotFound(domainService.Response) { + if response.WasNotFound(domainService.HttpResponse) { d.SetId("") return nil } return err } - if domainService.DomainServiceProperties.ReplicaSets == nil || len(*domainService.DomainServiceProperties.ReplicaSets) == 0 { - return fmt.Errorf("reading %s: domain service returned with missing replica set information, expected at least 1 replica set: %s", id, err) + model := domainService.Model + if model == nil { + return fmt.Errorf("reading %s: returned with null model", id) + } + + if model.Properties == nil || model.Properties.ReplicaSets == nil || len(*model.Properties.ReplicaSets) == 0 { + return fmt.Errorf("reading %s: returned with missing replica set information, expected at least 1 replica set", id) } var ( - domainControllerIpAddresses []string - externalAccessIpAddress string + domainControllerIPAddresses []string + externalAccessIPAddress string loc string serviceStatus string subnetId string ) - replicaSets := *domainService.DomainServiceProperties.ReplicaSets + replicaSets := *model.Properties.ReplicaSets for _, r := range replicaSets { - if r.ReplicaSetID == nil { + if r.ReplicaSetId == nil { return fmt.Errorf("reading %s: a replica set was returned with a missing ReplicaSetID", id) } // ReplicaSetName in the ID struct is really the replica set ID - if *r.ReplicaSetID == id.ReplicaSetName { + if *r.ReplicaSetId == id.ReplicaSetName { if r.DomainControllerIPAddress != nil { - domainControllerIpAddresses = *r.DomainControllerIPAddress + domainControllerIPAddresses = *r.DomainControllerIPAddress } if r.ExternalAccessIPAddress != nil { - externalAccessIpAddress = *r.ExternalAccessIPAddress + externalAccessIPAddress = *r.ExternalAccessIPAddress } if r.Location != nil { loc = location.NormalizeNilable(r.Location) @@ -243,14 +259,14 @@ func resourceActiveDirectoryDomainServiceReplicaSetRead(d *pluginsdk.ResourceDat if r.ServiceStatus != nil { serviceStatus = *r.ServiceStatus } - if r.SubnetID != nil { - subnetId = *r.SubnetID + if r.SubnetId != nil { + subnetId = *r.SubnetId } } } - d.Set("domain_controller_ip_addresses", domainControllerIpAddresses) - d.Set("external_access_ip_address", externalAccessIpAddress) + d.Set("domain_controller_ip_addresses", domainControllerIPAddresses) + d.Set("external_access_ip_address", externalAccessIPAddress) d.Set("location", loc) d.Set("service_status", serviceStatus) d.Set("subnet_id", subnetId) @@ -268,27 +284,34 @@ func resourceActiveDirectoryDomainServiceReplicaSetDelete(d *pluginsdk.ResourceD return err } - domainService, err := client.Get(ctx, id.ResourceGroup, id.DomainServiceName) + idsdk := domainservices.NewDomainServiceID(id.SubscriptionId, id.ResourceGroup, id.DomainServiceName) + + domainService, err := client.Get(ctx, idsdk) if err != nil { - if utils.ResponseWasNotFound(domainService.Response) { + if response.WasNotFound(domainService.HttpResponse) { return fmt.Errorf("deleting %s: domain service was not found: %s", id, err) } return err } - if domainService.DomainServiceProperties.ReplicaSets == nil || len(*domainService.DomainServiceProperties.ReplicaSets) == 0 { - return fmt.Errorf("deleting %s: domain service returned with missing replica set information, expected at least 1 replica set: %s", id, err) + model := domainService.Model + if model == nil { + return fmt.Errorf("reading %s: returned with null model", id) } - replicaSets := *domainService.DomainServiceProperties.ReplicaSets + if model.Properties == nil || model.Properties.ReplicaSets == nil || len(*model.Properties.ReplicaSets) == 0 { + return fmt.Errorf("reading %s: returned with missing replica set information, expected at least 1 replica set", id) + } - newReplicaSets := make([]aad.ReplicaSet, 0) + replicaSets := *model.Properties.ReplicaSets + + newReplicaSets := make([]domainservices.ReplicaSet, 0) for _, r := range replicaSets { - if r.ReplicaSetID == nil { + if r.ReplicaSetId == nil { return fmt.Errorf("deleting %s: a replica set was returned with a missing ReplicaSetID", id) } - if *r.ReplicaSetID == id.ReplicaSetName { + if *r.ReplicaSetId == id.ReplicaSetName { continue } @@ -299,15 +322,11 @@ func resourceActiveDirectoryDomainServiceReplicaSetDelete(d *pluginsdk.ResourceD return fmt.Errorf("deleting %s: could not determine which replica set to remove", id) } - domainService.DomainServiceProperties.ReplicaSets = &newReplicaSets + model.Properties.ReplicaSets = &newReplicaSets - future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.DomainServiceName, domainService) - if err != nil { + if err := client.CreateOrUpdateThenPoll(ctx, idsdk, *model); err != nil { return fmt.Errorf("deleting %s: %+v", id, err) } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for deletion of %s: %+v", id, err) - } // Wait for all replica sets to become available with two domain controllers each before proceeding // Generate a partial DomainServiceId since we don't need to know the initial replica set ID here diff --git a/internal/services/domainservices/active_directory_domain_service_resource.go b/internal/services/domainservices/active_directory_domain_service_resource.go index 102a41f641b1..82e7b0571215 100644 --- a/internal/services/domainservices/active_directory_domain_service_resource.go +++ b/internal/services/domainservices/active_directory_domain_service_resource.go @@ -7,18 +7,17 @@ import ( "strings" "time" - "github.com/Azure/azure-sdk-for-go/services/domainservices/mgmt/2020-01-01/aad" "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" - "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/aad/2021-05-01/domainservices" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" azValidate "github.com/hashicorp/terraform-provider-azurerm/helpers/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/locks" "github.com/hashicorp/terraform-provider-azurerm/internal/services/domainservices/parse" networkValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/validate" - "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" @@ -54,9 +53,9 @@ func resourceActiveDirectoryDomainService() *pluginsdk.Resource { ValidateFunc: validation.StringIsNotEmpty, // TODO: proper validation }, - "location": azure.SchemaLocation(), + "location": commonschema.Location(), - "resource_group_name": azure.SchemaResourceGroupName(), + "resource_group_name": commonschema.ResourceGroupName(), "domain_name": { Type: pluginsdk.TypeString, @@ -211,6 +210,18 @@ func resourceActiveDirectoryDomainService() *pluginsdk.Resource { MaxItems: 1, Elem: &pluginsdk.Resource{ Schema: map[string]*pluginsdk.Schema{ + "kerberos_armoring_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: false, + }, + + "kerberos_rc4_encryption_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: false, + }, + "ntlm_v1_enabled": { Type: pluginsdk.TypeBool, Optional: true, @@ -254,7 +265,7 @@ func resourceActiveDirectoryDomainService() *pluginsdk.Resource { }, false), }, - "tags": tags.Schema(), + "tags": commonschema.Tags(), "deployment_id": { Type: pluginsdk.TypeString, @@ -286,6 +297,7 @@ func resourceActiveDirectoryDomainService() *pluginsdk.Resource { func resourceActiveDirectoryDomainServiceCreateUpdate(d *pluginsdk.ResourceData, meta interface{}) error { client := meta.(*clients.Client).DomainServices.DomainServicesClient + subscriptionId := meta.(*clients.Client).Account.SubscriptionId ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) defer cancel() @@ -300,18 +312,24 @@ func resourceActiveDirectoryDomainServiceCreateUpdate(d *pluginsdk.ResourceData, // know the ID of the first replica set. var id *parse.DomainServiceId + idsdk := domainservices.NewDomainServiceID(subscriptionId, resourceGroup, name) + if d.IsNewResource() { - existing, err := client.Get(ctx, resourceGroup, name) + existing, err := client.Get(ctx, idsdk) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return fmt.Errorf("checking for presence of existing %s: %s", resourceErrorName, err) } } - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { // Parse the replica sets and assume the first one returned to be the initial replica set // This is a best effort and the user can choose any replica set if they structure their config accordingly - props := existing.DomainServiceProperties + model := existing.Model + if model == nil { + return fmt.Errorf("checking for presence of existing %s: API response contained nil or missing model", resourceErrorName) + } + props := model.Properties if props == nil { return fmt.Errorf("checking for presence of existing %s: API response contained nil or missing properties", resourceErrorName) } @@ -320,7 +338,7 @@ func resourceActiveDirectoryDomainServiceCreateUpdate(d *pluginsdk.ResourceData, return fmt.Errorf("checking for presence of existing %s: API response contained nil or missing replica set details", resourceErrorName) } initialReplicaSetId := replicaSets[0].(map[string]interface{})["id"].(string) - id := parse.NewDomainServiceID(client.SubscriptionID, resourceGroup, name, initialReplicaSetId) + id := parse.NewDomainServiceID(subscriptionId, resourceGroup, name, initialReplicaSetId) return tf.ImportAsExistsError(DomainServiceResourceName, id.ID()) } @@ -336,16 +354,16 @@ func resourceActiveDirectoryDomainServiceCreateUpdate(d *pluginsdk.ResourceData, } loc := location.Normalize(d.Get("location").(string)) - filteredSync := aad.FilteredSyncDisabled + filteredSync := domainservices.FilteredSyncDisabled if d.Get("filtered_sync_enabled").(bool) { - filteredSync = aad.FilteredSyncDisabled + filteredSync = domainservices.FilteredSyncDisabled } - domainService := aad.DomainService{ - DomainServiceProperties: &aad.DomainServiceProperties{ + domainService := domainservices.DomainService{ + Properties: &domainservices.DomainServiceProperties{ DomainName: utils.String(d.Get("domain_name").(string)), DomainSecuritySettings: expandDomainServiceSecurity(d.Get("security").([]interface{})), - FilteredSync: filteredSync, + FilteredSync: &filteredSync, LdapsSettings: expandDomainServiceLdaps(d.Get("secure_ldap").([]interface{})), NotificationSettings: expandDomainServiceNotifications(d.Get("notifications").([]interface{})), Sku: utils.String(d.Get("sku").(string)), @@ -355,36 +373,36 @@ func resourceActiveDirectoryDomainServiceCreateUpdate(d *pluginsdk.ResourceData, } if v := d.Get("domain_configuration_type").(string); v != "" { - domainService.DomainServiceProperties.DomainConfigurationType = &v + domainService.Properties.DomainConfigurationType = &v } if d.IsNewResource() { // On resource creation, specify the initial replica set. // No provision is made for changing the initial replica set, it should remain intact for the resource to function properly - replicaSets := []aad.ReplicaSet{ + replicaSets := []domainservices.ReplicaSet{ { Location: utils.String(loc), - SubnetID: utils.String(d.Get("initial_replica_set.0.subnet_id").(string)), + SubnetId: utils.String(d.Get("initial_replica_set.0.subnet_id").(string)), }, } - domainService.DomainServiceProperties.ReplicaSets = &replicaSets + domainService.Properties.ReplicaSets = &replicaSets } - future, err := client.CreateOrUpdate(ctx, resourceGroup, name, domainService) - if err != nil { + if err := client.CreateOrUpdateThenPoll(ctx, idsdk, domainService); err != nil { return fmt.Errorf("creating/updating %s: %+v", resourceErrorName, err) } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for %s: %+v", resourceErrorName, err) - } // Retrieve the domain service to discover the unique ID for the initial replica set, which should not subsequently change if d.IsNewResource() { - resp, err := client.Get(ctx, resourceGroup, name) + resp, err := client.Get(ctx, idsdk) if err != nil { return fmt.Errorf("retrieving %s after creating: %+v", resourceErrorName, err) } - props := resp.DomainServiceProperties + model := resp.Model + if model == nil { + return fmt.Errorf("%s returned with no model", resourceErrorName) + } + props := model.Properties if props == nil { return fmt.Errorf("%s returned with no properties", resourceErrorName) } @@ -399,7 +417,7 @@ func resourceActiveDirectoryDomainServiceCreateUpdate(d *pluginsdk.ResourceData, // Once we know the initial replica set ID, we can build a resource ID initialReplicaSetId := replicaSets[0].(map[string]interface{})["id"].(string) - newId := parse.NewDomainServiceID(client.SubscriptionID, resourceGroup, name, initialReplicaSetId) + newId := parse.NewDomainServiceID(subscriptionId, resourceGroup, name, initialReplicaSetId) id = &newId d.SetId(id.ID()) @@ -441,9 +459,11 @@ func resourceActiveDirectoryDomainServiceRead(d *pluginsdk.ResourceData, meta in return err } - resp, err := client.Get(ctx, id.ResourceGroup, id.Name) + idsdk := domainservices.NewDomainServiceID(id.SubscriptionId, id.ResourceGroup, id.Name) + + resp, err := client.Get(ctx, idsdk) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { d.SetId("") return nil } @@ -452,59 +472,64 @@ func resourceActiveDirectoryDomainServiceRead(d *pluginsdk.ResourceData, meta in d.Set("name", id.Name) d.Set("resource_group_name", id.ResourceGroup) - d.Set("resource_id", resp.ID) - d.Set("location", location.NormalizeNilable(resp.Location)) + if model := resp.Model; model != nil { + d.Set("location", location.NormalizeNilable(model.Location)) + d.Set("resource_id", model.Id) + if err := tags.FlattenAndSet(d, model.Tags); err != nil { + return err + } - if props := resp.DomainServiceProperties; props != nil { - d.Set("deployment_id", props.DeploymentID) - d.Set("domain_name", props.DomainName) - d.Set("sync_owner", props.SyncOwner) - d.Set("tenant_id", props.TenantID) - d.Set("version", props.Version) - d.Set("domain_configuration_type", props.DomainConfigurationType) + if props := model.Properties; props != nil { + d.Set("deployment_id", props.DeploymentId) + d.Set("domain_name", props.DomainName) + d.Set("sync_owner", props.SyncOwner) + d.Set("tenant_id", props.TenantId) + d.Set("version", props.Version) + d.Set("domain_configuration_type", props.DomainConfigurationType) - d.Set("filtered_sync_enabled", false) - if props.FilteredSync == aad.FilteredSyncEnabled { - d.Set("filtered_sync_enabled", true) - } + d.Set("filtered_sync_enabled", false) + if props.FilteredSync != nil && *props.FilteredSync == domainservices.FilteredSyncEnabled { + d.Set("filtered_sync_enabled", true) + } - d.Set("sku", props.Sku) + d.Set("sku", props.Sku) - if err := d.Set("notifications", flattenDomainServiceNotifications(props.NotificationSettings)); err != nil { - return fmt.Errorf("setting `notifications`: %+v", err) - } + if err := d.Set("notifications", flattenDomainServiceNotifications(props.NotificationSettings)); err != nil { + return fmt.Errorf("setting `notifications`: %+v", err) + } - var initialReplicaSet interface{} - replicaSets := flattenDomainServiceReplicaSets(props.ReplicaSets) + var initialReplicaSet interface{} + replicaSets := flattenDomainServiceReplicaSets(props.ReplicaSets) - // Determine the initial replica set. This is why we need to include InitialReplicaSetId in the resource ID, - // without it we would not be able to reliably support importing. - for _, replicaSetRaw := range replicaSets { - replicaSet := replicaSetRaw.(map[string]interface{}) - if replicaSet["id"].(string) == id.InitialReplicaSetIdName { - initialReplicaSet = replicaSetRaw - break + // Determine the initial replica set. This is why we need to include InitialReplicaSetId in the resource ID, + // without it we would not be able to reliably support importing. + for _, replicaSetRaw := range replicaSets { + replicaSet := replicaSetRaw.(map[string]interface{}) + if replicaSet["id"].(string) == id.InitialReplicaSetIdName { + initialReplicaSet = replicaSetRaw + break + } + } + if initialReplicaSet == nil { + // It's safest to error out here, since we don't want to wipe the initial replica set from state if it was deleted manually + return fmt.Errorf("reading %s: could not determine initial replica set from API response", id) + } + if err := d.Set("initial_replica_set", []interface{}{initialReplicaSet}); err != nil { + return fmt.Errorf("setting `initial_replica_set`: %+v", err) } - } - if initialReplicaSet == nil { - // It's safest to error out here, since we don't want to wipe the initial replica set from state if it was deleted manually - return fmt.Errorf("reading %s: could not determine initial replica set from API response", id) - } - if err := d.Set("initial_replica_set", []interface{}{initialReplicaSet}); err != nil { - return fmt.Errorf("setting `initial_replica_set`: %+v", err) - } - if err := d.Set("secure_ldap", flattenDomainServiceLdaps(d, props.LdapsSettings, false)); err != nil { - return fmt.Errorf("setting `secure_ldap`: %+v", err) - } + if err := d.Set("secure_ldap", flattenDomainServiceLdaps(d, props.LdapsSettings, false)); err != nil { + return fmt.Errorf("setting `secure_ldap`: %+v", err) + } - if err := d.Set("security", flattenDomainServiceSecurity(props.DomainSecuritySettings)); err != nil { - return fmt.Errorf("setting `security`: %+v", err) + if err := d.Set("security", flattenDomainServiceSecurity(props.DomainSecuritySettings)); err != nil { + return fmt.Errorf("setting `security`: %+v", err) + } } } - return tags.FlattenAndSet(d, resp.Tags) + return nil } func resourceActiveDirectoryDomainServiceDelete(d *pluginsdk.ResourceData, meta interface{}) error { @@ -517,32 +542,28 @@ func resourceActiveDirectoryDomainServiceDelete(d *pluginsdk.ResourceData, meta return err } - future, err := client.Delete(ctx, id.ResourceGroup, id.Name) - if err != nil { - return fmt.Errorf("deleting %s: %+v", id, err) - } + idsdk := domainservices.NewDomainServiceID(id.SubscriptionId, id.ResourceGroup, id.Name) - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - if !response.WasNotFound(future.Response()) { - return fmt.Errorf("waiting for deletion of %s: %+v", id, err) - } + if err := client.DeleteThenPoll(ctx, idsdk); err != nil { + return fmt.Errorf("deleting %s: %+v", id, err) } return nil } -func domainServiceControllerRefreshFunc(ctx context.Context, client *aad.DomainServicesClient, id parse.DomainServiceId, deleting bool) pluginsdk.StateRefreshFunc { +func domainServiceControllerRefreshFunc(ctx context.Context, client *domainservices.DomainServicesClient, id parse.DomainServiceId, deleting bool) pluginsdk.StateRefreshFunc { return func() (interface{}, string, error) { log.Printf("[DEBUG] Waiting for domain controllers to deploy...") - resp, err := client.Get(ctx, id.ResourceGroup, id.Name) + idsdk := domainservices.NewDomainServiceID(id.SubscriptionId, id.ResourceGroup, id.Name) + resp, err := client.Get(ctx, idsdk) if err != nil { return nil, "error", err } - if resp.DomainServiceProperties == nil || resp.DomainServiceProperties.ReplicaSets == nil || len(*resp.DomainServiceProperties.ReplicaSets) == 0 { + if model := resp.Model; model == nil || model.Properties == nil || model.Properties.ReplicaSets == nil || len(*model.Properties.ReplicaSets) == 0 { return nil, "error", fmt.Errorf("API error: `replicaSets` was not returned") } // Loop through all replica sets and ensure they are running and each have two available domain controllers - for _, repl := range *resp.DomainServiceProperties.ReplicaSets { + for _, repl := range *resp.Model.Properties.ReplicaSets { if repl.ServiceStatus == nil { return resp, "pending", nil } @@ -565,29 +586,30 @@ func domainServiceControllerRefreshFunc(ctx context.Context, client *aad.DomainS } } -func expandDomainServiceLdaps(input []interface{}) (ldaps *aad.LdapsSettings) { - ldaps = &aad.LdapsSettings{ - Ldaps: aad.LdapsDisabled, +func expandDomainServiceLdaps(input []interface{}) (ldaps *domainservices.LdapsSettings) { + state := domainservices.LdapsDisabled + ldaps = &domainservices.LdapsSettings{ + Ldaps: &state, } if len(input) > 0 { v := input[0].(map[string]interface{}) if v["enabled"].(bool) { - ldaps.Ldaps = aad.LdapsEnabled + *ldaps.Ldaps = domainservices.LdapsEnabled } ldaps.PfxCertificate = utils.String(v["pfx_certificate"].(string)) ldaps.PfxCertificatePassword = utils.String(v["pfx_certificate_password"].(string)) + access := domainservices.ExternalAccessDisabled if v["external_access_enabled"].(bool) { - ldaps.ExternalAccess = aad.Enabled - } else { - ldaps.ExternalAccess = aad.Disabled + access = domainservices.ExternalAccessEnabled } + ldaps.ExternalAccess = &access } return } -func expandDomainServiceNotifications(input []interface{}) *aad.NotificationSettings { +func expandDomainServiceNotifications(input []interface{}) *domainservices.NotificationSettings { if len(input) == 0 { return nil } @@ -601,61 +623,71 @@ func expandDomainServiceNotifications(input []interface{}) *aad.NotificationSett } } - notifyDcAdmins := aad.NotifyDcAdminsDisabled + notifyDcAdmins := domainservices.NotifyDcAdminsDisabled if n, ok := v["notify_dc_admins"]; ok && n.(bool) { - notifyDcAdmins = aad.NotifyDcAdminsEnabled + notifyDcAdmins = domainservices.NotifyDcAdminsEnabled } - notifyGlobalAdmins := aad.NotifyGlobalAdminsDisabled + notifyGlobalAdmins := domainservices.NotifyGlobalAdminsDisabled if n, ok := v["notify_global_admins"]; ok && n.(bool) { - notifyGlobalAdmins = aad.NotifyGlobalAdminsEnabled + notifyGlobalAdmins = domainservices.NotifyGlobalAdminsEnabled } - return &aad.NotificationSettings{ + return &domainservices.NotificationSettings{ AdditionalRecipients: &additionalRecipients, - NotifyDcAdmins: notifyDcAdmins, - NotifyGlobalAdmins: notifyGlobalAdmins, + NotifyDcAdmins: ¬ifyDcAdmins, + NotifyGlobalAdmins: ¬ifyGlobalAdmins, } } -func expandDomainServiceSecurity(input []interface{}) *aad.DomainSecuritySettings { +func expandDomainServiceSecurity(input []interface{}) *domainservices.DomainSecuritySettings { if len(input) == 0 { return nil } v := input[0].(map[string]interface{}) - ntlmV1 := aad.NtlmV1Disabled - syncKerberosPasswords := aad.SyncKerberosPasswordsDisabled - syncNtlmPasswords := aad.SyncNtlmPasswordsDisabled - syncOnPremPasswords := aad.SyncOnPremPasswordsDisabled - tlsV1 := aad.TLSV1Disabled + kerberosRc4Encryption := domainservices.KerberosRc4EncryptionDisabled + kerberosArmoring := domainservices.KerberosArmoringDisabled + ntlmV1 := domainservices.NtlmV1Disabled + syncKerberosPasswords := domainservices.SyncKerberosPasswordsDisabled + syncNtlmPasswords := domainservices.SyncNtlmPasswordsDisabled + syncOnPremPasswords := domainservices.SyncOnPremPasswordsDisabled + tlsV1 := domainservices.TlsV1Disabled + if v["kerberos_armoring_enabled"].(bool) { + kerberosArmoring = domainservices.KerberosArmoringEnabled + } + if v["kerberos_rc4_encryption_enabled"].(bool) { + kerberosRc4Encryption = domainservices.KerberosRc4EncryptionEnabled + } if v["ntlm_v1_enabled"].(bool) { - ntlmV1 = aad.NtlmV1Enabled + ntlmV1 = domainservices.NtlmV1Enabled } if v["sync_kerberos_passwords"].(bool) { - syncKerberosPasswords = aad.SyncKerberosPasswordsEnabled + syncKerberosPasswords = domainservices.SyncKerberosPasswordsEnabled } if v["sync_ntlm_passwords"].(bool) { - syncNtlmPasswords = aad.SyncNtlmPasswordsEnabled + syncNtlmPasswords = domainservices.SyncNtlmPasswordsEnabled } if v["sync_on_prem_passwords"].(bool) { - syncOnPremPasswords = aad.SyncOnPremPasswordsEnabled + syncOnPremPasswords = domainservices.SyncOnPremPasswordsEnabled } if v["tls_v1_enabled"].(bool) { - tlsV1 = aad.TLSV1Enabled + tlsV1 = domainservices.TlsV1Enabled } - return &aad.DomainSecuritySettings{ - NtlmV1: ntlmV1, - SyncKerberosPasswords: syncKerberosPasswords, - SyncNtlmPasswords: syncNtlmPasswords, - SyncOnPremPasswords: syncOnPremPasswords, - TLSV1: tlsV1, + return &domainservices.DomainSecuritySettings{ + KerberosArmoring: &kerberosArmoring, + KerberosRc4Encryption: &kerberosRc4Encryption, + NtlmV1: &ntlmV1, + SyncKerberosPasswords: &syncKerberosPasswords, + SyncNtlmPasswords: &syncNtlmPasswords, + SyncOnPremPasswords: &syncOnPremPasswords, + TlsV1: &tlsV1, } } -func flattenDomainServiceLdaps(d *pluginsdk.ResourceData, input *aad.LdapsSettings, dataSource bool) []interface{} { +func flattenDomainServiceLdaps(d *pluginsdk.ResourceData, input *domainservices.LdapsSettings, dataSource bool) []interface{} { result := map[string]interface{}{ "enabled": false, "external_access_enabled": false, @@ -677,14 +709,14 @@ func flattenDomainServiceLdaps(d *pluginsdk.ResourceData, input *aad.LdapsSettin } if input != nil { - if input.ExternalAccess == aad.Enabled { + if input.ExternalAccess != nil && *input.ExternalAccess == domainservices.ExternalAccessEnabled { result["external_access_enabled"] = true } - if input.Ldaps == aad.LdapsEnabled { + if input.Ldaps != nil && *input.Ldaps == domainservices.LdapsEnabled { result["enabled"] = true } if v := input.CertificateNotAfter; v != nil { - result["certificate_expiry"] = v.Format(time.RFC3339) + result["certificate_expiry"] = *v } if v := input.CertificateThumbprint; v != nil { result["certificate_thumbprint"] = *v @@ -697,7 +729,7 @@ func flattenDomainServiceLdaps(d *pluginsdk.ResourceData, input *aad.LdapsSettin return []interface{}{result} } -func flattenDomainServiceNotifications(input *aad.NotificationSettings) []interface{} { +func flattenDomainServiceNotifications(input *domainservices.NotificationSettings) []interface{} { if input == nil { return make([]interface{}, 0) } @@ -710,17 +742,17 @@ func flattenDomainServiceNotifications(input *aad.NotificationSettings) []interf if input.AdditionalRecipients != nil { result["additional_recipients"] = *input.AdditionalRecipients } - if input.NotifyDcAdmins == aad.NotifyDcAdminsEnabled { + if input.NotifyDcAdmins != nil && *input.NotifyDcAdmins == domainservices.NotifyDcAdminsEnabled { result["notify_dc_admins"] = true } - if input.NotifyGlobalAdmins == aad.NotifyGlobalAdminsEnabled { + if input.NotifyGlobalAdmins != nil && *input.NotifyGlobalAdmins == domainservices.NotifyGlobalAdminsEnabled { result["notify_global_admins"] = true } return []interface{}{result} } -func flattenDomainServiceReplicaSets(input *[]aad.ReplicaSet) (ret []interface{}) { +func flattenDomainServiceReplicaSets(input *[]domainservices.ReplicaSet) (ret []interface{}) { if input == nil { return } @@ -740,14 +772,14 @@ func flattenDomainServiceReplicaSets(input *[]aad.ReplicaSet) (ret []interface{} if in.ExternalAccessIPAddress != nil { repl["external_access_ip_address"] = *in.ExternalAccessIPAddress } - if in.ReplicaSetID != nil { - repl["id"] = *in.ReplicaSetID + if in.ReplicaSetId != nil { + repl["id"] = *in.ReplicaSetId } if in.ServiceStatus != nil { repl["service_status"] = *in.ServiceStatus } - if in.SubnetID != nil { - repl["subnet_id"] = *in.SubnetID + if in.SubnetId != nil { + repl["subnet_id"] = *in.SubnetId } ret = append(ret, repl) } @@ -755,31 +787,39 @@ func flattenDomainServiceReplicaSets(input *[]aad.ReplicaSet) (ret []interface{} return } -func flattenDomainServiceSecurity(input *aad.DomainSecuritySettings) []interface{} { +func flattenDomainServiceSecurity(input *domainservices.DomainSecuritySettings) []interface{} { if input == nil { return make([]interface{}, 0) } result := map[string]bool{ - "ntlm_v1_enabled": false, - "sync_kerberos_passwords": false, - "sync_ntlm_passwords": false, - "sync_on_prem_passwords": false, - "tls_v1_enabled": false, + "kerberos_armoring_enabled": false, + "kerberos_rc4_encryption_enabled": false, + "ntlm_v1_enabled": false, + "sync_kerberos_passwords": false, + "sync_ntlm_passwords": false, + "sync_on_prem_passwords": false, + "tls_v1_enabled": false, + } + if input.KerberosArmoring != nil && *input.KerberosArmoring == domainservices.KerberosArmoringEnabled { + result["kerberos_armoring_enabled"] = true + } + if input.KerberosRc4Encryption != nil && *input.KerberosRc4Encryption == domainservices.KerberosRc4EncryptionEnabled { + result["kerberos_rc4_encryption_enabled"] = true } - if input.NtlmV1 == aad.NtlmV1Enabled { + if input.NtlmV1 != nil && *input.NtlmV1 == domainservices.NtlmV1Enabled { result["ntlm_v1_enabled"] = true } - if input.SyncKerberosPasswords == aad.SyncKerberosPasswordsEnabled { + if input.SyncKerberosPasswords != nil && *input.SyncKerberosPasswords == domainservices.SyncKerberosPasswordsEnabled { result["sync_kerberos_passwords"] = true } - if input.SyncNtlmPasswords == aad.SyncNtlmPasswordsEnabled { + if input.SyncNtlmPasswords != nil && *input.SyncNtlmPasswords == domainservices.SyncNtlmPasswordsEnabled { result["sync_ntlm_passwords"] = true } - if input.SyncOnPremPasswords == aad.SyncOnPremPasswordsEnabled { + if input.SyncOnPremPasswords != nil && *input.SyncOnPremPasswords == domainservices.SyncOnPremPasswordsEnabled { result["sync_on_prem_passwords"] = true } - if input.TLSV1 == aad.TLSV1Enabled { + if input.TlsV1 != nil && *input.TlsV1 == domainservices.TlsV1Enabled { result["tls_v1_enabled"] = true } diff --git a/internal/services/domainservices/active_directory_domain_service_test.go b/internal/services/domainservices/active_directory_domain_service_test.go index 87e0e8e03976..2ff4bfc0a711 100644 --- a/internal/services/domainservices/active_directory_domain_service_test.go +++ b/internal/services/domainservices/active_directory_domain_service_test.go @@ -5,6 +5,7 @@ import ( "fmt" "testing" + "github.com/hashicorp/go-azure-sdk/resource-manager/aad/2021-05-01/domainservices" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" @@ -124,6 +125,8 @@ func TestAccActiveDirectoryDomainService_updateWithDatasource(t *testing.T) { check.That(dataSourceData.ResourceName).Key("secure_ldap.0.external_access_enabled").HasValue("true"), check.That(dataSourceData.ResourceName).Key("secure_ldap.0.public_certificate").Exists(), check.That(dataSourceData.ResourceName).Key("security.#").HasValue("1"), + check.That(dataSourceData.ResourceName).Key("security.0.kerberos_armoring_enabled").HasValue("true"), + check.That(dataSourceData.ResourceName).Key("security.0.kerberos_rc4_encryption_enabled").HasValue("true"), check.That(dataSourceData.ResourceName).Key("security.0.ntlm_v1_enabled").HasValue("true"), check.That(dataSourceData.ResourceName).Key("security.0.sync_kerberos_passwords").HasValue("true"), check.That(dataSourceData.ResourceName).Key("security.0.sync_ntlm_passwords").HasValue("true"), @@ -161,12 +164,14 @@ func (ActiveDirectoryDomainServiceResource) Exists(ctx context.Context, client * return nil, err } - resp, err := client.DomainServices.DomainServicesClient.Get(ctx, id.ResourceGroup, id.Name) + idsdk := domainservices.NewDomainServiceID(id.SubscriptionId, id.ResourceGroup, id.Name) + + resp, err := client.DomainServices.DomainServicesClient.Get(ctx, idsdk) if err != nil { return nil, fmt.Errorf("reading DomainService: %+v", err) } - return utils.Bool(resp.ID != nil), nil + return utils.Bool(resp.Model != nil && resp.Model.Id != nil), nil } func (ActiveDirectoryDomainServiceReplicaSetResource) Exists(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { @@ -175,17 +180,29 @@ func (ActiveDirectoryDomainServiceReplicaSetResource) Exists(ctx context.Context return nil, err } - resp, err := client.DomainServices.DomainServicesClient.Get(ctx, id.ResourceGroup, id.DomainServiceName) + idsdk := domainservices.NewDomainServiceID(id.SubscriptionId, id.ResourceGroup, id.DomainServiceName) + + resp, err := client.DomainServices.DomainServicesClient.Get(ctx, idsdk) if err != nil { return nil, fmt.Errorf("reading DomainService: %+v", err) } - if resp.ReplicaSets == nil || len(*resp.ReplicaSets) == 0 { + model := resp.Model + if model == nil { + return nil, fmt.Errorf("DomainService response returned with nil model") + } + + props := model.Properties + if props == nil { + return nil, fmt.Errorf("DomainService response returned with nil properties") + } + + if props.ReplicaSets == nil || len(*props.ReplicaSets) == 0 { return nil, fmt.Errorf("DomainService response returned with nil or empty replicaSets") } - for _, replica := range *resp.ReplicaSets { - if replica.ReplicaSetID != nil && *replica.ReplicaSetID == id.ReplicaSetName { + for _, replica := range *props.ReplicaSets { + if replica.ReplicaSetId != nil && *replica.ReplicaSetId == id.ReplicaSetName { return utils.Bool(true), nil } } @@ -339,11 +356,13 @@ resource "azurerm_active_directory_domain_service" "test" { } security { - ntlm_v1_enabled = true - sync_kerberos_passwords = true - sync_ntlm_passwords = true - sync_on_prem_passwords = true - tls_v1_enabled = true + kerberos_armoring_enabled = true + kerberos_rc4_encryption_enabled = true + ntlm_v1_enabled = true + sync_kerberos_passwords = true + sync_ntlm_passwords = true + sync_on_prem_passwords = true + tls_v1_enabled = true } tags = { diff --git a/internal/services/domainservices/active_directory_domain_service_trust_resource.go b/internal/services/domainservices/active_directory_domain_service_trust_resource.go index 7578996f5588..f3082a2dc692 100644 --- a/internal/services/domainservices/active_directory_domain_service_trust_resource.go +++ b/internal/services/domainservices/active_directory_domain_service_trust_resource.go @@ -6,7 +6,8 @@ import ( "strings" "time" - "github.com/Azure/azure-sdk-for-go/services/domainservices/mgmt/2020-01-01/aad" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/aad/2021-05-01/domainservices" "github.com/hashicorp/terraform-provider-azurerm/internal/locks" "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" "github.com/hashicorp/terraform-provider-azurerm/internal/services/domainservices/parse" @@ -98,16 +99,23 @@ func (r DomainServiceTrustResource) Create() sdk.ResourceFunc { } id := parse.NewDomainServiceTrustID(dsid.SubscriptionId, dsid.ResourceGroup, dsid.Name, plan.Name) + idsdk := domainservices.NewDomainServiceID(id.SubscriptionId, id.ResourceGroup, id.DomainServiceName) locks.ByName(id.DomainServiceName, DomainServiceResourceName) defer locks.UnlockByName(id.DomainServiceName, DomainServiceResourceName) - existing, err := client.Get(ctx, id.ResourceGroup, id.DomainServiceName) + existing, err := client.Get(ctx, idsdk) if err != nil { return fmt.Errorf("checking for presence of existing %s: %+v", id, err) } - existingTrusts := []aad.ForestTrust{} - if props := existing.DomainServiceProperties; props != nil { + + model := existing.Model + if model == nil { + return fmt.Errorf("reading %s: returned with null model", idsdk) + } + + existingTrusts := []domainservices.ForestTrust{} + if props := model.Properties; props != nil { if fsettings := props.ResourceForestSettings; fsettings != nil { if settings := fsettings.Settings; settings != nil { existingTrusts = *settings @@ -120,28 +128,24 @@ func (r DomainServiceTrustResource) Create() sdk.ResourceFunc { } } - existingTrusts = append(existingTrusts, aad.ForestTrust{ + existingTrusts = append(existingTrusts, domainservices.ForestTrust{ TrustedDomainFqdn: utils.String(plan.TrustedDomainFqdn), TrustDirection: utils.String("Inbound"), FriendlyName: utils.String(id.TrustName), - RemoteDNSIps: utils.String(strings.Join(plan.TrustedDomainDnsIPs, ",")), + RemoteDnsIPs: utils.String(strings.Join(plan.TrustedDomainDnsIPs, ",")), TrustPassword: utils.String(plan.Password), }) - params := aad.DomainService{ - DomainServiceProperties: &aad.DomainServiceProperties{ - ResourceForestSettings: &aad.ResourceForestSettings{ + params := domainservices.DomainService{ + Properties: &domainservices.DomainServiceProperties{ + ResourceForestSettings: &domainservices.ResourceForestSettings{ Settings: &existingTrusts, }, }, } - future, err := client.Update(ctx, id.ResourceGroup, id.DomainServiceName, params) - if err != nil { + if err := client.UpdateThenPoll(ctx, idsdk, params); err != nil { return fmt.Errorf("creating %s: %+v", id, err) } - if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for creation of %s: %+v", id, err) - } metadata.SetID(id) return nil @@ -160,22 +164,27 @@ func (r DomainServiceTrustResource) Read() sdk.ResourceFunc { return err } - resourceErrorName := fmt.Sprintf("Domain Service (Name: %q, Resource Group: %q)", id.DomainServiceName, id.ResourceGroup) + idsdk := domainservices.NewDomainServiceID(id.SubscriptionId, id.ResourceGroup, id.DomainServiceName) - existing, err := client.Get(ctx, id.ResourceGroup, id.DomainServiceName) + existing, err := client.Get(ctx, idsdk) if err != nil { - if utils.ResponseWasNotFound(existing.Response) { + if response.WasNotFound(existing.HttpResponse) { return metadata.MarkAsGone(id) } - return fmt.Errorf("retrieving %s: %+v", resourceErrorName, err) + return fmt.Errorf("retrieving %s: %+v", idsdk, err) + } + + model := existing.Model + if model == nil { + return fmt.Errorf("reading %s: returned with null model", idsdk) } - props := existing.DomainServiceProperties + props := model.Properties if props == nil { - return fmt.Errorf("checking for presence of existing %s: API response contained nil or missing properties", resourceErrorName) + return fmt.Errorf("checking for presence of existing %s: API response contained nil or missing properties", idsdk) } - existingTrusts := []aad.ForestTrust{} + existingTrusts := []domainservices.ForestTrust{} if props != nil { if fsettings := props.ResourceForestSettings; fsettings != nil { if settings := fsettings.Settings; settings != nil { @@ -183,7 +192,7 @@ func (r DomainServiceTrustResource) Read() sdk.ResourceFunc { } } } - var trust *aad.ForestTrust + var trust *domainservices.ForestTrust for _, setting := range existingTrusts { existingTrust := setting if setting.FriendlyName != nil && *setting.FriendlyName == id.TrustName { @@ -197,17 +206,17 @@ func (r DomainServiceTrustResource) Read() sdk.ResourceFunc { // Retrieve the initial replica set id to construct the domain service id. replicaSets := flattenDomainServiceReplicaSets(props.ReplicaSets) if len(replicaSets) == 0 { - return fmt.Errorf("checking for presence of existing %s: API response contained nil or missing replica set details", resourceErrorName) + return fmt.Errorf("checking for presence of existing %s: API response contained nil or missing replica set details", idsdk) } initialReplicaSetId := replicaSets[0].(map[string]interface{})["id"].(string) - dsid := parse.NewDomainServiceID(client.SubscriptionID, id.ResourceGroup, id.DomainServiceName, initialReplicaSetId) + dsid := parse.NewDomainServiceID(id.SubscriptionId, id.ResourceGroup, id.DomainServiceName, initialReplicaSetId) var state DomainServiceTrustModel if err := metadata.Decode(&state); err != nil { return err } - model := DomainServiceTrustModel{ + data := DomainServiceTrustModel{ DomainServiceId: dsid.ID(), Name: id.TrustName, // Setting the password from state as it is not returned by API. @@ -215,14 +224,14 @@ func (r DomainServiceTrustResource) Read() sdk.ResourceFunc { } if trust.TrustedDomainFqdn != nil { - model.TrustedDomainFqdn = *trust.TrustedDomainFqdn + data.TrustedDomainFqdn = *trust.TrustedDomainFqdn } - if trust.RemoteDNSIps != nil { - model.TrustedDomainDnsIPs = strings.Split(*trust.RemoteDNSIps, ",") + if trust.RemoteDnsIPs != nil { + data.TrustedDomainDnsIPs = strings.Split(*trust.RemoteDnsIPs, ",") } - return metadata.Encode(&model) + return metadata.Encode(&data) }, } } @@ -238,20 +247,25 @@ func (r DomainServiceTrustResource) Delete() sdk.ResourceFunc { return err } - resourceErrorName := fmt.Sprintf("Domain Service (Name: %q, Resource Group: %q)", id.DomainServiceName, id.ResourceGroup) + idsdk := domainservices.NewDomainServiceID(id.SubscriptionId, id.ResourceGroup, id.DomainServiceName) locks.ByName(id.DomainServiceName, DomainServiceResourceName) defer locks.UnlockByName(id.DomainServiceName, DomainServiceResourceName) - existing, err := client.Get(ctx, id.ResourceGroup, id.DomainServiceName) + existing, err := client.Get(ctx, idsdk) if err != nil { - if utils.ResponseWasNotFound(existing.Response) { + if response.WasNotFound(existing.HttpResponse) { return metadata.MarkAsGone(id) } - return fmt.Errorf("retrieving %s: %+v", resourceErrorName, err) + return fmt.Errorf("retrieving %s: %+v", idsdk, err) + } + + model := existing.Model + if model == nil { + return fmt.Errorf("reading %s: returned with null model", idsdk) } - existingTrusts := []aad.ForestTrust{} - if props := existing.DomainServiceProperties; props != nil { + existingTrusts := []domainservices.ForestTrust{} + if props := model.Properties; props != nil { if fsettings := props.ResourceForestSettings; fsettings != nil { if settings := fsettings.Settings; settings != nil { existingTrusts = *settings @@ -259,7 +273,7 @@ func (r DomainServiceTrustResource) Delete() sdk.ResourceFunc { } } var found bool - newTrusts := []aad.ForestTrust{} + newTrusts := []domainservices.ForestTrust{} for _, trust := range existingTrusts { if trust.FriendlyName != nil && *trust.FriendlyName == id.TrustName { found = true @@ -272,21 +286,17 @@ func (r DomainServiceTrustResource) Delete() sdk.ResourceFunc { return metadata.MarkAsGone(id) } - params := aad.DomainService{ - DomainServiceProperties: &aad.DomainServiceProperties{ - ResourceForestSettings: &aad.ResourceForestSettings{ + params := domainservices.DomainService{ + Properties: &domainservices.DomainServiceProperties{ + ResourceForestSettings: &domainservices.ResourceForestSettings{ Settings: &newTrusts, }, }, } - future, err := client.Update(ctx, id.ResourceGroup, id.DomainServiceName, params) - if err != nil { + if err := client.UpdateThenPoll(ctx, idsdk, params); err != nil { return fmt.Errorf("deleting %s: %+v", id, err) } - if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for removal of %s: %+v", id, err) - } return nil }, @@ -304,17 +314,23 @@ func (r DomainServiceTrustResource) Update() sdk.ResourceFunc { return err } - resourceErrorName := fmt.Sprintf("Domain Service (Name: %q, Resource Group: %q)", id.DomainServiceName, id.ResourceGroup) + idsdk := domainservices.NewDomainServiceID(id.SubscriptionId, id.ResourceGroup, id.DomainServiceName) locks.ByName(id.DomainServiceName, DomainServiceResourceName) defer locks.UnlockByName(id.DomainServiceName, DomainServiceResourceName) - existing, err := client.Get(ctx, id.ResourceGroup, id.DomainServiceName) + existing, err := client.Get(ctx, idsdk) if err != nil { - return fmt.Errorf("retrieving %s: %+v", resourceErrorName, err) + return fmt.Errorf("retrieving %s: %+v", idsdk, err) + } + + model := existing.Model + if model == nil { + return fmt.Errorf("reading %s: returned with null model", idsdk) } - existingTrusts := []aad.ForestTrust{} - if props := existing.DomainServiceProperties; props != nil { + + existingTrusts := []domainservices.ForestTrust{} + if props := model.Properties; props != nil { if fsettings := props.ResourceForestSettings; fsettings != nil { if settings := fsettings.Settings; settings != nil { existingTrusts = *settings @@ -328,7 +344,7 @@ func (r DomainServiceTrustResource) Update() sdk.ResourceFunc { } var found bool - newTrusts := []aad.ForestTrust{} + newTrusts := []domainservices.ForestTrust{} for _, trust := range existingTrusts { if trust.FriendlyName != nil && *trust.FriendlyName == id.TrustName { found = true @@ -336,7 +352,7 @@ func (r DomainServiceTrustResource) Update() sdk.ResourceFunc { trust.TrustedDomainFqdn = utils.String(plan.TrustedDomainFqdn) } if metadata.ResourceData.HasChange("trusted_domain_dns_ips") { - trust.RemoteDNSIps = utils.String(strings.Join(plan.TrustedDomainDnsIPs, ",")) + trust.RemoteDnsIPs = utils.String(strings.Join(plan.TrustedDomainDnsIPs, ",")) } trust.TrustPassword = utils.String(plan.Password) } @@ -346,21 +362,17 @@ func (r DomainServiceTrustResource) Update() sdk.ResourceFunc { return fmt.Errorf("%s not exists: %+v", id, err) } - params := aad.DomainService{ - DomainServiceProperties: &aad.DomainServiceProperties{ - ResourceForestSettings: &aad.ResourceForestSettings{ + params := domainservices.DomainService{ + Properties: &domainservices.DomainServiceProperties{ + ResourceForestSettings: &domainservices.ResourceForestSettings{ Settings: &newTrusts, }, }, } - future, err := client.Update(ctx, id.ResourceGroup, id.DomainServiceName, params) - if err != nil { + if err := client.UpdateThenPoll(ctx, idsdk, params); err != nil { return fmt.Errorf("updating %s: %+v", id, err) } - if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for update of %s: %+v", id, err) - } return nil }, } diff --git a/internal/services/domainservices/active_directory_domain_service_trust_resource_test.go b/internal/services/domainservices/active_directory_domain_service_trust_resource_test.go index bd18f105253e..629d2571ff2d 100644 --- a/internal/services/domainservices/active_directory_domain_service_trust_resource_test.go +++ b/internal/services/domainservices/active_directory_domain_service_trust_resource_test.go @@ -6,7 +6,8 @@ import ( "os" "testing" - "github.com/Azure/azure-sdk-for-go/services/domainservices/mgmt/2020-01-01/aad" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/aad/2021-05-01/domainservices" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" @@ -116,15 +117,23 @@ func (r DomainServiceTrustResource) Exists(ctx context.Context, clients *clients return nil, err } - resp, err := client.Get(ctx, id.ResourceGroup, id.DomainServiceName) + idsdk := domainservices.NewDomainServiceID(id.SubscriptionId, id.ResourceGroup, id.DomainServiceName) + + resp, err := client.Get(ctx, idsdk) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { return utils.Bool(false), nil } return nil, err } - existingTrusts := []aad.ForestTrust{} - if props := resp.DomainServiceProperties; props != nil { + + model := resp.Model + if model == nil { + return nil, fmt.Errorf("reading %s: returned with null model", idsdk) + } + + existingTrusts := []domainservices.ForestTrust{} + if props := model.Properties; props != nil { if fsettings := props.ResourceForestSettings; fsettings != nil { if settings := fsettings.Settings; settings != nil { existingTrusts = *settings diff --git a/internal/services/domainservices/client/client.go b/internal/services/domainservices/client/client.go index e3f16a08a108..e83f747a2938 100644 --- a/internal/services/domainservices/client/client.go +++ b/internal/services/domainservices/client/client.go @@ -1,16 +1,16 @@ package client import ( - "github.com/Azure/azure-sdk-for-go/services/domainservices/mgmt/2020-01-01/aad" + "github.com/hashicorp/go-azure-sdk/resource-manager/aad/2021-05-01/domainservices" "github.com/hashicorp/terraform-provider-azurerm/internal/common" ) type Client struct { - DomainServicesClient *aad.DomainServicesClient + DomainServicesClient *domainservices.DomainServicesClient } func NewClient(o *common.ClientOptions) *Client { - domainServicesClient := aad.NewDomainServicesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + domainServicesClient := domainservices.NewDomainServicesClientWithBaseURI(o.ResourceManagerEndpoint) o.ConfigureClient(&domainServicesClient.Client, o.ResourceManagerAuthorizer) return &Client{ diff --git a/internal/services/eventhub/client/client.go b/internal/services/eventhub/client/client.go index cb49f8333294..dba63b7829a5 100644 --- a/internal/services/eventhub/client/client.go +++ b/internal/services/eventhub/client/client.go @@ -1,15 +1,16 @@ package client import ( - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/authorizationruleseventhubs" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/authorizationrulesnamespaces" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/checknameavailabilitydisasterrecoveryconfigs" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/consumergroups" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/disasterrecoveryconfigs" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/eventhubs" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2018-01-01-preview/eventhubsclusters" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2018-01-01-preview/networkrulesets" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-01-01-preview/namespaces" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/authorizationruleseventhubs" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/authorizationrulesnamespaces" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/checknameavailabilitydisasterrecoveryconfigs" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/consumergroups" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/disasterrecoveryconfigs" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/eventhubs" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/eventhubsclusters" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/networkrulesets" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/schemaregistry" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2022-01-01-preview/namespaces" "github.com/hashicorp/terraform-provider-azurerm/internal/common" ) @@ -23,6 +24,7 @@ type Client struct { NamespacesClient *namespaces.NamespacesClient NamespaceAuthorizationRulesClient *authorizationrulesnamespaces.AuthorizationRulesNamespacesClient NetworkRuleSetsClient *networkrulesets.NetworkRuleSetsClient + SchemaRegistryClient *schemaregistry.SchemaRegistryClient } func NewClient(o *common.ClientOptions) *Client { @@ -53,6 +55,9 @@ func NewClient(o *common.ClientOptions) *Client { networkRuleSetsClient := networkrulesets.NewNetworkRuleSetsClientWithBaseURI(o.ResourceManagerEndpoint) o.ConfigureClient(&networkRuleSetsClient.Client, o.ResourceManagerAuthorizer) + schemaRegistryClient := schemaregistry.NewSchemaRegistryClientWithBaseURI(o.ResourceManagerEndpoint) + o.ConfigureClient(&schemaRegistryClient.Client, o.ResourceManagerAuthorizer) + return &Client{ ClusterClient: &clustersClient, ConsumerGroupClient: &consumerGroupsClient, @@ -63,5 +68,6 @@ func NewClient(o *common.ClientOptions) *Client { NamespacesClient: &namespacesClient, NamespaceAuthorizationRulesClient: &namespaceAuthorizationRulesClient, NetworkRuleSetsClient: &networkRuleSetsClient, + SchemaRegistryClient: &schemaRegistryClient, } } diff --git a/internal/services/eventhub/eventhub_authorization_rule_data_source.go b/internal/services/eventhub/eventhub_authorization_rule_data_source.go index 64e12bbccc89..64682d9972af 100644 --- a/internal/services/eventhub/eventhub_authorization_rule_data_source.go +++ b/internal/services/eventhub/eventhub_authorization_rule_data_source.go @@ -6,8 +6,8 @@ import ( "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/authorizationruleseventhubs" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/eventhubs" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/authorizationruleseventhubs" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/eventhubs" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/services/eventhub/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" diff --git a/internal/services/eventhub/eventhub_authorization_rule_resource.go b/internal/services/eventhub/eventhub_authorization_rule_resource.go index 70bda16dbdb7..01794f6da18a 100644 --- a/internal/services/eventhub/eventhub_authorization_rule_resource.go +++ b/internal/services/eventhub/eventhub_authorization_rule_resource.go @@ -6,8 +6,8 @@ import ( "time" "github.com/hashicorp/go-azure-helpers/lang/response" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/authorizationruleseventhubs" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/eventhubs" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/authorizationruleseventhubs" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/eventhubs" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" diff --git a/internal/services/eventhub/eventhub_authorization_rule_resource_test.go b/internal/services/eventhub/eventhub_authorization_rule_resource_test.go index 1691d5debce6..b1bfb14d87e8 100644 --- a/internal/services/eventhub/eventhub_authorization_rule_resource_test.go +++ b/internal/services/eventhub/eventhub_authorization_rule_resource_test.go @@ -6,7 +6,7 @@ import ( "strconv" "testing" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/eventhubs" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/eventhubs" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" diff --git a/internal/services/eventhub/eventhub_cluster_data_source.go b/internal/services/eventhub/eventhub_cluster_data_source.go index 77a820e43a73..92e6ea95d60e 100644 --- a/internal/services/eventhub/eventhub_cluster_data_source.go +++ b/internal/services/eventhub/eventhub_cluster_data_source.go @@ -7,7 +7,7 @@ import ( "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2018-01-01-preview/eventhubsclusters" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/eventhubsclusters" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" diff --git a/internal/services/eventhub/eventhub_cluster_resource.go b/internal/services/eventhub/eventhub_cluster_resource.go index 7f0c66aae8b7..3403c4c19d11 100644 --- a/internal/services/eventhub/eventhub_cluster_resource.go +++ b/internal/services/eventhub/eventhub_cluster_resource.go @@ -11,7 +11,7 @@ import ( "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2018-01-01-preview/eventhubsclusters" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/eventhubsclusters" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" diff --git a/internal/services/eventhub/eventhub_cluster_resource_test.go b/internal/services/eventhub/eventhub_cluster_resource_test.go index b2ea26b1b249..76d4331a76a5 100644 --- a/internal/services/eventhub/eventhub_cluster_resource_test.go +++ b/internal/services/eventhub/eventhub_cluster_resource_test.go @@ -5,7 +5,7 @@ import ( "fmt" "testing" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2018-01-01-preview/eventhubsclusters" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/eventhubsclusters" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" diff --git a/internal/services/eventhub/eventhub_consumer_group_data_source.go b/internal/services/eventhub/eventhub_consumer_group_data_source.go index 36cd7000e2b6..815cdb33ca98 100644 --- a/internal/services/eventhub/eventhub_consumer_group_data_source.go +++ b/internal/services/eventhub/eventhub_consumer_group_data_source.go @@ -6,7 +6,7 @@ import ( "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/consumergroups" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/consumergroups" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/services/eventhub/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" diff --git a/internal/services/eventhub/eventhub_consumer_group_resource.go b/internal/services/eventhub/eventhub_consumer_group_resource.go index dca39f7408cc..af86aab0114d 100644 --- a/internal/services/eventhub/eventhub_consumer_group_resource.go +++ b/internal/services/eventhub/eventhub_consumer_group_resource.go @@ -6,7 +6,7 @@ import ( "time" "github.com/hashicorp/go-azure-helpers/lang/response" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/consumergroups" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/consumergroups" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" "github.com/hashicorp/terraform-provider-azurerm/internal/services/eventhub/migration" diff --git a/internal/services/eventhub/eventhub_consumer_group_resource_test.go b/internal/services/eventhub/eventhub_consumer_group_resource_test.go index bbf4729347fe..a3a8aa1a4494 100644 --- a/internal/services/eventhub/eventhub_consumer_group_resource_test.go +++ b/internal/services/eventhub/eventhub_consumer_group_resource_test.go @@ -5,7 +5,7 @@ import ( "fmt" "testing" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/consumergroups" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/consumergroups" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" diff --git a/internal/services/eventhub/eventhub_data_source.go b/internal/services/eventhub/eventhub_data_source.go index 61929f149044..1dfc20e99d57 100644 --- a/internal/services/eventhub/eventhub_data_source.go +++ b/internal/services/eventhub/eventhub_data_source.go @@ -6,7 +6,7 @@ import ( "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/eventhubs" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/eventhubs" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" diff --git a/internal/services/eventhub/eventhub_namespace_authorization_rule_data_source.go b/internal/services/eventhub/eventhub_namespace_authorization_rule_data_source.go index 7ce5dc97a623..31109163d127 100644 --- a/internal/services/eventhub/eventhub_namespace_authorization_rule_data_source.go +++ b/internal/services/eventhub/eventhub_namespace_authorization_rule_data_source.go @@ -6,7 +6,7 @@ import ( "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/authorizationrulesnamespaces" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/authorizationrulesnamespaces" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/services/eventhub/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" diff --git a/internal/services/eventhub/eventhub_namespace_authorization_rule_resource.go b/internal/services/eventhub/eventhub_namespace_authorization_rule_resource.go index e5c7daacaff2..3f701cdbe901 100644 --- a/internal/services/eventhub/eventhub_namespace_authorization_rule_resource.go +++ b/internal/services/eventhub/eventhub_namespace_authorization_rule_resource.go @@ -6,7 +6,7 @@ import ( "time" "github.com/hashicorp/go-azure-helpers/lang/response" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/authorizationrulesnamespaces" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/authorizationrulesnamespaces" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" diff --git a/internal/services/eventhub/eventhub_namespace_authorization_rule_resource_test.go b/internal/services/eventhub/eventhub_namespace_authorization_rule_resource_test.go index f9e5de6331b7..142cb93994cd 100644 --- a/internal/services/eventhub/eventhub_namespace_authorization_rule_resource_test.go +++ b/internal/services/eventhub/eventhub_namespace_authorization_rule_resource_test.go @@ -6,7 +6,7 @@ import ( "strconv" "testing" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/authorizationrulesnamespaces" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/authorizationrulesnamespaces" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" diff --git a/internal/services/eventhub/eventhub_namespace_customer_managed_key_resource.go b/internal/services/eventhub/eventhub_namespace_customer_managed_key_resource.go index 57f22221db0f..6f3425229502 100644 --- a/internal/services/eventhub/eventhub_namespace_customer_managed_key_resource.go +++ b/internal/services/eventhub/eventhub_namespace_customer_managed_key_resource.go @@ -7,7 +7,7 @@ import ( "time" "github.com/hashicorp/go-azure-helpers/lang/response" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-01-01-preview/namespaces" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2022-01-01-preview/namespaces" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/locks" diff --git a/internal/services/eventhub/eventhub_namespace_customer_managed_key_resource_test.go b/internal/services/eventhub/eventhub_namespace_customer_managed_key_resource_test.go index cdf986900a3e..ab4d4c6e8473 100644 --- a/internal/services/eventhub/eventhub_namespace_customer_managed_key_resource_test.go +++ b/internal/services/eventhub/eventhub_namespace_customer_managed_key_resource_test.go @@ -5,7 +5,7 @@ import ( "fmt" "testing" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-01-01-preview/namespaces" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2022-01-01-preview/namespaces" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" diff --git a/internal/services/eventhub/eventhub_namespace_data_source.go b/internal/services/eventhub/eventhub_namespace_data_source.go index b4691fe125ba..c67c5d809f0b 100644 --- a/internal/services/eventhub/eventhub_namespace_data_source.go +++ b/internal/services/eventhub/eventhub_namespace_data_source.go @@ -9,8 +9,8 @@ import ( "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/authorizationrulesnamespaces" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-01-01-preview/namespaces" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/authorizationrulesnamespaces" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2022-01-01-preview/namespaces" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" diff --git a/internal/services/eventhub/eventhub_namespace_disaster_recovery_config_resource.go b/internal/services/eventhub/eventhub_namespace_disaster_recovery_config_resource.go index 436db25284c0..aa4489a14a45 100644 --- a/internal/services/eventhub/eventhub_namespace_disaster_recovery_config_resource.go +++ b/internal/services/eventhub/eventhub_namespace_disaster_recovery_config_resource.go @@ -8,8 +8,8 @@ import ( "time" "github.com/hashicorp/go-azure-helpers/lang/response" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/checknameavailabilitydisasterrecoveryconfigs" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/disasterrecoveryconfigs" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/checknameavailabilitydisasterrecoveryconfigs" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/disasterrecoveryconfigs" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" diff --git a/internal/services/eventhub/eventhub_namespace_disaster_recovery_config_resource_test.go b/internal/services/eventhub/eventhub_namespace_disaster_recovery_config_resource_test.go index 49cd724c4c22..90810659e837 100644 --- a/internal/services/eventhub/eventhub_namespace_disaster_recovery_config_resource_test.go +++ b/internal/services/eventhub/eventhub_namespace_disaster_recovery_config_resource_test.go @@ -5,7 +5,7 @@ import ( "fmt" "testing" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/disasterrecoveryconfigs" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/disasterrecoveryconfigs" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" diff --git a/internal/services/eventhub/eventhub_namespace_resource.go b/internal/services/eventhub/eventhub_namespace_resource.go index fdc9ba6d3926..bf9ca2bddc45 100644 --- a/internal/services/eventhub/eventhub_namespace_resource.go +++ b/internal/services/eventhub/eventhub_namespace_resource.go @@ -14,10 +14,10 @@ import ( "github.com/hashicorp/go-azure-helpers/resourcemanager/identity" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/authorizationrulesnamespaces" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2018-01-01-preview/eventhubsclusters" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2018-01-01-preview/networkrulesets" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-01-01-preview/namespaces" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/authorizationrulesnamespaces" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/eventhubsclusters" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/networkrulesets" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2022-01-01-preview/namespaces" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" @@ -190,6 +190,29 @@ func resourceEventHubNamespace() *pluginsdk.Resource { }, }, + "local_authentication_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: true, + }, + + "minimum_tls_version": { + Type: pluginsdk.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice([]string{ + string(namespaces.TlsVersionOnePointZero), + string(namespaces.TlsVersionOnePointOne), + string(namespaces.TlsVersionOnePointTwo), + }, false), + }, + + "public_network_access_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: true, + }, + "default_primary_connection_string_alias": { Type: pluginsdk.TypeString, Computed: true, @@ -228,22 +251,26 @@ func resourceEventHubNamespace() *pluginsdk.Resource { "tags": commonschema.Tags(), }, - CustomizeDiff: pluginsdk.CustomizeDiffShim(func(ctx context.Context, d *pluginsdk.ResourceDiff, v interface{}) error { - oldSku, newSku := d.GetChange("sku") - if d.HasChange("sku") { - if strings.EqualFold(newSku.(string), string(namespaces.SkuNamePremium)) || strings.EqualFold(oldSku.(string), string(namespaces.SkuTierPremium)) { - log.Printf("[DEBUG] cannot migrate a namespace from or to Premium SKU") - d.ForceNew("sku") - } - if strings.EqualFold(newSku.(string), string(namespaces.SkuTierPremium)) { - zoneRedundant := d.Get("zone_redundant").(bool) - if !zoneRedundant { - return fmt.Errorf("zone_redundant needs to be set to true when using premium SKU") + + CustomizeDiff: pluginsdk.CustomDiffWithAll( + pluginsdk.CustomizeDiffShim(func(ctx context.Context, d *pluginsdk.ResourceDiff, v interface{}) error { + oldSku, newSku := d.GetChange("sku") + if d.HasChange("sku") { + if strings.EqualFold(newSku.(string), string(namespaces.SkuNamePremium)) || strings.EqualFold(oldSku.(string), string(namespaces.SkuTierPremium)) { + log.Printf("[DEBUG] cannot migrate a namespace from or to Premium SKU") + d.ForceNew("sku") + } + if strings.EqualFold(newSku.(string), string(namespaces.SkuTierPremium)) { + zoneRedundant := d.Get("zone_redundant").(bool) + if !zoneRedundant { + return fmt.Errorf("zone_redundant needs to be set to true when using premium SKU") + } } } - } - return nil - }), + return nil + }), + pluginsdk.CustomizeDiffShim(eventhubTLSVersionDiff), + ), } } @@ -278,6 +305,16 @@ func resourceEventHubNamespaceCreate(d *pluginsdk.ResourceData, meta interface{} return fmt.Errorf("expanding `identity`: %+v", err) } + publicNetworkEnabled := namespaces.PublicNetworkAccessEnabled + if !d.Get("public_network_access_enabled").(bool) { + publicNetworkEnabled = namespaces.PublicNetworkAccessDisabled + } + + disableLocalAuth := false + if !d.Get("local_authentication_enabled").(bool) { + disableLocalAuth = true + } + parameters := namespaces.EHNamespace{ Location: &location, Sku: &namespaces.Sku{ @@ -292,6 +329,8 @@ func resourceEventHubNamespaceCreate(d *pluginsdk.ResourceData, meta interface{} Properties: &namespaces.EHNamespaceProperties{ IsAutoInflateEnabled: utils.Bool(autoInflateEnabled), ZoneRedundant: utils.Bool(zoneRedundant), + DisableLocalAuth: utils.Bool(disableLocalAuth), + PublicNetworkAccess: &publicNetworkEnabled, }, Tags: tags.Expand(t), } @@ -300,6 +339,11 @@ func resourceEventHubNamespaceCreate(d *pluginsdk.ResourceData, meta interface{} parameters.Properties.ClusterArmId = utils.String(v) } + if tlsValue := d.Get("minimum_tls_version").(string); tlsValue != "" { + minimumTls := namespaces.TlsVersion(tlsValue) + parameters.Properties.MinimumTlsVersion = &minimumTls + } + if v, ok := d.GetOk("maximum_throughput_units"); ok { parameters.Properties.MaximumThroughputUnits = utils.Int64(int64(v.(int))) } @@ -312,25 +356,19 @@ func resourceEventHubNamespaceCreate(d *pluginsdk.ResourceData, meta interface{} ruleSets, hasRuleSets := d.GetOk("network_rulesets") if hasRuleSets { + // cannot use network rulesets with the basic SKU + if parameters.Sku.Name == namespaces.SkuNameBasic { + return fmt.Errorf("network_rulesets cannot be used when the SKU is basic") + } + rulesets := networkrulesets.NetworkRuleSet{ Properties: expandEventHubNamespaceNetworkRuleset(ruleSets.([]interface{})), } - // cannot use network rulesets with the basic SKU - if parameters.Sku.Name != namespaces.SkuNameBasic { - ruleSetsClient := meta.(*clients.Client).Eventhub.NetworkRuleSetsClient - namespaceId := networkrulesets.NewNamespaceID(id.SubscriptionId, id.ResourceGroupName, id.NamespaceName) - if _, err := ruleSetsClient.NamespacesCreateOrUpdateNetworkRuleSet(ctx, namespaceId, rulesets); err != nil { - return fmt.Errorf("setting network ruleset properties for %s: %+v", id, err) - } - } else if rulesets.Properties != nil { - props := rulesets.Properties - // so if the user has specified the non default rule sets throw a validation error - if *props.DefaultAction != networkrulesets.DefaultActionDeny || - (props.IpRules != nil && len(*props.IpRules) > 0) || - (props.VirtualNetworkRules != nil && len(*props.VirtualNetworkRules) > 0) { - return fmt.Errorf("network_rulesets cannot be used when the SKU is basic") - } + ruleSetsClient := meta.(*clients.Client).Eventhub.NetworkRuleSetsClient + namespaceId := networkrulesets.NewNamespaceID(id.SubscriptionId, id.ResourceGroupName, id.NamespaceName) + if _, err := ruleSetsClient.NamespacesCreateOrUpdateNetworkRuleSet(ctx, namespaceId, rulesets); err != nil { + return fmt.Errorf("setting network ruleset properties for %s: %+v", id, err) } } @@ -353,6 +391,16 @@ func resourceEventHubNamespaceUpdate(d *pluginsdk.ResourceData, meta interface{} autoInflateEnabled := d.Get("auto_inflate_enabled").(bool) zoneRedundant := d.Get("zone_redundant").(bool) + publicNetworkEnabled := namespaces.PublicNetworkAccessEnabled + if !d.Get("public_network_access_enabled").(bool) { + publicNetworkEnabled = namespaces.PublicNetworkAccessDisabled + } + + disableLocalAuth := false + if !d.Get("local_authentication_enabled").(bool) { + disableLocalAuth = true + } + identity, err := identity.ExpandSystemAndUserAssignedMap(d.Get("identity").([]interface{})) if err != nil { return fmt.Errorf("expanding `identity`: %+v", err) @@ -372,6 +420,8 @@ func resourceEventHubNamespaceUpdate(d *pluginsdk.ResourceData, meta interface{} Properties: &namespaces.EHNamespaceProperties{ IsAutoInflateEnabled: utils.Bool(autoInflateEnabled), ZoneRedundant: utils.Bool(zoneRedundant), + DisableLocalAuth: utils.Bool(disableLocalAuth), + PublicNetworkAccess: &publicNetworkEnabled, }, Tags: tags.Expand(t), } @@ -380,6 +430,11 @@ func resourceEventHubNamespaceUpdate(d *pluginsdk.ResourceData, meta interface{} parameters.Properties.ClusterArmId = utils.String(v) } + if tlsValue := d.Get("minimum_tls_version").(string); tlsValue != "" { + minimumTls := namespaces.TlsVersion(tlsValue) + parameters.Properties.MinimumTlsVersion = &minimumTls + } + if v, ok := d.GetOk("maximum_throughput_units"); ok { parameters.Properties.MaximumThroughputUnits = utils.Int64(int64(v.(int))) } @@ -397,32 +452,37 @@ func resourceEventHubNamespaceUpdate(d *pluginsdk.ResourceData, meta interface{} return fmt.Errorf("updating %s: %+v", id, err) } - d.SetId(id.ID()) + if d.HasChange("network_rulesets") { + // cannot use network rulesets with the basic SKU + if parameters.Sku.Name == namespaces.SkuNameBasic { + return fmt.Errorf("network_rulesets cannot be used when the SKU is basic") + } - ruleSets, hasRuleSets := d.GetOk("network_rulesets") - if hasRuleSets { + ruleSets := d.Get("network_rulesets") rulesets := networkrulesets.NetworkRuleSet{ Properties: expandEventHubNamespaceNetworkRuleset(ruleSets.([]interface{})), } - // cannot use network rulesets with the basic SKU - if parameters.Sku.Name != namespaces.SkuNameBasic { - ruleSetsClient := meta.(*clients.Client).Eventhub.NetworkRuleSetsClient - namespaceId := networkrulesets.NewNamespaceID(id.SubscriptionId, id.ResourceGroupName, id.NamespaceName) - if _, err := ruleSetsClient.NamespacesCreateOrUpdateNetworkRuleSet(ctx, namespaceId, rulesets); err != nil { - return fmt.Errorf("setting network ruleset properties for %s: %+v", id, err) - } - } else if rulesets.Properties != nil { - props := rulesets.Properties - // so if the user has specified the non default rule sets throw a validation error - if *props.DefaultAction != networkrulesets.DefaultActionDeny || - (props.IpRules != nil && len(*props.IpRules) > 0) || - (props.VirtualNetworkRules != nil && len(*props.VirtualNetworkRules) > 0) { - return fmt.Errorf("network_rulesets cannot be used when the SKU is basic") - } + ruleSetsClient := meta.(*clients.Client).Eventhub.NetworkRuleSetsClient + namespaceId := networkrulesets.NewNamespaceID(id.SubscriptionId, id.ResourceGroupName, id.NamespaceName) + if _, err := ruleSetsClient.NamespacesCreateOrUpdateNetworkRuleSet(ctx, namespaceId, rulesets); err != nil { + return fmt.Errorf("setting network ruleset properties for %s: %+v", id, err) } } + deadline, _ := ctx.Deadline() + stateConf := &pluginsdk.StateChangeConf{ + Pending: []string{"Activating", "ActivatingIdentity", "Updating", "Pending"}, + Target: []string{"Succeeded"}, + Refresh: eventHubNamespaceProvisioningStateRefreshFunc(ctx, client, id), + Timeout: time.Until(deadline), + PollInterval: 10 * time.Second, + } + + if _, err := stateConf.WaitForStateContext(ctx); err != nil { + return fmt.Errorf("waiting for %s to be updated: %+v", id, err) + } + return resourceEventHubNamespaceRead(d, meta) } @@ -472,6 +532,22 @@ func resourceEventHubNamespaceRead(d *pluginsdk.ResourceData, meta interface{}) d.Set("maximum_throughput_units", int(*props.MaximumThroughputUnits)) d.Set("zone_redundant", props.ZoneRedundant) d.Set("dedicated_cluster_id", props.ClusterArmId) + + localAuthDisabled := false + if props.DisableLocalAuth != nil { + localAuthDisabled = *props.DisableLocalAuth + } + d.Set("local_authentication_enabled", !localAuthDisabled) + + publicNetworkAccess := true + if props.PublicNetworkAccess != nil && *props.PublicNetworkAccess == namespaces.PublicNetworkAccessDisabled { + publicNetworkAccess = false + } + d.Set("public_network_access_enabled", publicNetworkAccess) + + if props.MinimumTlsVersion != nil { + d.Set("minimum_tls_version", *props.MinimumTlsVersion) + } } if err := tags.FlattenAndSet(d, model.Tags); err != nil { @@ -568,6 +644,26 @@ func eventHubNamespaceStateStatusCodeRefreshFunc(ctx context.Context, client *na } } +func eventHubNamespaceProvisioningStateRefreshFunc(ctx context.Context, client *namespaces.NamespacesClient, id namespaces.NamespaceId) pluginsdk.StateRefreshFunc { + return func() (interface{}, string, error) { + res, err := client.Get(ctx, id) + + provisioningState := "Pending" + if err != nil { + if response.WasNotFound(res.HttpResponse) { + return res, provisioningState, nil + } + return nil, "Error", fmt.Errorf("polling for the provisioning state of %s: %+v", id, err) + } + + if res.Model != nil && res.Model.Properties != nil && res.Model.Properties.ProvisioningState != nil { + provisioningState = *res.Model.Properties.ProvisioningState + } + + return res, provisioningState, nil + } +} + func expandEventHubNamespaceNetworkRuleset(input []interface{}) *networkrulesets.NetworkRuleSetProperties { if len(input) == 0 { return nil @@ -606,11 +702,11 @@ func expandEventHubNamespaceNetworkRuleset(input []interface{}) *networkrulesets if v, ok := block["ip_rule"].([]interface{}); ok { if len(v) > 0 { - var rules []networkrulesets.NWRuleSetIpRules + var rules []networkrulesets.NWRuleSetIPRules for _, r := range v { rblock := r.(map[string]interface{}) - rules = append(rules, networkrulesets.NWRuleSetIpRules{ - IpMask: utils.String(rblock["ip_mask"].(string)), + rules = append(rules, networkrulesets.NWRuleSetIPRules{ + IPMask: utils.String(rblock["ip_mask"].(string)), Action: func() *networkrulesets.NetworkRuleIPAction { v := networkrulesets.NetworkRuleIPAction(rblock["action"].(string)) return &v @@ -618,7 +714,7 @@ func expandEventHubNamespaceNetworkRuleset(input []interface{}) *networkrulesets }) } - ruleset.IpRules = &rules + ruleset.IPRules = &rules } } @@ -649,7 +745,7 @@ func flattenEventHubNamespaceNetworkRuleset(ruleset networkrulesets.NamespacesGe } } ipBlocks := make([]interface{}, 0) - if ipRules := ruleset.Model.Properties.IpRules; ipRules != nil { + if ipRules := ruleset.Model.Properties.IPRules; ipRules != nil { for _, ipRule := range *ipRules { block := make(map[string]interface{}) @@ -660,7 +756,7 @@ func flattenEventHubNamespaceNetworkRuleset(ruleset networkrulesets.NamespacesGe block["action"] = action - if v := ipRule.IpMask; v != nil { + if v := ipRule.IPMask; v != nil { block["ip_mask"] = *v } @@ -693,3 +789,11 @@ func resourceVnetRuleHash(v interface{}) int { } return pluginsdk.HashString(buf.String()) } + +func eventhubTLSVersionDiff(ctx context.Context, d *pluginsdk.ResourceDiff, _ interface{}) (err error) { + old, new := d.GetChange("minimum_tls_version") + if old != "" && new == "" { + err = fmt.Errorf("`minimum_tls_version` has been set before, please set a valid value for this property ") + } + return +} diff --git a/internal/services/eventhub/eventhub_namespace_resource_test.go b/internal/services/eventhub/eventhub_namespace_resource_test.go index 7793f6235337..9712741a2f93 100644 --- a/internal/services/eventhub/eventhub_namespace_resource_test.go +++ b/internal/services/eventhub/eventhub_namespace_resource_test.go @@ -6,7 +6,7 @@ import ( "regexp" "testing" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-01-01-preview/namespaces" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2022-01-01-preview/namespaces" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" @@ -326,6 +326,21 @@ func TestAccEventHubNamespace_BasicWithCapacity(t *testing.T) { }) } +func TestAccEventHubNamespace_BasicWithLocalAuthProperty(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_eventhub_namespace", "test") + r := EventHubNamespaceResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.localAuthProperty(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("local_authentication_enabled").HasValue("false"), + ), + }, + }) +} + func TestAccEventHubNamespace_BasicWithCapacityUpdate(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_eventhub_namespace", "test") r := EventHubNamespaceResource{} @@ -428,6 +443,50 @@ func TestAccEventHubNamespace_maximumThroughputUnitsUpdate(t *testing.T) { }) } +func TestAccEventHubNamespace_publicNetworkAccessUpdate(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_eventhub_namespace", "test") + r := EventHubNamespaceResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("public_network_access_enabled").HasValue("true"), + ), + }, + { + Config: r.publicNetworkAccessUpdate(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("public_network_access_enabled").HasValue("false"), + ), + }, + }) +} + +func TestAccEventHubNamespace_minimumTLSUpdate(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_eventhub_namespace", "test") + r := EventHubNamespaceResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("minimum_tls_version").HasValue("1.2"), + ), + }, + { + Config: r.minimumTLSUpdate(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("minimum_tls_version").HasValue("1.1"), + ), + }, + }) +} + func TestAccEventHubNamespace_autoInfalteDisabledWithAutoInflateUnits(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_eventhub_namespace", "test") r := EventHubNamespaceResource{} @@ -924,6 +983,69 @@ resource "azurerm_eventhub_namespace" "test" { `, data.RandomInteger, data.Locations.Primary, data.RandomInteger, capacity) } +func (EventHubNamespaceResource) localAuthProperty(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_eventhub_namespace" "test" { + name = "acctesteventhubnamespace-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku = "Basic" + local_authentication_enabled = false +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger) +} + +func (EventHubNamespaceResource) publicNetworkAccessUpdate(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_eventhub_namespace" "test" { + name = "acctesteventhubnamespace-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku = "Basic" + public_network_access_enabled = false +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger) +} + +func (EventHubNamespaceResource) minimumTLSUpdate(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_eventhub_namespace" "test" { + name = "acctesteventhubnamespace-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku = "Basic" + minimum_tls_version = "1.1" +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger) +} + func (EventHubNamespaceResource) maximumThroughputUnitsUpdate(data acceptance.TestData) string { return fmt.Sprintf(` provider "azurerm" { diff --git a/internal/services/eventhub/eventhub_namespace_schema_registry_resource.go b/internal/services/eventhub/eventhub_namespace_schema_registry_resource.go new file mode 100644 index 000000000000..a2e62d4bcc54 --- /dev/null +++ b/internal/services/eventhub/eventhub_namespace_schema_registry_resource.go @@ -0,0 +1,180 @@ +package eventhub + +import ( + "fmt" + "log" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/namespaces" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/schemaregistry" + "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/eventhub/validate" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" +) + +func resourceEventHubNamespaceSchemaRegistry() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Create: resourceEventHubNamespaceSchemaRegistryCreateUpdate, + Read: resourceEventHubNamespaceSchemaRegistryRead, + // Update: resourceEventHubNamespaceSchemaRegistryCreateUpdate, + Delete: resourceEventHubNamespaceSchemaRegistryDelete, + + Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { + _, err := schemaregistry.ParseSchemaGroupID(id) + return err + }), + + Timeouts: &pluginsdk.ResourceTimeout{ + Create: pluginsdk.DefaultTimeout(30 * time.Minute), + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + // Update: pluginsdk.DefaultTimeout(30 * time.Minute), + Delete: pluginsdk.DefaultTimeout(30 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.ValidateSchemaGroupName(), + }, + + "namespace_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: namespaces.ValidateNamespaceID, + }, + + "schema_compatibility": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{ + string(schemaregistry.SchemaCompatibilityNone), + string(schemaregistry.SchemaCompatibilityBackward), + string(schemaregistry.SchemaCompatibilityForward), + }, false), + }, + + "schema_type": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{ + string(schemaregistry.SchemaTypeUnknown), + string(schemaregistry.SchemaTypeAvro), + }, false), + }, + }, + } +} + +func resourceEventHubNamespaceSchemaRegistryCreateUpdate(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Eventhub.SchemaRegistryClient + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + log.Printf("[INFO] preparing arguments for AzureRM EventHub Namespace Schema Registry creation.") + + namespaceId, err := namespaces.ParseNamespaceID(d.Get("namespace_id").(string)) + if err != nil { + return fmt.Errorf("parsing eventhub namespace %s error: %+v", namespaceId.ID(), err) + } + + id := schemaregistry.NewSchemaGroupID(subscriptionId, namespaceId.ResourceGroupName, namespaceId.NamespaceName, d.Get("name").(string)) + if d.IsNewResource() { + existing, err := client.Get(ctx, id) + if err != nil { + if !response.WasNotFound(existing.HttpResponse) { + return fmt.Errorf("checking for presence of existing %s: %+v", id, err) + } + } + + if existing.Model != nil { + return tf.ImportAsExistsError("azurerm_eventhub_namespace_schema_group", id.ID()) + } + } + + schemaCompatibilityType := schemaregistry.SchemaCompatibility(d.Get("schema_compatibility").(string)) + schemaType := schemaregistry.SchemaType(d.Get("schema_type").(string)) + + parameters := schemaregistry.SchemaGroup{ + Properties: &schemaregistry.SchemaGroupProperties{ + SchemaCompatibility: &schemaCompatibilityType, + SchemaType: &schemaType, + }, + } + + if _, err := client.CreateOrUpdate(ctx, id, parameters); err != nil { + return fmt.Errorf("creating %s: %+v", id, err) + } + + d.SetId(id.ID()) + + return resourceEventHubNamespaceSchemaRegistryRead(d, meta) +} + +func resourceEventHubNamespaceSchemaRegistryRead(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Eventhub.SchemaRegistryClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := schemaregistry.ParseSchemaGroupID(d.Id()) + if err != nil { + return err + } + + resp, err := client.Get(ctx, *id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + d.SetId("") + return nil + } + return fmt.Errorf("making Read request on %s: %+v", id, err) + } + + d.Set("name", id.SchemaGroupName) + + namespaceId := namespaces.NewNamespaceID(id.SubscriptionId, id.ResourceGroupName, id.NamespaceName) + d.Set("namespace_id", namespaceId.ID()) + + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + if props.SchemaCompatibility != nil { + d.Set("schema_compatibility", string(*props.SchemaCompatibility)) + } + if props.SchemaType != nil { + d.Set("schema_type", string(*props.SchemaType)) + } + } + } + + return nil +} + +func resourceEventHubNamespaceSchemaRegistryDelete(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Eventhub.SchemaRegistryClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := schemaregistry.ParseSchemaGroupID(d.Id()) + if err != nil { + return err + } + + resp, err := client.Delete(ctx, *id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return nil + } + + return fmt.Errorf("deleting %s: %+v", id, err) + } + + return nil +} diff --git a/internal/services/eventhub/eventhub_namespace_schema_registry_resource_test.go b/internal/services/eventhub/eventhub_namespace_schema_registry_resource_test.go new file mode 100644 index 000000000000..cfb779444b81 --- /dev/null +++ b/internal/services/eventhub/eventhub_namespace_schema_registry_resource_test.go @@ -0,0 +1,71 @@ +package eventhub_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/schemaregistry" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type EventHubNamespaceSchemaRegistryResource struct{} + +func TestAccEventHubNamespaceSchemaRegistry_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_eventhub_namespace_schema_group", "test") + r := EventHubNamespaceSchemaRegistryResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r)), + }, + data.ImportStep(), + }) +} + +func (EventHubNamespaceSchemaRegistryResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + id, err := schemaregistry.ParseSchemaGroupID(state.ID) + if err != nil { + return nil, err + } + + resp, err := clients.Eventhub.SchemaRegistryClient.Get(ctx, *id) + if err != nil { + return nil, fmt.Errorf("retrieving %s: %v", *id, err) + } + + return utils.Bool(resp.Model != nil), nil +} + +func (EventHubNamespaceSchemaRegistryResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-eventhubSG-%d" + location = "%s" +} + +resource "azurerm_eventhub_namespace" "test" { + name = "acctesteventhubnamespace-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku = "Standard" +} + +resource "azurerm_eventhub_namespace_schema_group" "test" { + name = "acctestsg-%d" + namespace_id = azurerm_eventhub_namespace.test.id + schema_compatibility = "Forward" + schema_type = "Avro" +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} diff --git a/internal/services/eventhub/eventhub_resource.go b/internal/services/eventhub/eventhub_resource.go index 536be3754628..ffaa7ffb3e4a 100644 --- a/internal/services/eventhub/eventhub_resource.go +++ b/internal/services/eventhub/eventhub_resource.go @@ -6,8 +6,8 @@ import ( "time" "github.com/hashicorp/go-azure-helpers/lang/response" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/eventhubs" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-01-01-preview/namespaces" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/eventhubs" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2022-01-01-preview/namespaces" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" diff --git a/internal/services/eventhub/eventhub_resource_test.go b/internal/services/eventhub/eventhub_resource_test.go index 579c92c652ae..7a23fde4d42a 100644 --- a/internal/services/eventhub/eventhub_resource_test.go +++ b/internal/services/eventhub/eventhub_resource_test.go @@ -6,7 +6,7 @@ import ( "strconv" "testing" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/eventhubs" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/eventhubs" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" diff --git a/internal/services/eventhub/migration/consumer_group.go b/internal/services/eventhub/migration/consumer_group.go index 08a09b63ff98..0e3ec8e815e4 100644 --- a/internal/services/eventhub/migration/consumer_group.go +++ b/internal/services/eventhub/migration/consumer_group.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/consumergroups" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/consumergroups" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" ) diff --git a/internal/services/eventhub/migration/eventhub_authorization_rule.go b/internal/services/eventhub/migration/eventhub_authorization_rule.go index 94868d53184f..52529b323223 100644 --- a/internal/services/eventhub/migration/eventhub_authorization_rule.go +++ b/internal/services/eventhub/migration/eventhub_authorization_rule.go @@ -4,7 +4,7 @@ import ( "context" "log" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/eventhubs" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/eventhubs" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" ) diff --git a/internal/services/eventhub/registration.go b/internal/services/eventhub/registration.go index 19db6da0b323..0edb4cf9a9f3 100644 --- a/internal/services/eventhub/registration.go +++ b/internal/services/eventhub/registration.go @@ -46,6 +46,7 @@ func (r Registration) SupportedResources() map[string]*pluginsdk.Resource { "azurerm_eventhub_namespace_customer_managed_key": resourceEventHubNamespaceCustomerManagedKey(), "azurerm_eventhub_namespace_disaster_recovery_config": resourceEventHubNamespaceDisasterRecoveryConfig(), "azurerm_eventhub_namespace": resourceEventHubNamespace(), + "azurerm_eventhub_namespace_schema_group": resourceEventHubNamespaceSchemaRegistry(), "azurerm_eventhub": resourceEventHub(), } } diff --git a/internal/services/eventhub/validate/eventhub_names.go b/internal/services/eventhub/validate/eventhub_names.go index ed1d5b01801e..09c0fe01af28 100644 --- a/internal/services/eventhub/validate/eventhub_names.go +++ b/internal/services/eventhub/validate/eventhub_names.go @@ -35,3 +35,10 @@ func ValidateEventHubAuthorizationRuleName() pluginsdk.SchemaValidateFunc { "The authorization rule name can contain only letters, numbers, periods, hyphens and underscores. The name must start and end with a letter or number and be up to 60 characters long.", ) } + +func ValidateSchemaGroupName() pluginsdk.SchemaValidateFunc { + return validation.StringMatch( + regexp.MustCompile("^[a-zA-Z0-9]([-._a-zA-Z0-9]{0,254}[a-zA-Z0-9])?$"), + "The schema group name can contain only letters, numbers, periods (.), hyphens (-),and underscores (_), up to 256 characters, and it must begin and end with a letter or number.", + ) +} diff --git a/internal/services/firewall/firewall_policy_resource.go b/internal/services/firewall/firewall_policy_resource.go index e9086275bc69..b1cd243ef554 100644 --- a/internal/services/firewall/firewall_policy_resource.go +++ b/internal/services/firewall/firewall_policy_resource.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/identity" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" @@ -17,9 +18,9 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/internal/locks" "github.com/hashicorp/terraform-provider-azurerm/internal/services/firewall/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/firewall/validate" - logAnalytiscValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/loganalytics/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/suppress" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" "github.com/hashicorp/terraform-provider-azurerm/utils" @@ -98,6 +99,12 @@ func resourceFirewallPolicyCreateUpdate(d *pluginsdk.ResourceData, meta interfac } } + if v, ok := d.GetOk("sql_redirect_allowed"); ok { + props.FirewallPolicyPropertiesFormat.SQL = &network.FirewallPolicySQL{ + AllowSQLRedirect: utils.Bool(v.(bool)), + } + } + if v, ok := d.GetOk("private_ip_ranges"); ok { privateIPRanges := utils.ExpandStringSlice(v.([]interface{})) props.FirewallPolicyPropertiesFormat.Snat = &network.FirewallPolicySNAT{ @@ -198,6 +205,12 @@ func resourceFirewallPolicyRead(d *pluginsdk.ResourceData, meta interface{}) err if err := d.Set("insights", flattenFirewallPolicyInsights(prop.Insights)); err != nil { return fmt.Errorf(`setting "insights": %+v`, err) } + + if prop.SQL != nil && prop.SQL.AllowSQLRedirect != nil { + if err := d.Set("sql_redirect_allowed", prop.SQL.AllowSQLRedirect); err != nil { + return fmt.Errorf("setting `sql_redirect_allowed`: %+v", err) + } + } } flattenedIdentity, err := flattenFirewallPolicyIdentity(resp.Identity) @@ -297,10 +310,16 @@ func expandFirewallPolicyIntrusionDetection(input []interface{}) *network.Firewa }) } + var privateRanges []string + for _, v := range raw["private_ranges"].([]interface{}) { + privateRanges = append(privateRanges, v.(string)) + } + return &network.FirewallPolicyIntrusionDetection{ Mode: network.FirewallPolicyIntrusionDetectionStateType(raw["mode"].(string)), Configuration: &network.FirewallPolicyIntrusionDetectionConfiguration{ SignatureOverrides: &signatureOverrides, + PrivateRanges: &privateRanges, BypassTrafficSettings: &trafficBypass, }, } @@ -460,12 +479,12 @@ func flattenFirewallPolicyIntrusionDetection(input *network.FirewallPolicyIntrus description = *bypass.Description } - sourceAddresses := make([]string, 0) + var sourceAddresses []string if bypass.SourceAddresses != nil { sourceAddresses = *bypass.SourceAddresses } - destinationAddresses := make([]string, 0) + var destinationAddresses []string if bypass.DestinationAddresses != nil { destinationAddresses = *bypass.DestinationAddresses } @@ -497,12 +516,17 @@ func flattenFirewallPolicyIntrusionDetection(input *network.FirewallPolicyIntrus }) } } + var privateRanges []string + if privates := input.Configuration.PrivateRanges; privates != nil { + privateRanges = *privates + } return []interface{}{ map[string]interface{}{ "mode": string(input.Mode), "signature_overrides": signatureOverrides, "traffic_bypass": trafficBypass, + "private_ranges": privateRanges, }, } } @@ -727,6 +751,13 @@ func resourceFirewallPolicySchema() map[string]*pluginsdk.Schema { }, }, }, + "private_ranges": { + Type: pluginsdk.TypeList, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + }, + }, "traffic_bypass": { Type: pluginsdk.TypeList, Optional: true, @@ -743,12 +774,14 @@ func resourceFirewallPolicySchema() map[string]*pluginsdk.Schema { "protocol": { Type: pluginsdk.TypeString, Required: true, + // protocol to be one of [ICMP ANY TCP UDP] but response may be "Any" + DiffSuppressFunc: suppress.CaseDifference, ValidateFunc: validation.StringInSlice([]string{ string(network.FirewallPolicyIntrusionDetectionProtocolICMP), string(network.FirewallPolicyIntrusionDetectionProtocolANY), string(network.FirewallPolicyIntrusionDetectionProtocolTCP), string(network.FirewallPolicyIntrusionDetectionProtocolUDP), - }, false), + }, true), }, "source_addresses": { Type: pluginsdk.TypeSet, @@ -826,7 +859,7 @@ func resourceFirewallPolicySchema() map[string]*pluginsdk.Schema { "default_log_analytics_workspace_id": { Type: pluginsdk.TypeString, Required: true, - ValidateFunc: logAnalytiscValidate.LogAnalyticsWorkspaceID, + ValidateFunc: workspaces.ValidateWorkspaceID, }, "retention_in_days": { Type: pluginsdk.TypeInt, @@ -841,7 +874,7 @@ func resourceFirewallPolicySchema() map[string]*pluginsdk.Schema { "id": { Type: pluginsdk.TypeString, Required: true, - ValidateFunc: logAnalytiscValidate.LogAnalyticsWorkspaceID, + ValidateFunc: workspaces.ValidateWorkspaceID, }, "firewall_location": commonschema.LocationWithoutForceNew(), }, @@ -851,6 +884,11 @@ func resourceFirewallPolicySchema() map[string]*pluginsdk.Schema { }, }, + "sql_redirect_allowed": { + Type: pluginsdk.TypeBool, + Optional: true, + }, + "child_policies": { Type: pluginsdk.TypeList, Computed: true, diff --git a/internal/services/firewall/firewall_policy_resource_test.go b/internal/services/firewall/firewall_policy_resource_test.go index 77610b0cec81..5f03e5f6cf8b 100644 --- a/internal/services/firewall/firewall_policy_resource_test.go +++ b/internal/services/firewall/firewall_policy_resource_test.go @@ -58,6 +58,7 @@ func TestAccFirewallPolicy_complete(t *testing.T) { check.That(data.ResourceName).Key("dns.0.servers.0").HasValue("1.1.1.1"), check.That(data.ResourceName).Key("dns.0.servers.1").HasValue("3.3.3.3"), check.That(data.ResourceName).Key("dns.0.servers.2").HasValue("2.2.2.2"), + check.That(data.ResourceName).Key("dns.0.proxy_enabled").HasValue("true"), ), }, data.ImportStep(), @@ -127,13 +128,6 @@ func TestAccFirewallPolicy_updatePremium(t *testing.T) { ), }, data.ImportStep(), - { - Config: r.basic(data), - Check: acceptance.ComposeTestCheckFunc( - check.That(data.ResourceName).ExistsInAzure(r), - ), - }, - data.ImportStep(), }) } @@ -287,11 +281,14 @@ resource "azurerm_firewall_policy" "test" { state = "Alert" id = "1" } + private_ranges = ["172.111.111.111"] traffic_bypass { - name = "Name bypass traffic settings" - description = "Description bypass traffic settings" - protocol = "ANY" - destination_ports = ["*"] + name = "Name bypass traffic settings" + description = "Description bypass traffic settings" + destination_addresses = [] + source_addresses = [] + protocol = "Any" + destination_ports = ["*"] source_ip_groups = [ azurerm_ip_group.test_source.id, ] @@ -300,6 +297,7 @@ resource "azurerm_firewall_policy" "test" { ] } } + sql_redirect_allowed = true identity { type = "UserAssigned" identity_ids = [ diff --git a/internal/services/firewall/firewall_resource.go b/internal/services/firewall/firewall_resource.go index e65975c52606..843cb7b0a5e8 100644 --- a/internal/services/firewall/firewall_resource.go +++ b/internal/services/firewall/firewall_resource.go @@ -74,7 +74,6 @@ func resourceFirewall() *pluginsdk.Resource { "sku_tier": { Type: pluginsdk.TypeString, Required: true, - ForceNew: true, ValidateFunc: validation.StringInSlice([]string{ string(network.AzureFirewallSkuTierPremium), string(network.AzureFirewallSkuTierStandard), diff --git a/internal/services/firewall/firewall_resource_test.go b/internal/services/firewall/firewall_resource_test.go index a4b9b8a095ac..84b5ebdf6ccc 100644 --- a/internal/services/firewall/firewall_resource_test.go +++ b/internal/services/firewall/firewall_resource_test.go @@ -16,6 +16,9 @@ import ( type FirewallResource struct{} +const premium = "Premium" +const standard = "Standard" + func TestAccFirewall_basic(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_firewall", "test") r := FirewallResource{} @@ -194,6 +197,31 @@ func TestAccFirewall_withZones(t *testing.T) { }) } +func TestAccFirewall_skuTierUpdate(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_firewall", "test") + r := FirewallResource{} + skuTier := standard + skuTierUpdate := premium + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.withSkuTier(data, skuTier), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("sku_tier").HasValue("Standard"), + ), + }, + { + Config: r.withSkuTier(data, skuTierUpdate), + Check: acceptance.ComposeTestCheckFunc( + + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("sku_tier").HasValue("Premium"), + ), + }, + }) +} + func TestAccFirewall_withoutZone(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_firewall", "test") r := FirewallResource{} @@ -764,6 +792,58 @@ resource "azurerm_firewall" "test" { `, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger) } +func (FirewallResource) withSkuTier(data acceptance.TestData, skuTier string) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-fw-%d" + location = "%s" +} + +resource "azurerm_virtual_network" "test" { + name = "acctestvirtnet%d" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_subnet" "test" { + name = "AzureFirewallSubnet" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.1.0/24"] +} + +resource "azurerm_public_ip" "test" { + name = "acctestpip%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + allocation_method = "Static" + sku = "Standard" + zones = [] +} + +resource "azurerm_firewall" "test" { + name = "acctestfirewall%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku_name = "AZFW_VNet" + sku_tier = "%s" + + ip_configuration { + name = "configuration" + subnet_id = azurerm_subnet.test.id + public_ip_address_id = azurerm_public_ip.test.id + } + + zones = [] +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, skuTier) +} + func (FirewallResource) withZones(data acceptance.TestData, zones []string) string { zoneString := strings.Join(zones, ",") return fmt.Sprintf(` diff --git a/internal/services/hdinsight/common_hdinsight.go b/internal/services/hdinsight/common_hdinsight.go index be369070aaf2..c8e10689a6d5 100644 --- a/internal/services/hdinsight/common_hdinsight.go +++ b/internal/services/hdinsight/common_hdinsight.go @@ -321,6 +321,17 @@ func createHDInsightEdgeNodes(ctx context.Context, client *hdinsight.Application ApplicationType: utils.String("CustomApplication"), }, } + + if v, ok := input["https_endpoints"]; ok { + httpsEndpoints := expandHDInsightApplicationEdgeNodeHttpsEndpoints(v.([]interface{})) + application.Properties.HTTPSEndpoints = httpsEndpoints + } + + if v, ok := input["uninstall_script_actions"]; ok { + uninstallScriptActions := expandHDInsightApplicationEdgeNodeUninstallScriptActions(v.([]interface{})) + application.Properties.UninstallScriptActions = uninstallScriptActions + } + future, err := client.Create(ctx, resourceGroup, name, name, application) if err != nil { return fmt.Errorf("creating edge nodes for HDInsight Hadoop Cluster %q (Resource Group %q): %+v", name, resourceGroup, err) diff --git a/internal/services/hdinsight/hdinsight_hadoop_cluster_resource.go b/internal/services/hdinsight/hdinsight_hadoop_cluster_resource.go index bfdaeef76dfb..3df0a02f86ba 100644 --- a/internal/services/hdinsight/hdinsight_hadoop_cluster_resource.go +++ b/internal/services/hdinsight/hdinsight_hadoop_cluster_resource.go @@ -95,6 +95,8 @@ func resourceHDInsightHadoopCluster() *pluginsdk.Resource { }, }, + "disk_encryption": SchemaHDInsightsDiskEncryptionProperties(), + "gateway": SchemaHDInsightsGateway(), "metastores": SchemaHDInsightsExternalMetastores(), @@ -153,9 +155,18 @@ func resourceHDInsightHadoopCluster() *pluginsdk.Resource { Required: true, ValidateFunc: validation.StringIsNotEmpty, }, + "parameters": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.StringIsNotEmpty, + }, }, }, }, + + "https_endpoints": SchemaHDInsightsHttpsEndpoints(), + + "uninstall_script_actions": SchemaHDInsightsScriptActions(), }, }, }, @@ -264,6 +275,14 @@ func resourceHDInsightHadoopClusterCreate(d *pluginsdk.ResourceData, meta interf Identity: identity, } + if diskEncryptionPropertiesRaw, ok := d.GetOk("disk_encryption"); ok { + diskEncryptionProperties, err := ExpandHDInsightsDiskEncryptionProperties(diskEncryptionPropertiesRaw.([]interface{})) + if err != nil { + return err + } + params.Properties.DiskEncryptionProperties = diskEncryptionProperties + } + if v, ok := d.GetOk("security_profile"); ok { params.Properties.SecurityProfile = ExpandHDInsightSecurityProfile(v.([]interface{})) @@ -428,6 +447,16 @@ func resourceHDInsightHadoopClusterRead(d *pluginsdk.ResourceData, meta interfac flattenedRoles = flattenHDInsightEdgeNode(flattenedRoles, edgeNodeProps) } + if props.DiskEncryptionProperties != nil { + diskEncryptionProps, err := FlattenHDInsightsDiskEncryptionProperties(*props.DiskEncryptionProperties) + if err != nil { + return err + } + if err := d.Set("disk_encryption", diskEncryptionProps); err != nil { + return fmt.Errorf("flattening `disk_encryption`: %+v", err) + } + } + if err := d.Set("roles", flattenedRoles); err != nil { return fmt.Errorf("flattening `roles`: %+v", err) } @@ -485,7 +514,30 @@ func flattenHDInsightEdgeNode(roles []interface{}, props *hdinsight.ApplicationP for _, action := range *installScriptActions { actions["name"] = action.Name actions["uri"] = action.URI + actions["parameters"] = action.Parameters + } + } + + if uninstallScriptActions := props.UninstallScriptActions; uninstallScriptActions != nil && len(*uninstallScriptActions) != 0 { + uninstallActions := make(map[string]interface{}) + for _, uninstallAction := range *uninstallScriptActions { + actions["name"] = uninstallAction.Name + actions["uri"] = uninstallAction.URI + actions["parameters"] = uninstallAction.Parameters + } + edgeNode["uninstall_script_actions"] = []interface{}{uninstallActions} + } + + if HTTPSEndpoints := props.HTTPSEndpoints; HTTPSEndpoints != nil && len(*HTTPSEndpoints) != 0 { + httpsEndpoints := make(map[string]interface{}) + for _, HTTPSEndpoint := range *HTTPSEndpoints { + httpsEndpoints["access_modes"] = HTTPSEndpoint.AccessModes + httpsEndpoints["destination_port"] = HTTPSEndpoint.DestinationPort + httpsEndpoints["disable_gateway_auth"] = HTTPSEndpoint.DisableGatewayAuth + httpsEndpoints["private_ip_address"] = HTTPSEndpoint.PrivateIPAddress + httpsEndpoints["sub_domain_suffix"] = HTTPSEndpoint.SubDomainSuffix } + edgeNode["https_endpoints"] = []interface{}{httpsEndpoints} } edgeNode["install_script_action"] = []interface{}{actions} @@ -524,12 +576,69 @@ func expandHDInsightApplicationEdgeNodeInstallScriptActions(input []interface{}) name := val["name"].(string) uri := val["uri"].(string) + parameters := val["parameters"].(string) action := hdinsight.RuntimeScriptAction{ Name: utils.String(name), URI: utils.String(uri), // The only role available for edge nodes is edgenode - Roles: &[]string{"edgenode"}, + Parameters: utils.String(parameters), + Roles: &[]string{"edgenode"}, + } + + actions = append(actions, action) + } + + return &actions +} + +func expandHDInsightApplicationEdgeNodeHttpsEndpoints(input []interface{}) *[]hdinsight.ApplicationGetHTTPSEndpoint { + endpoints := make([]hdinsight.ApplicationGetHTTPSEndpoint, 0) + if len(input) == 0 || input[0] == nil { + return &endpoints + } + + for _, v := range input { + val := v.(map[string]interface{}) + + accessModes := val["access_modes"].([]string) + destinationPort := val["destination_port"].(int32) + disableGatewayAuth := val["disable_gateway_auth"].(bool) + privateIpAddress := val["private_ip_address"].(string) + subDomainSuffix := val["sub_domain_suffix"].(string) + + endPoint := hdinsight.ApplicationGetHTTPSEndpoint{ + AccessModes: &accessModes, + DestinationPort: utils.Int32(destinationPort), + PrivateIPAddress: utils.String(privateIpAddress), + SubDomainSuffix: utils.String(subDomainSuffix), + DisableGatewayAuth: utils.Bool(disableGatewayAuth), + } + + endpoints = append(endpoints, endPoint) + } + + return &endpoints +} + +func expandHDInsightApplicationEdgeNodeUninstallScriptActions(input []interface{}) *[]hdinsight.RuntimeScriptAction { + actions := make([]hdinsight.RuntimeScriptAction, 0) + if len(input) == 0 || input[0] == nil { + return &actions + } + + for _, v := range input { + val := v.(map[string]interface{}) + + name := val["name"].(string) + uri := val["uri"].(string) + parameters := val["parameters"].(string) + + action := hdinsight.RuntimeScriptAction{ + Name: utils.String(name), + URI: utils.String(uri), + Parameters: utils.String(parameters), + Roles: &[]string{"edgenode"}, } actions = append(actions, action) diff --git a/internal/services/hdinsight/hdinsight_hadoop_cluster_resource_test.go b/internal/services/hdinsight/hdinsight_hadoop_cluster_resource_test.go index fc357f3a5520..34887c8c22e3 100644 --- a/internal/services/hdinsight/hdinsight_hadoop_cluster_resource_test.go +++ b/internal/services/hdinsight/hdinsight_hadoop_cluster_resource_test.go @@ -323,6 +323,26 @@ func TestAccHDInsightHadoopCluster_tls(t *testing.T) { }) } +func TestAccHDInsightHadoopCluster_diskEncryption(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_hdinsight_hadoop_cluster", "test") + r := HDInsightHadoopClusterResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.diskEncryption(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("roles.0.head_node.0.password", + "roles.0.head_node.0.vm_size", + "roles.0.worker_node.0.password", + "roles.0.worker_node.0.vm_size", + "roles.0.zookeeper_node.0.password", + "roles.0.zookeeper_node.0.vm_size", + "storage_account"), + }) +} + func TestAccHDInsightHadoopCluster_allMetastores(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_hdinsight_hadoop_cluster", "test") r := HDInsightHadoopClusterResource{} @@ -539,7 +559,7 @@ func TestAccHDInsightHadoopCluster_updateMonitor(t *testing.T) { }) } -func TestAccAzureRMHDInsightHadoopCluster_autoscale(t *testing.T) { +func TestAccAzureRMHDInsightHadoopCluster_autoscaleWithSchedule(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_hdinsight_hadoop_cluster", "test") r := HDInsightHadoopClusterResource{} data.ResourceTest(t, r, []acceptance.TestStep{ @@ -558,6 +578,28 @@ func TestAccAzureRMHDInsightHadoopCluster_autoscale(t *testing.T) { "roles.0.zookeeper_node.0.password", "roles.0.zookeeper_node.0.vm_size", "storage_account"), + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("https_endpoint").Exists(), + check.That(data.ResourceName).Key("ssh_endpoint").Exists(), + ), + }, + data.ImportStep("roles.0.head_node.0.password", + "roles.0.head_node.0.vm_size", + "roles.0.worker_node.0.password", + "roles.0.worker_node.0.vm_size", + "roles.0.zookeeper_node.0.password", + "roles.0.zookeeper_node.0.vm_size", + "storage_account"), + }) +} + +func TestAccAzureRMHDInsightHadoopCluster_autoscaleWithCapacity(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_hdinsight_hadoop_cluster", "test") + r := HDInsightHadoopClusterResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ { Config: r.autoscale_capacity(data), Check: acceptance.ComposeTestCheckFunc( @@ -1642,6 +1684,54 @@ resource "azurerm_hdinsight_hadoop_cluster" "test" { `, r.template(data), data.RandomInteger) } +func (r HDInsightHadoopClusterResource) diskEncryption(data acceptance.TestData) string { + return fmt.Sprintf(` +%s +resource "azurerm_hdinsight_hadoop_cluster" "test" { + name = "acctesthdi-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + cluster_version = "4.0" + tier = "Standard" + tls_min_version = "1.2" + component_version { + hadoop = "3.1" + } + gateway { + username = "acctestusrgw" + password = "TerrAform123!" + } + disk_encryption { + encryption_at_host_enabled = true + } + storage_account { + storage_container_id = azurerm_storage_container.test.id + storage_account_key = azurerm_storage_account.test.primary_access_key + is_default = true + } + roles { + head_node { + vm_size = "Standard_D4a_V4" + username = "acctestusrvm" + password = "AccTestvdSC4daf986!" + } + worker_node { + vm_size = "Standard_D4a_V4" + username = "acctestusrvm" + password = "AccTestvdSC4daf986!" + target_instance_count = 2 + } + zookeeper_node { + vm_size = "Standard_DS2_V2" + username = "acctestusrvm" + password = "AccTestvdSC4daf986!" + } + } +} + +`, r.template(data), data.RandomInteger) +} + func (r HDInsightHadoopClusterResource) allMetastores(data acceptance.TestData) string { return fmt.Sprintf(` %s diff --git a/internal/services/hdinsight/hdinsight_hbase_cluster_resource.go b/internal/services/hdinsight/hdinsight_hbase_cluster_resource.go index b7a728ab529e..525860966e86 100644 --- a/internal/services/hdinsight/hdinsight_hbase_cluster_resource.go +++ b/internal/services/hdinsight/hdinsight_hbase_cluster_resource.go @@ -89,6 +89,8 @@ func resourceHDInsightHBaseCluster() *pluginsdk.Resource { }, }, + "disk_encryption": SchemaHDInsightsDiskEncryptionProperties(), + "gateway": SchemaHDInsightsGateway(), "metastores": SchemaHDInsightsExternalMetastores(), @@ -230,6 +232,13 @@ func resourceHDInsightHBaseClusterCreate(d *pluginsdk.ResourceData, meta interfa } } + if diskEncryptionPropertiesRaw, ok := d.GetOk("disk_encryption"); ok { + params.Properties.DiskEncryptionProperties, err = ExpandHDInsightsDiskEncryptionProperties(diskEncryptionPropertiesRaw.([]interface{})) + if err != nil { + return err + } + } + future, err := client.Create(ctx, resourceGroup, name, params) if err != nil { return fmt.Errorf("failure creating HDInsight HBase Cluster %q (Resource Group %q): %+v", name, resourceGroup, err) @@ -335,6 +344,16 @@ func resourceHDInsightHBaseClusterRead(d *pluginsdk.ResourceData, meta interface } } + if props.DiskEncryptionProperties != nil { + diskEncryptionProps, err := FlattenHDInsightsDiskEncryptionProperties(*props.DiskEncryptionProperties) + if err != nil { + return err + } + if err := d.Set("disk_encryption", diskEncryptionProps); err != nil { + return fmt.Errorf("flattening `disk_encryption`: %+v", err) + } + } + hbaseRoles := hdInsightRoleDefinition{ HeadNodeDef: hdInsightHBaseClusterHeadNodeDefinition, WorkerNodeDef: hdInsightHBaseClusterWorkerNodeDefinition, diff --git a/internal/services/hdinsight/hdinsight_hbase_cluster_resource_test.go b/internal/services/hdinsight/hdinsight_hbase_cluster_resource_test.go index 561acd1428b7..67690918b949 100644 --- a/internal/services/hdinsight/hdinsight_hbase_cluster_resource_test.go +++ b/internal/services/hdinsight/hdinsight_hbase_cluster_resource_test.go @@ -221,6 +221,26 @@ func TestAccHDInsightHBaseCluster_tls(t *testing.T) { }) } +func TestAccHDInsightHBaseCluster_diskEncryption(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_hdinsight_hbase_cluster", "test") + r := HDInsightHBaseClusterResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.diskEncryption(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("roles.0.head_node.0.password", + "roles.0.head_node.0.vm_size", + "roles.0.worker_node.0.password", + "roles.0.worker_node.0.vm_size", + "roles.0.zookeeper_node.0.password", + "roles.0.zookeeper_node.0.vm_size", + "storage_account"), + }) +} + func TestAccHDInsightHBaseCluster_allMetastores(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_hdinsight_hbase_cluster", "test") r := HDInsightHBaseClusterResource{} @@ -400,43 +420,6 @@ func TestAccHDInsightHBaseCluster_updateMonitor(t *testing.T) { }) } -func TestAccAzureRMHDInsightHBaseCluster_autoscale(t *testing.T) { - data := acceptance.BuildTestData(t, "azurerm_hdinsight_hbase_cluster", "test") - r := HDInsightHBaseClusterResource{} - data.ResourceTest(t, r, []acceptance.TestStep{ - { - Config: r.autoscale_schedule(data), - Check: acceptance.ComposeTestCheckFunc( - check.That(data.ResourceName).ExistsInAzure(r), - check.That(data.ResourceName).Key("https_endpoint").Exists(), - check.That(data.ResourceName).Key("ssh_endpoint").Exists(), - ), - }, - data.ImportStep("roles.0.head_node.0.password", - "roles.0.head_node.0.vm_size", - "roles.0.worker_node.0.password", - "roles.0.worker_node.0.vm_size", - "roles.0.zookeeper_node.0.password", - "roles.0.zookeeper_node.0.vm_size", - "storage_account"), - { - Config: r.basic(data), - Check: acceptance.ComposeTestCheckFunc( - check.That(data.ResourceName).ExistsInAzure(r), - check.That(data.ResourceName).Key("https_endpoint").Exists(), - check.That(data.ResourceName).Key("ssh_endpoint").Exists(), - ), - }, - data.ImportStep("roles.0.head_node.0.password", - "roles.0.head_node.0.vm_size", - "roles.0.worker_node.0.password", - "roles.0.worker_node.0.vm_size", - "roles.0.zookeeper_node.0.password", - "roles.0.zookeeper_node.0.vm_size", - "storage_account"), - }) -} - func testAccHDInsightHBaseCluster_securityProfile(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_hdinsight_hbase_cluster", "test") r := HDInsightHBaseClusterResource{} @@ -1361,6 +1344,61 @@ resource "azurerm_hdinsight_hbase_cluster" "test" { `, r.template(data), data.RandomInteger) } +func (r HDInsightHBaseClusterResource) diskEncryption(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_hdinsight_hbase_cluster" "test" { + name = "acctesthdi-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + cluster_version = "4.0" + tier = "Standard" + tls_min_version = "1.2" + + component_version { + hbase = "2.1" + } + + gateway { + username = "acctestusrgw" + password = "TerrAform123!" + } + + storage_account { + storage_container_id = azurerm_storage_container.test.id + storage_account_key = azurerm_storage_account.test.primary_access_key + is_default = true + } + + disk_encryption { + encryption_at_host_enabled = true + } + + roles { + head_node { + vm_size = "Standard_D4a_V4" + username = "acctestusrvm" + password = "AccTestvdSC4daf986!" + } + + worker_node { + vm_size = "Standard_D4a_V4" + username = "acctestusrvm" + password = "AccTestvdSC4daf986!" + target_instance_count = 2 + } + + zookeeper_node { + vm_size = "Standard_D4a_V4" + username = "acctestusrvm" + password = "AccTestvdSC4daf986!" + } + } +} +`, r.template(data), data.RandomInteger) +} + func (r HDInsightHBaseClusterResource) allMetastores(data acceptance.TestData) string { return fmt.Sprintf(` %s @@ -1603,71 +1641,6 @@ resource "azurerm_hdinsight_hbase_cluster" "test" { `, r.template(data), data.RandomString, data.RandomInteger, data.RandomInteger) } -func (r HDInsightHBaseClusterResource) autoscale_schedule(data acceptance.TestData) string { - return fmt.Sprintf(` -%s - -resource "azurerm_hdinsight_hbase_cluster" "test" { - name = "acctesthdi-%d" - resource_group_name = azurerm_resource_group.test.name - location = azurerm_resource_group.test.location - cluster_version = "4.0" - tier = "Standard" - - component_version { - hbase = "2.1" - } - - gateway { - username = "acctestusrgw" - password = "TerrAform123!" - } - - storage_account { - storage_container_id = azurerm_storage_container.test.id - storage_account_key = azurerm_storage_account.test.primary_access_key - is_default = true - } - - roles { - head_node { - vm_size = "Standard_D3_V2" - username = "acctestusrvm" - password = "AccTestvdSC4daf986!" - } - - worker_node { - vm_size = "Standard_D3_V2" - username = "acctestusrvm" - password = "AccTestvdSC4daf986!" - target_instance_count = 2 - autoscale { - recurrence { - timezone = "Pacific Standard Time" - schedule { - days = ["Monday"] - time = "10:00" - target_instance_count = 5 - } - schedule { - days = ["Saturday", "Sunday"] - time = "10:00" - target_instance_count = 3 - } - } - } - } - - zookeeper_node { - vm_size = "Standard_D3_V2" - username = "acctestusrvm" - password = "AccTestvdSC4daf986!" - } - } -} -`, r.template(data), data.RandomInteger) -} - func (r HDInsightHBaseClusterResource) securityProfile(data acceptance.TestData) string { return fmt.Sprintf(` %[1]s diff --git a/internal/services/hdinsight/hdinsight_interactive_query_cluster_resource.go b/internal/services/hdinsight/hdinsight_interactive_query_cluster_resource.go index db2ac3331351..1b898494a08a 100644 --- a/internal/services/hdinsight/hdinsight_interactive_query_cluster_resource.go +++ b/internal/services/hdinsight/hdinsight_interactive_query_cluster_resource.go @@ -82,6 +82,8 @@ func resourceHDInsightInteractiveQueryCluster() *pluginsdk.Resource { Computed: true, }, + "disk_encryption": SchemaHDInsightsDiskEncryptionProperties(), + "component_version": { Type: pluginsdk.TypeList, Required: true, @@ -230,6 +232,13 @@ func resourceHDInsightInteractiveQueryClusterCreate(d *pluginsdk.ResourceData, m Identity: identity, } + if diskEncryptionPropertiesRaw, ok := d.GetOk("disk_encryption"); ok { + params.Properties.DiskEncryptionProperties, err = ExpandHDInsightsDiskEncryptionProperties(diskEncryptionPropertiesRaw.([]interface{})) + if err != nil { + return err + } + } + if v, ok := d.GetOk("security_profile"); ok { params.Properties.SecurityProfile = ExpandHDInsightSecurityProfile(v.([]interface{})) @@ -345,6 +354,16 @@ func resourceHDInsightInteractiveQueryClusterRead(d *pluginsdk.ResourceData, met d.Set("encryption_in_transit_enabled", props.EncryptionInTransitProperties.IsEncryptionInTransitEnabled) } + if props.DiskEncryptionProperties != nil { + diskEncryptionProps, err := FlattenHDInsightsDiskEncryptionProperties(*props.DiskEncryptionProperties) + if err != nil { + return err + } + if err := d.Set("disk_encryption", diskEncryptionProps); err != nil { + return fmt.Errorf("flattening `disk_encryption`: %+v", err) + } + } + if props.NetworkProperties != nil { if err := d.Set("network", FlattenHDInsightsNetwork(props.NetworkProperties)); err != nil { return fmt.Errorf("flattening `network`: %+v", err) diff --git a/internal/services/hdinsight/hdinsight_interactive_query_cluster_resource_test.go b/internal/services/hdinsight/hdinsight_interactive_query_cluster_resource_test.go index fac046e93a32..93b627ab021a 100644 --- a/internal/services/hdinsight/hdinsight_interactive_query_cluster_resource_test.go +++ b/internal/services/hdinsight/hdinsight_interactive_query_cluster_resource_test.go @@ -244,6 +244,26 @@ func TestAccHDInsightInteractiveQueryCluster_encryption_in_transit(t *testing.T) }) } +func TestAccHDInsightInteractiveQueryCluster_diskEncryption(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_hdinsight_interactive_query_cluster", "test") + r := HDInsightInteractiveQueryClusterResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.diskEncryption(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("roles.0.head_node.0.password", + "roles.0.head_node.0.vm_size", + "roles.0.worker_node.0.password", + "roles.0.worker_node.0.vm_size", + "roles.0.zookeeper_node.0.password", + "roles.0.zookeeper_node.0.vm_size", + "storage_account"), + }) +} + func TestAccHDInsightInteractiveQueryCluster_allMetastores(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_hdinsight_interactive_query_cluster", "test") r := HDInsightInteractiveQueryClusterResource{} @@ -1452,6 +1472,61 @@ resource "azurerm_hdinsight_interactive_query_cluster" "test" { `, r.template(data), data.RandomInteger) } +func (r HDInsightInteractiveQueryClusterResource) diskEncryption(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_hdinsight_interactive_query_cluster" "test" { + name = "acctesthdi-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + cluster_version = "4.0" + tier = "Standard" + tls_min_version = "1.2" + + component_version { + interactive_hive = "3.1" + } + + disk_encryption { + encryption_at_host_enabled = true + } + + gateway { + username = "acctestusrgw" + password = "TerrAform123!" + } + + storage_account { + storage_container_id = azurerm_storage_container.test.id + storage_account_key = azurerm_storage_account.test.primary_access_key + is_default = true + } + + roles { + head_node { + vm_size = "Standard_D8a_V4" + username = "acctestusrvm" + password = "AccTestvdSC4daf986!" + } + + worker_node { + vm_size = "Standard_D16a_V4" + username = "acctestusrvm" + password = "AccTestvdSC4daf986!" + target_instance_count = 2 + } + + zookeeper_node { + vm_size = "Standard_DS2_V2" + username = "acctestusrvm" + password = "AccTestvdSC4daf986!" + } + } +} +`, r.template(data), data.RandomInteger) +} + func (r HDInsightInteractiveQueryClusterResource) allMetastores(data acceptance.TestData) string { return fmt.Sprintf(` %s diff --git a/internal/services/hdinsight/hdinsight_kafka_cluster_resource.go b/internal/services/hdinsight/hdinsight_kafka_cluster_resource.go index 5d2e867f0980..6c495508aa51 100644 --- a/internal/services/hdinsight/hdinsight_kafka_cluster_resource.go +++ b/internal/services/hdinsight/hdinsight_kafka_cluster_resource.go @@ -115,6 +115,8 @@ func resourceHDInsightKafkaCluster() *pluginsdk.Resource { Optional: true, }, + "disk_encryption": SchemaHDInsightsDiskEncryptionProperties(), + "roles": { Type: pluginsdk.TypeList, Required: true, @@ -273,6 +275,13 @@ func resourceHDInsightKafkaClusterCreate(d *pluginsdk.ResourceData, meta interfa } } + if diskEncryptionPropertiesRaw, ok := d.GetOk("disk_encryption"); ok { + params.Properties.DiskEncryptionProperties, err = ExpandHDInsightsDiskEncryptionProperties(diskEncryptionPropertiesRaw.([]interface{})) + if err != nil { + return err + } + } + if v, ok := d.GetOk("security_profile"); ok { params.Properties.SecurityProfile = ExpandHDInsightSecurityProfile(v.([]interface{})) @@ -413,6 +422,16 @@ func resourceHDInsightKafkaClusterRead(d *pluginsdk.ResourceData, meta interface } } + if props.DiskEncryptionProperties != nil { + diskEncryptionProps, err := FlattenHDInsightsDiskEncryptionProperties(*props.DiskEncryptionProperties) + if err != nil { + return err + } + if err := d.Set("disk_encryption", diskEncryptionProps); err != nil { + return fmt.Errorf("flattening `disk_encryption`: %+v", err) + } + } + monitor, err := extensionsClient.GetMonitoringStatus(ctx, resourceGroup, name) if err != nil { return fmt.Errorf("failed reading monitor configuration for HDInsight Hadoop Cluster %q (Resource Group %q): %+v", name, resourceGroup, err) diff --git a/internal/services/hdinsight/hdinsight_kafka_cluster_resource_test.go b/internal/services/hdinsight/hdinsight_kafka_cluster_resource_test.go index ce732de4c606..f173e48d9491 100644 --- a/internal/services/hdinsight/hdinsight_kafka_cluster_resource_test.go +++ b/internal/services/hdinsight/hdinsight_kafka_cluster_resource_test.go @@ -406,6 +406,28 @@ func TestAccHDInsightKafkaCluster_restProxy(t *testing.T) { }) } +func TestAccHDInsightKafkaCluster_diskEncryption(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_hdinsight_kafka_cluster", "test") + r := HDInsightKafkaClusterResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.diskEncryption(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("roles.0.head_node.0.password", + "roles.0.head_node.0.vm_size", + "roles.0.worker_node.0.password", + "roles.0.worker_node.0.vm_size", + "roles.0.zookeeper_node.0.password", + "roles.0.zookeeper_node.0.vm_size", + "roles.0.kafka_management_node.0.password", + "roles.0.kafka_management_node.0.vm_size", + "storage_account"), + }) +} + func TestAccHDInsightKafkaCluster_encryptionInTransitEnabled(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_hdinsight_kafka_cluster", "test") r := HDInsightKafkaClusterResource{} @@ -1344,6 +1366,61 @@ resource "azurerm_hdinsight_kafka_cluster" "test" { `, r.template(data), data.RandomInteger, data.RandomInteger) } +func (r HDInsightKafkaClusterResource) diskEncryption(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_hdinsight_kafka_cluster" "test" { + name = "acctesthdi-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + cluster_version = "4.0" + tier = "Standard" + + component_version { + kafka = "2.1" + } + + gateway { + username = "acctestusrgw" + password = "TerrAform123!" + } + + storage_account { + storage_container_id = azurerm_storage_container.test.id + storage_account_key = azurerm_storage_account.test.primary_access_key + is_default = true + } + + disk_encryption { + encryption_at_host_enabled = true + } + + roles { + head_node { + vm_size = "Standard_D4a_V4" + username = "acctestusrvm" + password = "AccTestvdSC4daf986!" + } + + worker_node { + vm_size = "Standard_D4a_V4" + username = "acctestusrvm" + password = "AccTestvdSC4daf986!" + target_instance_count = 3 + number_of_disks_per_node = 2 + } + + zookeeper_node { + vm_size = "Standard_DS2_V2" + username = "acctestusrvm" + password = "AccTestvdSC4daf986!" + } + } +} +`, r.template(data), data.RandomInteger) +} + func (r HDInsightKafkaClusterResource) encryptionInTransitEnabled(data acceptance.TestData) string { return fmt.Sprintf(` %s diff --git a/internal/services/hdinsight/hdinsight_spark_cluster_resource.go b/internal/services/hdinsight/hdinsight_spark_cluster_resource.go index a50f1dda8817..02bc3422b036 100644 --- a/internal/services/hdinsight/hdinsight_spark_cluster_resource.go +++ b/internal/services/hdinsight/hdinsight_spark_cluster_resource.go @@ -82,6 +82,8 @@ func resourceHDInsightSparkCluster() *pluginsdk.Resource { Computed: true, }, + "disk_encryption": SchemaHDInsightsDiskEncryptionProperties(), + "component_version": { Type: pluginsdk.TypeList, Required: true, @@ -230,6 +232,13 @@ func resourceHDInsightSparkClusterCreate(d *pluginsdk.ResourceData, meta interfa Identity: identity, } + if diskEncryptionPropertiesRaw, ok := d.GetOk("disk_encryption"); ok { + params.Properties.DiskEncryptionProperties, err = ExpandHDInsightsDiskEncryptionProperties(diskEncryptionPropertiesRaw.([]interface{})) + if err != nil { + return err + } + } + if v, ok := d.GetOk("security_profile"); ok { params.Properties.SecurityProfile = ExpandHDInsightSecurityProfile(v.([]interface{})) @@ -352,6 +361,16 @@ func resourceHDInsightSparkClusterRead(d *pluginsdk.ResourceData, meta interface d.Set("encryption_in_transit_enabled", props.EncryptionInTransitProperties.IsEncryptionInTransitEnabled) } + if props.DiskEncryptionProperties != nil { + diskEncryptionProps, err := FlattenHDInsightsDiskEncryptionProperties(*props.DiskEncryptionProperties) + if err != nil { + return err + } + if err := d.Set("disk_encryption", diskEncryptionProps); err != nil { + return fmt.Errorf("flattening setting `disk_encryption`: %+v", err) + } + } + if props.NetworkProperties != nil { if err := d.Set("network", FlattenHDInsightsNetwork(props.NetworkProperties)); err != nil { return fmt.Errorf("flattening `network`: %+v", err) diff --git a/internal/services/hdinsight/hdinsight_spark_cluster_resource_test.go b/internal/services/hdinsight/hdinsight_spark_cluster_resource_test.go index 3b62179eaa99..60defb4af05b 100644 --- a/internal/services/hdinsight/hdinsight_spark_cluster_resource_test.go +++ b/internal/services/hdinsight/hdinsight_spark_cluster_resource_test.go @@ -244,6 +244,26 @@ func TestAccHDInsightSparkCluster_encryption_in_transit(t *testing.T) { }) } +func TestAccHDInsightSparkCluster_diskEncryption(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_hdinsight_spark_cluster", "test") + r := HDInsightSparkClusterResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.diskEncryption(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("roles.0.head_node.0.password", + "roles.0.head_node.0.vm_size", + "roles.0.worker_node.0.password", + "roles.0.worker_node.0.vm_size", + "roles.0.zookeeper_node.0.password", + "roles.0.zookeeper_node.0.vm_size", + "storage_account"), + }) +} + func TestAccHDInsightSparkCluster_allMetastores(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_hdinsight_spark_cluster", "test") r := HDInsightSparkClusterResource{} @@ -423,12 +443,12 @@ func TestAccHDInsightSparkCluster_updateMonitor(t *testing.T) { }) } -func TestAccAzureRMHDInsightSparkCluster_autoscale(t *testing.T) { +func TestAccAzureRMHDInsightSparkCluster_autoscaleWithSchedule(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_hdinsight_spark_cluster", "test") r := HDInsightSparkClusterResource{} data.ResourceTest(t, r, []acceptance.TestStep{ { - Config: r.autoscale_capacity(data), + Config: r.autoscale_schedule(data), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), check.That(data.ResourceName).Key("https_endpoint").Exists(), @@ -443,7 +463,29 @@ func TestAccAzureRMHDInsightSparkCluster_autoscale(t *testing.T) { "roles.0.zookeeper_node.0.vm_size", "storage_account"), { - Config: r.autoscale_schedule(data), + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("https_endpoint").Exists(), + check.That(data.ResourceName).Key("ssh_endpoint").Exists(), + ), + }, + data.ImportStep("roles.0.head_node.0.password", + "roles.0.head_node.0.vm_size", + "roles.0.worker_node.0.password", + "roles.0.worker_node.0.vm_size", + "roles.0.zookeeper_node.0.password", + "roles.0.zookeeper_node.0.vm_size", + "storage_account"), + }) +} + +func TestAccAzureRMHDInsightSparkCluster_autoscaleWithCapacity(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_hdinsight_spark_cluster", "test") + r := HDInsightSparkClusterResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.autoscale_capacity(data), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), check.That(data.ResourceName).Key("https_endpoint").Exists(), @@ -1452,6 +1494,63 @@ resource "azurerm_hdinsight_spark_cluster" "test" { `, r.template(data), data.RandomInteger) } +func (r HDInsightSparkClusterResource) diskEncryption(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_hdinsight_spark_cluster" "test" { + name = "acctesthdi-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + cluster_version = "4.0" + tier = "Standard" + tls_min_version = "1.2" + + + component_version { + spark = "2.4" + } + + gateway { + username = "acctestusrgw" + password = "TerrAform123!" + } + + storage_account { + storage_container_id = azurerm_storage_container.test.id + storage_account_key = azurerm_storage_account.test.primary_access_key + is_default = true + } + + disk_encryption { + encryption_at_host_enabled = true + } + + roles { + head_node { + vm_size = "Standard_D4a_V4" + username = "acctestusrvm" + password = "AccTestvdSC4daf986!" + } + + worker_node { + vm_size = "Standard_D4a_V4" + username = "acctestusrvm" + password = "AccTestvdSC4daf986!" + target_instance_count = 3 + } + + zookeeper_node { + vm_size = "Standard_DS2_V2" + username = "acctestusrvm" + password = "AccTestvdSC4daf986!" + } + } +} +`, r.template(data), data.RandomInteger) + +} + func (r HDInsightSparkClusterResource) allMetastores(data acceptance.TestData) string { return fmt.Sprintf(` %s diff --git a/internal/services/hdinsight/schema.go b/internal/services/hdinsight/schema.go index 755b0c9d4823..1058e0c2d6e0 100644 --- a/internal/services/hdinsight/schema.go +++ b/internal/services/hdinsight/schema.go @@ -9,7 +9,10 @@ import ( "github.com/Azure/azure-sdk-for-go/services/hdinsight/mgmt/2018-06-01/hdinsight" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" + azValidate "github.com/hashicorp/terraform-provider-azurerm/helpers/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/services/hdinsight/validate" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/keyvault/parse" + keyVault "github.com/hashicorp/terraform-provider-azurerm/internal/services/keyvault/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/utils" @@ -289,6 +292,86 @@ func SchemaHDInsightsSecurityProfile() *pluginsdk.Schema { } } +func SchemaHDInsightsScriptActions() *pluginsdk.Schema { + return &pluginsdk.Schema{ + Type: pluginsdk.TypeList, + Optional: true, + ForceNew: true, + MinItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "uri": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.IsURLWithHTTPorHTTPS, + }, + + "parameters": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, + }, + } +} + +func SchemaHDInsightsHttpsEndpoints() *pluginsdk.Schema { + return &pluginsdk.Schema{ + Type: pluginsdk.TypeList, + Optional: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "access_modes": { + Type: pluginsdk.TypeList, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, + + "destination_port": { + Type: pluginsdk.TypeInt, + Optional: true, + ValidateFunc: azValidate.PortNumber, + }, + + "disable_gateway_auth": { + Type: pluginsdk.TypeBool, + Optional: true, + }, + + "private_ip_address": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.IsIPAddress, + }, + + "sub_domain_suffix": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, + }, + } +} + +type HttpEndpointModel struct { + AccessModes []string `tfschema:"access_modes"` + DestinationPort int32 `tfschema:"destination_port"` + DisableGatewayAuth bool `tfschema:"disable_gateway_auth"` + PrivateIpAddress string `tfschema:"private_ip_address"` + SubDomainSuffix string `tfschema:"sub_domain_suffix"` +} + func ExpandHDInsightsConfigurations(input []interface{}) map[string]interface{} { vs := input[0].(map[string]interface{}) @@ -642,6 +725,107 @@ func SchemaHDInsightsGen2StorageAccounts() *pluginsdk.Schema { } } +func SchemaHDInsightsDiskEncryptionProperties() *pluginsdk.Schema { + return &pluginsdk.Schema{ + Type: pluginsdk.TypeList, + Optional: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "encryption_algorithm": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + string(hdinsight.JSONWebKeyEncryptionAlgorithmRSA15), + string(hdinsight.JSONWebKeyEncryptionAlgorithmRSAOAEP), + string(hdinsight.JSONWebKeyEncryptionAlgorithmRSAOAEP256), + }, false), + }, + + "encryption_at_host_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + }, + + "key_vault_managed_identity_id": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: commonids.ValidateUserAssignedIdentityID, + }, + + "key_vault_key_id": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: keyVault.NestedItemId, + }, + }, + }, + } +} + +func ExpandHDInsightsDiskEncryptionProperties(input []interface{}) (*hdinsight.DiskEncryptionProperties, error) { + v := input[0].(map[string]interface{}) + + encryptionAlgorithm := v["encryption_algorithm"].(string) + encryptionAtHost := v["encryption_at_host_enabled"].(bool) + keyVaultManagedIdentityId := v["key_vault_managed_identity_id"].(string) + + diskEncryptionProps := &hdinsight.DiskEncryptionProperties{ + EncryptionAlgorithm: hdinsight.JSONWebKeyEncryptionAlgorithm(encryptionAlgorithm), + EncryptionAtHost: &encryptionAtHost, + MsiResourceID: &keyVaultManagedIdentityId, + } + + if id, ok := v["key_vault_key_id"]; ok && id.(string) != "" { + keyVaultKeyId, err := parse.ParseNestedItemID(id.(string)) + if err != nil { + return nil, err + } + diskEncryptionProps.KeyName = &keyVaultKeyId.Name + diskEncryptionProps.KeyVersion = &keyVaultKeyId.Version + diskEncryptionProps.VaultURI = &keyVaultKeyId.KeyVaultBaseUrl + } + + return diskEncryptionProps, nil +} + +func FlattenHDInsightsDiskEncryptionProperties(input hdinsight.DiskEncryptionProperties) ([]interface{}, error) { + var encryptionAlgorithm string + var encryptionAtHost bool + var keyName string + var keyVersion string + var msiResourceId string + var keyVaultKeyId string + + if input.EncryptionAtHost != nil { + encryptionAtHost = *input.EncryptionAtHost + } + encryptionAlgorithm = string(input.EncryptionAlgorithm) + if input.KeyName != nil { + keyName = *input.KeyName + } + if input.KeyVersion != nil { + keyVersion = *input.KeyVersion + } + msiResourceId = *input.MsiResourceID + + if keyName != "" || keyVersion != "" { + keyVaultKeyIdRaw, err := parse.NewNestedItemID(*input.VaultURI, "keys", keyName, keyVersion) + if err != nil { + return nil, err + } + keyVaultKeyId = keyVaultKeyIdRaw.ID() + } + + return []interface{}{ + map[string]interface{}{ + "encryption_algorithm": encryptionAlgorithm, + "encryption_at_host_enabled": encryptionAtHost, + "key_vault_key_id": keyVaultKeyId, + "key_vault_managed_identity_id": msiResourceId, + }, + }, nil +} + // ExpandHDInsightsStorageAccounts returns an array of StorageAccount structs, as well as a ClusterIdentity // populated with any managed identities required for accessing Data Lake Gen2 storage. func ExpandHDInsightsStorageAccounts(storageAccounts []interface{}, gen2storageAccounts []interface{}) (*[]hdinsight.StorageAccount, *hdinsight.ClusterIdentity, error) { diff --git a/internal/services/healthcare/client/client.go b/internal/services/healthcare/client/client.go index ac266932cd86..f699d48e44b1 100644 --- a/internal/services/healthcare/client/client.go +++ b/internal/services/healthcare/client/client.go @@ -6,10 +6,12 @@ import ( ) type Client struct { - HealthcareServiceClient *healthcareapis.ServicesClient - HealthcareWorkspaceClient *healthcareapis.WorkspacesClient - HealthcareWorkspaceDicomServiceClient *healthcareapis.DicomServicesClient - HealthcareWorkspaceFhirServiceClient *healthcareapis.FhirServicesClient + HealthcareServiceClient *healthcareapis.ServicesClient + HealthcareWorkspaceClient *healthcareapis.WorkspacesClient + HealthcareWorkspaceDicomServiceClient *healthcareapis.DicomServicesClient + HealthcareWorkspaceFhirServiceClient *healthcareapis.FhirServicesClient + HealthcareWorkspaceMedTechServiceClient *healthcareapis.IotConnectorsClient + HealthcareWorkspaceMedTechServiceFhirDestinationClient *healthcareapis.IotConnectorFhirDestinationClient } func NewClient(o *common.ClientOptions) *Client { @@ -25,10 +27,18 @@ func NewClient(o *common.ClientOptions) *Client { HealthcareWorkspaceFhirServiceClient := healthcareapis.NewFhirServicesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&HealthcareWorkspaceFhirServiceClient.Client, o.ResourceManagerAuthorizer) + HealthcareWorkspaceMedTechServiceClient := healthcareapis.NewIotConnectorsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&HealthcareWorkspaceMedTechServiceClient.Client, o.ResourceManagerAuthorizer) + + HealthcareWorkspaceMedTechServiceFhirDestinationClient := healthcareapis.NewIotConnectorFhirDestinationClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&HealthcareWorkspaceMedTechServiceFhirDestinationClient.Client, o.ResourceManagerAuthorizer) + return &Client{ - HealthcareServiceClient: &HealthcareServiceClient, - HealthcareWorkspaceClient: &HealthcareWorkspaceClient, - HealthcareWorkspaceDicomServiceClient: &HealthcareWorkspaceDicomServiceClient, - HealthcareWorkspaceFhirServiceClient: &HealthcareWorkspaceFhirServiceClient, + HealthcareServiceClient: &HealthcareServiceClient, + HealthcareWorkspaceClient: &HealthcareWorkspaceClient, + HealthcareWorkspaceDicomServiceClient: &HealthcareWorkspaceDicomServiceClient, + HealthcareWorkspaceFhirServiceClient: &HealthcareWorkspaceFhirServiceClient, + HealthcareWorkspaceMedTechServiceClient: &HealthcareWorkspaceMedTechServiceClient, + HealthcareWorkspaceMedTechServiceFhirDestinationClient: &HealthcareWorkspaceMedTechServiceFhirDestinationClient, } } diff --git a/internal/services/healthcare/healthcare_medtech_service_data_source.go b/internal/services/healthcare/healthcare_medtech_service_data_source.go new file mode 100644 index 000000000000..70409f6e36f7 --- /dev/null +++ b/internal/services/healthcare/healthcare_medtech_service_data_source.go @@ -0,0 +1,130 @@ +package healthcare + +import ( + "encoding/json" + "fmt" + "strings" + "time" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/healthcare/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/healthcare/validate" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +func dataSourceHealthcareIotConnector() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Read: dataSourceHealthcareIotConnectorRead, + + Timeouts: &pluginsdk.ResourceTimeout{ + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validate.MedTechServiceName(), + }, + + "workspace_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.WorkspaceID, + }, + + "identity": commonschema.SystemAssignedIdentityComputed(), + + "eventhub_namespace_name": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "eventhub_name": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "eventhub_consumer_group_name": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "device_mapping_json": { + Type: pluginsdk.TypeString, + Computed: true, + }, + }, + } +} + +func dataSourceHealthcareIotConnectorRead(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).HealthCare.HealthcareWorkspaceMedTechServiceClient + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + workspaceId, err := parse.WorkspaceID(d.Get("workspace_id").(string)) + if err != nil { + return fmt.Errorf("parsing workspace id error: %+v", err) + } + + id := parse.NewMedTechServiceID(subscriptionId, workspaceId.ResourceGroup, workspaceId.Name, d.Get("name").(string)) + + resp, err := client.Get(ctx, id.ResourceGroup, id.WorkspaceName, id.IotconnectorName) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + d.SetId("") + return nil + } + return fmt.Errorf("retrieving %s: %+v", id, err) + } + + d.SetId(id.ID()) + d.Set("name", id.IotconnectorName) + + d.Set("workspace_id", workspaceId.ID()) + + if err := d.Set("identity", flattenMedTechServiceIdentity(resp.Identity)); err != nil { + return fmt.Errorf("setting `identity`: %+v", err) + } + if props := resp.IotConnectorProperties; props != nil { + if props.IngestionEndpointConfiguration.EventHubName != nil { + d.Set("eventhub_name", props.IngestionEndpointConfiguration.EventHubName) + } + + if props.IngestionEndpointConfiguration.ConsumerGroup != nil { + d.Set("eventhub_consumer_group_name", props.IngestionEndpointConfiguration.ConsumerGroup) + } + + if props.DeviceMapping != nil { + deviceMapData, err := json.Marshal(props.DeviceMapping) + if err != nil { + return err + } + + var m map[string]*json.RawMessage + if err = json.Unmarshal(deviceMapData, &m); err != nil { + return err + } + mapContent := "" + if v, ok := m["content"]; ok { + contents, err := json.Marshal(v) + if err != nil { + return err + } + mapContent = string(contents) + } + d.Set("device_mapping_json", mapContent) + } + + if props.IngestionEndpointConfiguration.FullyQualifiedEventHubNamespace != nil { + d.Set("eventhub_namespace_name", strings.TrimSuffix(*props.IngestionEndpointConfiguration.FullyQualifiedEventHubNamespace, ".servicebus.windows.net")) + } + } + return nil +} diff --git a/internal/services/healthcare/healthcare_medtech_service_data_source_test.go b/internal/services/healthcare/healthcare_medtech_service_data_source_test.go new file mode 100644 index 000000000000..4533b90d28da --- /dev/null +++ b/internal/services/healthcare/healthcare_medtech_service_data_source_test.go @@ -0,0 +1,35 @@ +package healthcare_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" +) + +type HealthCareWorkspaceIotConnectorDataSource struct{} + +func TestAccHealthCareWorkspaceIotConnectorDataSource_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_healthcare_medtech_service", "test") + r := HealthCareWorkspaceIotConnectorDataSource{} + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("name").Exists()), + }, + }) +} + +func (HealthCareWorkspaceIotConnectorDataSource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +data "azurerm_healthcare_medtech_service" "test" { + name = azurerm_healthcare_medtech_service.test.name + workspace_id = azurerm_healthcare_workspace.test.id +} +`, HealthCareWorkspaceMedTechServiceResource{}.basic(data)) +} diff --git a/internal/services/healthcare/healthcare_medtech_service_fhir_destination_resource.go b/internal/services/healthcare/healthcare_medtech_service_fhir_destination_resource.go new file mode 100644 index 000000000000..24ea1139ce50 --- /dev/null +++ b/internal/services/healthcare/healthcare_medtech_service_fhir_destination_resource.go @@ -0,0 +1,292 @@ +package healthcare + +import ( + "context" + "encoding/json" + "fmt" + "log" + "time" + + "github.com/Azure/azure-sdk-for-go/services/healthcareapis/mgmt/2021-11-01/healthcareapis" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" + "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/healthcare/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/healthcare/validate" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +func resourceHealthcareApisMedTechServiceFhirDestination() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Create: resourceHealthcareApisMedTechServiceFhirDestinationCreate, + Read: resourceHealthcareApisMedTechServiceFhirDestinationRead, + Update: resourceHealthcareApisMedTechServiceFhirDestinationUpdate, + Delete: resourceHealthcareApisMedTechServiceFhirDestinationDelete, + + Timeouts: &pluginsdk.ResourceTimeout{ + Create: pluginsdk.DefaultTimeout(90 * time.Minute), + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + Update: pluginsdk.DefaultTimeout(90 * time.Minute), + Delete: pluginsdk.DefaultTimeout(90 * time.Minute), + }, + + Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { + _, err := parse.MedTechServiceFhirDestinationID(id) + return err + }), + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.MedTechServiceName(), + }, + + "medtech_service_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.MedTechServiceID, + }, + + "location": commonschema.Location(), + + "destination_fhir_service_id": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validate.FhirServiceID, + }, + + "destination_identity_resolution_type": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(healthcareapis.IotIdentityResolutionTypeCreate), + string(healthcareapis.IotIdentityResolutionTypeLookup), + }, false), + }, + + "destination_fhir_mapping_json": { + Type: pluginsdk.TypeString, + Required: true, + StateFunc: utils.NormalizeJson, + DiffSuppressFunc: suppressJsonOrderingDifference, + }, + }, + } +} + +func resourceHealthcareApisMedTechServiceFhirDestinationCreate(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).HealthCare.HealthcareWorkspaceMedTechServiceFhirDestinationClient + ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + log.Printf("[INFO] preparing arguments for AzureRM Healthcare Med Tech Service Fhir Destination creation.") + + medTechService, err := parse.MedTechServiceID(d.Get("medtech_service_id").(string)) + if err != nil { + return fmt.Errorf("parsing Med Tech Service error: %+v", err) + } + id := parse.NewMedTechServiceFhirDestinationID(medTechService.SubscriptionId, medTechService.ResourceGroup, medTechService.WorkspaceName, medTechService.IotconnectorName, d.Get("name").(string)) + + if d.IsNewResource() { + existing, err := client.Get(ctx, id.ResourceGroup, id.WorkspaceName, id.IotconnectorName, id.FhirdestinationName) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("checking for presence of existing %s: %+v", id, err) + } + } + if !utils.ResponseWasNotFound(existing.Response) { + return tf.ImportAsExistsError("azurerm_healthcare_medtech_service_fhir_destination", id.ID()) + } + } + + fhirServiceId, err := parse.FhirServiceID(d.Get("destination_fhir_service_id").(string)) + if err != nil { + return fmt.Errorf("parsing fhir destination id err: %+v", err) + } + + iotFhirServiceParameters := healthcareapis.IotFhirDestination{ + Location: utils.String(azure.NormalizeLocation(d.Get("location").(string))), + IotFhirDestinationProperties: &healthcareapis.IotFhirDestinationProperties{ + FhirServiceResourceID: utils.String(fhirServiceId.ID()), + ResourceIdentityResolutionType: healthcareapis.IotIdentityResolutionType(d.Get("destination_identity_resolution_type").(string)), + }, + } + + fhirMap := healthcareapis.IotMappingProperties{} + fhirMappingJson := fmt.Sprintf(`{ "content": %s }`, d.Get("destination_fhir_mapping_json").(string)) + if err := json.Unmarshal([]byte(fhirMappingJson), &fhirMap); err != nil { + return err + } + iotFhirServiceParameters.IotFhirDestinationProperties.FhirMapping = &fhirMap + + medTechServiceDesFuture, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.WorkspaceName, id.IotconnectorName, id.FhirdestinationName, iotFhirServiceParameters) + if err != nil { + return fmt.Errorf("updating fhir service %s for the Med Tech Service err: %+v", id, err) + } + if err = medTechServiceDesFuture.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for creation/update of %s: %+v", id, err) + } + + d.SetId(id.ID()) + + return resourceHealthcareApisMedTechServiceFhirDestinationRead(d, meta) +} + +func resourceHealthcareApisMedTechServiceFhirDestinationRead(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).HealthCare.HealthcareWorkspaceMedTechServiceFhirDestinationClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.MedTechServiceFhirDestinationID(d.Id()) + if err != nil { + return err + } + + medTechServiceId := parse.NewMedTechServiceID(id.SubscriptionId, id.ResourceGroup, id.WorkspaceName, id.IotconnectorName) + d.Set("medtech_service_id", medTechServiceId.ID()) + + resp, err := client.Get(ctx, id.ResourceGroup, id.WorkspaceName, id.IotconnectorName, id.FhirdestinationName) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[WARN] Healthcare Apis Med Tech Service Fhir Destination %s was not found", id) + d.SetId("") + return nil + } + return fmt.Errorf("retrieving %s: %+v", *id, err) + } + + d.Set("name", id.FhirdestinationName) + + if resp.Location != nil { + d.Set("location", location.NormalizeNilable(resp.Location)) + } + + if props := resp.IotFhirDestinationProperties; props != nil { + if props.FhirServiceResourceID != nil { + d.Set("destination_fhir_service_id", props.FhirServiceResourceID) + } + + if props.FhirMapping.Content != nil { + fhirMapData, err := json.Marshal(props.FhirMapping) + if err != nil { + return err + } + + var m map[string]*json.RawMessage + if err = json.Unmarshal(fhirMapData, &m); err != nil { + return err + } + mapContent := "" + if v, ok := m["content"]; ok { + contents, err := json.Marshal(v) + if err != nil { + return err + } + mapContent = string(contents) + } + d.Set("destination_fhir_mapping_json", mapContent) + } + d.Set("destination_identity_resolution_type", props.ResourceIdentityResolutionType) + } + return nil +} + +func resourceHealthcareApisMedTechServiceFhirDestinationUpdate(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).HealthCare.HealthcareWorkspaceMedTechServiceFhirDestinationClient + ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + + medTechService, err := parse.MedTechServiceID(d.Get("medtech_service_id").(string)) + if err != nil { + return fmt.Errorf("parsing Med Tech Service error: %+v", err) + } + id := parse.NewMedTechServiceFhirDestinationID(medTechService.SubscriptionId, medTechService.ResourceGroup, medTechService.WorkspaceName, medTechService.IotconnectorName, d.Get("name").(string)) + + fhirServiceId, err := parse.FhirServiceID(d.Get("destination_fhir_service_id").(string)) + if err != nil { + return fmt.Errorf("parsing fhir destination id err: %+v", err) + } + + medTechFhirServiceParameters := healthcareapis.IotFhirDestination{ + Location: utils.String(azure.NormalizeLocation(d.Get("location").(string))), + IotFhirDestinationProperties: &healthcareapis.IotFhirDestinationProperties{ + FhirServiceResourceID: utils.String(fhirServiceId.ID()), + ResourceIdentityResolutionType: healthcareapis.IotIdentityResolutionType(d.Get("destination_identity_resolution_type").(string)), + }, + } + + fhirMap := healthcareapis.IotMappingProperties{} + fhirMappingJson := fmt.Sprintf(`{ "content": %s }`, d.Get("destination_fhir_mapping_json").(string)) + if err := json.Unmarshal([]byte(fhirMappingJson), &fhirMap); err != nil { + return err + } + medTechFhirServiceParameters.IotFhirDestinationProperties.FhirMapping = &fhirMap + + medTechServiceDesFuture, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.WorkspaceName, id.IotconnectorName, id.FhirdestinationName, medTechFhirServiceParameters) + if err != nil { + return fmt.Errorf("updating fhir service %s for the Med Tech Service err: %+v", id, err) + } + if err = medTechServiceDesFuture.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for update of %s: %+v", id, err) + } + + d.SetId(id.ID()) + + return resourceHealthcareApisMedTechServiceFhirDestinationRead(d, meta) +} + +func resourceHealthcareApisMedTechServiceFhirDestinationDelete(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).HealthCare.HealthcareWorkspaceMedTechServiceFhirDestinationClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.MedTechServiceFhirDestinationID(d.Id()) + if err != nil { + return err + } + + future, err := client.Delete(ctx, id.ResourceGroup, id.WorkspaceName, id.IotconnectorName, id.FhirdestinationName) + if err != nil { + if response.WasNotFound(future.Response()) { + return nil + } + return fmt.Errorf("deleting %s: %+v", *id, err) + } + log.Printf("[DEBUG] Waiting for %s to be deleted..", id) + stateConf := &pluginsdk.StateChangeConf{ + Pending: []string{"Pending"}, + Target: []string{"Deleted"}, + Refresh: healthcareApiMedTechServiceFhirDestinationStateCodeRefreshFunc(ctx, client, *id), + Timeout: d.Timeout(pluginsdk.TimeoutDelete), + ContinuousTargetOccurence: 3, + PollInterval: 10 * time.Second, + } + + if _, err := stateConf.WaitForStateContext(ctx); err != nil { + return fmt.Errorf("waiting for %s to be deleted: %+v", id, err) + } + return nil +} + +func healthcareApiMedTechServiceFhirDestinationStateCodeRefreshFunc(ctx context.Context, client *healthcareapis.IotConnectorFhirDestinationClient, id parse.MedTechServiceFhirDestinationId) pluginsdk.StateRefreshFunc { + return func() (interface{}, string, error) { + res, err := client.Get(ctx, id.ResourceGroup, id.WorkspaceName, id.IotconnectorName, id.FhirdestinationName) + + if err != nil { + if utils.ResponseWasNotFound(res.Response) { + return res, "Deleted", nil + } + return nil, "Error", fmt.Errorf("polling for the status of %s: %+v", id, err) + } + + return res, "Pending", nil + } +} diff --git a/internal/services/healthcare/healthcare_medtech_service_fhir_destination_resource_test.go b/internal/services/healthcare/healthcare_medtech_service_fhir_destination_resource_test.go new file mode 100644 index 000000000000..56c2f86b5c94 --- /dev/null +++ b/internal/services/healthcare/healthcare_medtech_service_fhir_destination_resource_test.go @@ -0,0 +1,233 @@ +package healthcare_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/healthcare/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type HealthCareMedTechServiceFhirDestinationResource struct{} + +func TestAccHealthCareMedTechServiceFhirDestination_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_healthcare_medtech_service_fhir_destination", "test") + r := HealthCareMedTechServiceFhirDestinationResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r)), + }, + data.ImportStep(), + }) +} + +func TestAccHealthCareMedTechServiceFhirDestination_updateTemplate(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_healthcare_medtech_service_fhir_destination", "test") + r := HealthCareMedTechServiceFhirDestinationResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r)), + }, + data.ImportStep(), + { + Config: r.updateTemplate(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r)), + }, + data.ImportStep(), + }) +} + +func TestAccHealthCareMedTechServiceFhirDestination_updateFhir(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_healthcare_medtech_service_fhir_destination", "test") + r := HealthCareMedTechServiceFhirDestinationResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r)), + }, + data.ImportStep(), + { + Config: r.updateFhirId(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r)), + }, + data.ImportStep(), + }) +} + +func TestAccHealthCareMedTechServiceFhirDestination_updateResolutionType(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_healthcare_medtech_service_fhir_destination", "test") + r := HealthCareMedTechServiceFhirDestinationResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r)), + }, + data.ImportStep(), + { + Config: r.updateResolutionType(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r)), + }, + data.ImportStep(), + }) +} + +func (r HealthCareMedTechServiceFhirDestinationResource) Exists(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + id, err := parse.MedTechServiceFhirDestinationID(state.ID) + if err != nil { + return nil, err + } + resp, err := client.HealthCare.HealthcareWorkspaceMedTechServiceFhirDestinationClient.Get(ctx, id.ResourceGroup, id.WorkspaceName, id.IotconnectorName, id.FhirdestinationName) + if err != nil { + return nil, fmt.Errorf("retrieving %s, %+v", *id, err) + } + return utils.Bool(resp.IotFhirDestinationProperties != nil), nil +} + +func (r HealthCareMedTechServiceFhirDestinationResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_healthcare_medtech_service_fhir_destination" "test" { + name = "des%d" + location = azurerm_resource_group.test.location + medtech_service_id = azurerm_healthcare_medtech_service.test.id + destination_fhir_service_id = azurerm_healthcare_fhir_service.test.id + destination_identity_resolution_type = "Create" + + destination_fhir_mapping_json = <= ago(newExceptionsTimeRange) + | extend stack = tostring(details[0].rawStack) + | summarize count(), dcount(user_AuthenticatedId), min(timestamp), max(timestamp), any(stack) by problemId + ) on problemId + | order by count_ desc + BODY +} +`, r.template(data), data.RandomInteger) +} + +func (r LogAnalyticsQueryPackQueryResource) complete(data acceptance.TestData) string { + return fmt.Sprintf(` +%[1]s + +resource "azurerm_log_analytics_query_pack" "test" { + name = "acctestlaqp-%[2]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location +} + +resource "azurerm_log_analytics_query_pack_query" "test" { + name = "%[3]s" + query_pack_id = azurerm_log_analytics_query_pack.test.id + display_name = "Exceptions - New in the last 24 hours" + description = "my description" + categories = ["network"] + resource_types = ["microsoft.web/sites"] + solutions = ["LogManagement"] + + body = <= ago(newExceptionsTimeRange) + | extend stack = tostring(details[0].rawStack) + | summarize count(), dcount(user_AuthenticatedId), min(timestamp), max(timestamp), any(stack) by problemId + ) on problemId + | order by count_ desc + BODY + + additional_settings_json = <= ago(newExceptionsTimeRange) + | extend stack = tostring(details[0].rawStack) + | summarize count(), dcount(user_AuthenticatedId), min(timestamp), max(timestamp), any(stack) by problemId + ) on problemId + | order by count_ desc + BODY + + additional_settings_json = < 0 { existing := (*existingList)[0] - if existing.ID != nil && *existing.ID != "" { - return tf.ImportAsExistsError("azurerm_maintenance_assignment_dedicated_host", *existing.ID) + if existing.Id != nil && *existing.Id != "" { + return tf.ImportAsExistsError("azurerm_maintenance_assignment_dedicated_host", configurationId.ID()) } } - maintenanceConfigurationID := d.Get("maintenance_configuration_id").(string) - configurationId, _ := parse.MaintenanceConfigurationIDInsensitively(maintenanceConfigurationID) - // set assignment name to configuration name - assignmentName := configurationId.Name - configurationAssignment := maintenance.ConfigurationAssignment{ + assignmentName := configurationId.ResourceName + configurationAssignment := configurationassignments.ConfigurationAssignment{ Name: utils.String(assignmentName), Location: utils.String(location.Normalize(d.Get("location").(string))), - ConfigurationAssignmentProperties: &maintenance.ConfigurationAssignmentProperties{ - MaintenanceConfigurationID: utils.String(maintenanceConfigurationID), - ResourceID: utils.String(dedicatedHostIdRaw), + Properties: &configurationassignments.ConfigurationAssignmentProperties{ + MaintenanceConfigurationId: utils.String(configurationId.ID()), + ResourceId: utils.String(dedicatedHostId.ID()), }, } // It may take a few minutes after starting a VM for it to become available to assign to a configuration + + id := configurationassignments.NewProviders2ConfigurationAssignmentID(dedicatedHostId.SubscriptionId, dedicatedHostId.ResourceGroupName, "Microsoft.Compute", "hostGroups", dedicatedHostId.HostGroupName, "hosts", dedicatedHostId.HostName, assignmentName) err = pluginsdk.Retry(d.Timeout(pluginsdk.TimeoutCreate), func() *pluginsdk.RetryError { - if _, err := client.CreateOrUpdateParent(ctx, dedicatedHostId.ResourceGroup, "Microsoft.Compute", "hostGroups", dedicatedHostId.HostGroupName, "hosts", dedicatedHostId.HostName, assignmentName, configurationAssignment); err != nil { + + if _, err := client.CreateOrUpdateParent(ctx, id, configurationAssignment); err != nil { + if strings.Contains(err.Error(), "It may take a few minutes after starting a VM for it to become available to assign to a configuration") { return pluginsdk.RetryableError(fmt.Errorf("expected VM is available to assign to a configuration but was in pending state, retrying")) } - return pluginsdk.NonRetryableError(fmt.Errorf("issuing creating request for Maintenance Assignment (Dedicated Host ID %q): %+v", dedicatedHostIdRaw, err)) + return pluginsdk.NonRetryableError(fmt.Errorf("issuing creating request for Maintenance Assignment (Dedicated Host ID %q): %+v", dedicatedHostId.ID(), err)) } return nil @@ -107,19 +115,8 @@ func resourceArmMaintenanceAssignmentDedicatedHostCreate(d *pluginsdk.ResourceDa return err } - resp, err := getMaintenanceAssignmentDedicatedHost(ctx, client, dedicatedHostId, dedicatedHostIdRaw) - if err != nil { - return err - } - if resp == nil || len(*resp) == 0 { - return fmt.Errorf("could not find Maintenance assignment (virtual machine scale set ID: %q)", dedicatedHostIdRaw) - } - assignment := (*resp)[0] - if assignment.ID == nil || *assignment.ID == "" { - return fmt.Errorf("empty or nil ID of Maintenance Assignment (Dedicated Host ID %q)", dedicatedHostIdRaw) - } + d.SetId(id.ID()) - d.SetId(*assignment.ID) return resourceArmMaintenanceAssignmentDedicatedHostRead(d, meta) } @@ -142,18 +139,22 @@ func resourceArmMaintenanceAssignmentDedicatedHostRead(d *pluginsdk.ResourceData return nil } assignment := (*resp)[0] - if assignment.ID == nil || *assignment.ID == "" { + if assignment.Id == nil || *assignment.Id == "" { return fmt.Errorf("empty or nil ID of Maintenance Assignment (Dedicated Host ID: %q", id.DedicatedHostIdRaw) } - dedicatedHostId := "" - if id.DedicatedHostId != nil { - dedicatedHostId = id.DedicatedHostId.ID() - } - d.Set("dedicated_host_id", dedicatedHostId) + d.Set("dedicated_host_id", id.DedicatedHostId.ID()) - if props := assignment.ConfigurationAssignmentProperties; props != nil { - d.Set("maintenance_configuration_id", props.MaintenanceConfigurationID) + if props := assignment.Properties; props != nil { + maintenanceConfigurationId := "" + if props.MaintenanceConfigurationId != nil { + parsedId, err := maintenanceconfigurations.ParseMaintenanceConfigurationIDInsensitively(*props.MaintenanceConfigurationId) + if err != nil { + return fmt.Errorf("parsing %q: %+v", *props.MaintenanceConfigurationId, err) + } + maintenanceConfigurationId = parsedId.ID() + } + d.Set("maintenance_configuration_id", maintenanceConfigurationId) } return nil } @@ -168,20 +169,26 @@ func resourceArmMaintenanceAssignmentDedicatedHostDelete(d *pluginsdk.ResourceDa return err } - if _, err := client.DeleteParent(ctx, id.DedicatedHostId.ResourceGroup, "Microsoft.Compute", "hostGroups", id.DedicatedHostId.HostGroupName, "hosts", id.DedicatedHostId.HostName, id.Name); err != nil { + providerConfigAssignmentId := configurationassignments.NewProviders2ConfigurationAssignmentID(id.DedicatedHostId.SubscriptionId, id.DedicatedHostId.ResourceGroupName, "Microsoft.Compute", "hostGroups", id.DedicatedHostId.HostGroupName, "hosts", id.DedicatedHostId.HostName, id.Name) + + if _, err := client.DeleteParent(ctx, providerConfigAssignmentId); err != nil { return fmt.Errorf("deleting Maintenance Assignment to resource %q: %+v", id.DedicatedHostIdRaw, err) } return nil } -func getMaintenanceAssignmentDedicatedHost(ctx context.Context, client *maintenance.ConfigurationAssignmentsClient, id *parseCompute.DedicatedHostId, dedicatedHostId string) (result *[]maintenance.ConfigurationAssignment, err error) { - resp, err := client.ListParent(ctx, id.ResourceGroup, "Microsoft.Compute", "hostGroups", id.HostGroupName, "hosts", id.HostName) +func getMaintenanceAssignmentDedicatedHost(ctx context.Context, client *configurationassignments.ConfigurationAssignmentsClient, hostId dedicatedhosts.HostId, dedicatedHostId string) (result *[]configurationassignments.ConfigurationAssignment, err error) { + + id := configurationassignments.NewResourceGroupProviderID(hostId.SubscriptionId, hostId.ResourceGroupName, "Microsoft.Compute", "hostGroups", hostId.HostGroupName, "hosts", hostId.HostName) + + resp, err := client.ListParent(ctx, id) + if err != nil { - if !utils.ResponseWasNotFound(resp.Response) { + if !response.WasNotFound(resp.HttpResponse) { err = fmt.Errorf("checking for presence of existing Maintenance assignment (Dedicated Host ID %q): %+v", dedicatedHostId, err) - return + return nil, err } } - return resp.Value, nil + return resp.Model.Value, nil } diff --git a/internal/services/maintenance/maintenance_assignment_dedicated_host_resource_test.go b/internal/services/maintenance/maintenance_assignment_dedicated_host_resource_test.go index 7693b4b1b826..cfdaad295c88 100644 --- a/internal/services/maintenance/maintenance_assignment_dedicated_host_resource_test.go +++ b/internal/services/maintenance/maintenance_assignment_dedicated_host_resource_test.go @@ -5,6 +5,7 @@ import ( "fmt" "testing" + "github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/configurationassignments" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" @@ -51,12 +52,14 @@ func (MaintenanceAssignmentDedicatedHostResource) Exists(ctx context.Context, cl return nil, err } - resp, err := clients.Maintenance.ConfigurationAssignmentsClient.ListParent(ctx, id.DedicatedHostId.ResourceGroup, "Microsoft.Compute", "hostGroups", id.DedicatedHostId.HostGroupName, "hosts", id.DedicatedHostId.HostName) + rgProviderId := configurationassignments.NewResourceGroupProviderID(id.DedicatedHostId.SubscriptionId, id.DedicatedHostId.ResourceGroupName, "Microsoft.Compute", "hostGroups", id.DedicatedHostId.HostGroupName, "hosts", id.DedicatedHostId.HostName) + resp, err := clients.Maintenance.ConfigurationAssignmentsClient.ListParent(ctx, rgProviderId) + if err != nil { return nil, fmt.Errorf("retrieving Maintenance Assignment Dedicated Host (target resource id: %q): %v", id.DedicatedHostIdRaw, err) } - return utils.Bool(resp.Value != nil && len(*resp.Value) != 0), nil + return utils.Bool(resp.Model != nil && resp.Model.Value != nil && len(*resp.Model.Value) != 0), nil } func (r MaintenanceAssignmentDedicatedHostResource) basic(data acceptance.TestData) string { @@ -98,7 +101,7 @@ resource "azurerm_maintenance_configuration" "test" { name = "acctest-MC%[1]d" resource_group_name = azurerm_resource_group.test.name location = azurerm_resource_group.test.location - scope = "All" + scope = "Host" } resource "azurerm_dedicated_host_group" "test" { diff --git a/internal/services/maintenance/maintenance_assignment_virtual_machine_resource.go b/internal/services/maintenance/maintenance_assignment_virtual_machine_resource.go index b264e0bfed37..9b735287916e 100644 --- a/internal/services/maintenance/maintenance_assignment_virtual_machine_resource.go +++ b/internal/services/maintenance/maintenance_assignment_virtual_machine_resource.go @@ -6,15 +6,16 @@ import ( "strings" "time" - "github.com/Azure/azure-sdk-for-go/services/maintenance/mgmt/2021-05-01/maintenance" + "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/configurationassignments" + "github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/maintenanceconfigurations" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" parseCompute "github.com/hashicorp/terraform-provider-azurerm/internal/services/compute/parse" validateCompute "github.com/hashicorp/terraform-provider-azurerm/internal/services/compute/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/services/maintenance/parse" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/maintenance/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/suppress" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" @@ -42,10 +43,11 @@ func resourceArmMaintenanceAssignmentVirtualMachine() *pluginsdk.Resource { "location": azure.SchemaLocation(), "maintenance_configuration_id": { - Type: pluginsdk.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validate.MaintenanceConfigurationID, + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: maintenanceconfigurations.ValidateMaintenanceConfigurationID, + DiffSuppressFunc: suppress.CaseDifference, // TODO remove in 4.0 with a work around or when https://github.com/Azure/azure-rest-api-specs/issues/8653 is fixed }, "virtual_machine_id": { @@ -53,7 +55,7 @@ func resourceArmMaintenanceAssignmentVirtualMachine() *pluginsdk.Resource { Required: true, ForceNew: true, ValidateFunc: validateCompute.VirtualMachineID, - DiffSuppressFunc: suppress.CaseDifference, + DiffSuppressFunc: suppress.CaseDifference, // TODO remove in 4.0 }, }, } @@ -64,41 +66,47 @@ func resourceArmMaintenanceAssignmentVirtualMachineCreate(d *pluginsdk.ResourceD ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) defer cancel() - virtualMachineIdRaw := d.Get("virtual_machine_id").(string) - virtualMachineId, _ := parseCompute.VirtualMachineID(virtualMachineIdRaw) + virtualMachineId, err := parseCompute.VirtualMachineID(d.Get("virtual_machine_id").(string)) + if err != nil { + return err + } - existingList, err := getMaintenanceAssignmentVirtualMachine(ctx, client, virtualMachineId, virtualMachineIdRaw) + configurationId, err := maintenanceconfigurations.ParseMaintenanceConfigurationID(d.Get("maintenance_configuration_id").(string)) + if err != nil { + return err + } + + existingList, err := getMaintenanceAssignmentVirtualMachine(ctx, client, virtualMachineId, virtualMachineId.ID()) if err != nil { return err } if existingList != nil && len(*existingList) > 0 { existing := (*existingList)[0] - if existing.ID != nil && *existing.ID != "" { - return tf.ImportAsExistsError("azurerm_maintenance_assignment_virtual_machine", *existing.ID) + if existing.Id != nil && *existing.Id != "" { + return tf.ImportAsExistsError("azurerm_maintenance_assignment_virtual_machine", configurationId.ID()) } } - maintenanceConfigurationID := d.Get("maintenance_configuration_id").(string) - configurationId, _ := parse.MaintenanceConfigurationIDInsensitively(maintenanceConfigurationID) - // set assignment name to configuration name - assignmentName := configurationId.Name - configurationAssignment := maintenance.ConfigurationAssignment{ + assignmentName := configurationId.ResourceName + configurationAssignment := configurationassignments.ConfigurationAssignment{ Name: utils.String(assignmentName), Location: utils.String(location.Normalize(d.Get("location").(string))), - ConfigurationAssignmentProperties: &maintenance.ConfigurationAssignmentProperties{ - MaintenanceConfigurationID: utils.String(maintenanceConfigurationID), - ResourceID: utils.String(virtualMachineIdRaw), + Properties: &configurationassignments.ConfigurationAssignmentProperties{ + MaintenanceConfigurationId: utils.String(configurationId.ID()), + ResourceId: utils.String(virtualMachineId.ID()), }, } + id := configurationassignments.NewConfigurationAssignmentID(virtualMachineId.SubscriptionId, virtualMachineId.ResourceGroup, "Microsoft.Compute", "virtualMachines", virtualMachineId.Name, assignmentName) + // It may take a few minutes after starting a VM for it to become available to assign to a configuration err = pluginsdk.Retry(d.Timeout(pluginsdk.TimeoutCreate), func() *pluginsdk.RetryError { - if _, err := client.CreateOrUpdate(ctx, virtualMachineId.ResourceGroup, "Microsoft.Compute", "virtualMachines", virtualMachineId.Name, assignmentName, configurationAssignment); err != nil { + if _, err := client.CreateOrUpdate(ctx, id, configurationAssignment); err != nil { if strings.Contains(err.Error(), "It may take a few minutes after starting a VM for it to become available to assign to a configuration") { return pluginsdk.RetryableError(fmt.Errorf("expected VM is available to assign to a configuration but was in pending state, retrying")) } - return pluginsdk.NonRetryableError(fmt.Errorf("issuing creating request for Maintenance Assignment (virtual machine ID %q): %+v", virtualMachineIdRaw, err)) + return pluginsdk.NonRetryableError(fmt.Errorf("issuing creating request for Maintenance Assignment (virtual machine ID %q): %+v", virtualMachineId.ID(), err)) } return nil @@ -107,19 +115,7 @@ func resourceArmMaintenanceAssignmentVirtualMachineCreate(d *pluginsdk.ResourceD return err } - resp, err := getMaintenanceAssignmentVirtualMachine(ctx, client, virtualMachineId, virtualMachineIdRaw) - if err != nil { - return err - } - if resp == nil || len(*resp) == 0 { - return fmt.Errorf("could not find Maintenance assignment (virtual machine ID: %q)", virtualMachineIdRaw) - } - assignment := (*resp)[0] - if assignment.ID == nil || *assignment.ID == "" { - return fmt.Errorf("empty or nil ID of Maintenance Assignment (virtual machine ID %q)", virtualMachineIdRaw) - } - - d.SetId(*assignment.ID) + d.SetId(id.ID()) return resourceArmMaintenanceAssignmentVirtualMachineRead(d, meta) } @@ -142,7 +138,7 @@ func resourceArmMaintenanceAssignmentVirtualMachineRead(d *pluginsdk.ResourceDat return nil } assignment := (*resp)[0] - if assignment.ID == nil || *assignment.ID == "" { + if assignment.Id == nil || *assignment.Id == "" { return fmt.Errorf("empty or nil ID of Maintenance Assignment (virtual machine ID id: %q", id.VirtualMachineIdRaw) } @@ -152,8 +148,16 @@ func resourceArmMaintenanceAssignmentVirtualMachineRead(d *pluginsdk.ResourceDat virtualMachineId = id.VirtualMachineId.ID() } d.Set("virtual_machine_id", virtualMachineId) - if props := assignment.ConfigurationAssignmentProperties; props != nil { - d.Set("maintenance_configuration_id", props.MaintenanceConfigurationID) + if props := assignment.Properties; props != nil { + maintenanceConfigurationId := "" + if props.MaintenanceConfigurationId != nil { + parsedId, err := maintenanceconfigurations.ParseMaintenanceConfigurationIDInsensitively(*props.MaintenanceConfigurationId) + if err != nil { + return fmt.Errorf("parsing %q: %+v", *props.MaintenanceConfigurationId, err) + } + maintenanceConfigurationId = parsedId.ID() + } + d.Set("maintenance_configuration_id", maintenanceConfigurationId) } return nil } @@ -163,25 +167,30 @@ func resourceArmMaintenanceAssignmentVirtualMachineDelete(d *pluginsdk.ResourceD ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.MaintenanceAssignmentVirtualMachineID(d.Id()) + vmId, err := parse.MaintenanceAssignmentVirtualMachineID(d.Id()) if err != nil { return err } - if _, err := client.Delete(ctx, id.VirtualMachineId.ResourceGroup, "Microsoft.Compute", "virtualMachines", id.VirtualMachineId.Name, id.Name); err != nil { - return fmt.Errorf("deleting Maintenance Assignment to resource %q: %+v", id.VirtualMachineIdRaw, err) + id := configurationassignments.NewConfigurationAssignmentID(vmId.VirtualMachineId.SubscriptionId, vmId.VirtualMachineId.ResourceGroup, "Microsoft.Compute", "virtualMachines", vmId.VirtualMachineId.Name, vmId.Name) + + if _, err := client.Delete(ctx, id); err != nil { + return fmt.Errorf("deleting Maintenance Assignment to resource %q: %+v", vmId.VirtualMachineIdRaw, err) } return nil } -func getMaintenanceAssignmentVirtualMachine(ctx context.Context, client *maintenance.ConfigurationAssignmentsClient, id *parseCompute.VirtualMachineId, virtualMachineId string) (result *[]maintenance.ConfigurationAssignment, err error) { - resp, err := client.List(ctx, id.ResourceGroup, "Microsoft.Compute", "virtualMachines", id.Name) +func getMaintenanceAssignmentVirtualMachine(ctx context.Context, client *configurationassignments.ConfigurationAssignmentsClient, vmId *parseCompute.VirtualMachineId, virtualMachineId string) (result *[]configurationassignments.ConfigurationAssignment, err error) { + + id := configurationassignments.NewProviderID(vmId.SubscriptionId, vmId.ResourceGroup, "Microsoft.Compute", "virtualMachines", vmId.Name) + resp, err := client.List(ctx, id) if err != nil { - if !utils.ResponseWasNotFound(resp.Response) { + if !response.WasNotFound(resp.HttpResponse) { err = fmt.Errorf("checking for presence of existing Maintenance assignment (virtual machine ID: %q): %+v", virtualMachineId, err) return } } - return resp.Value, nil + + return resp.Model.Value, nil } diff --git a/internal/services/maintenance/maintenance_assignment_virtual_machine_resource_test.go b/internal/services/maintenance/maintenance_assignment_virtual_machine_resource_test.go index 137aeb11467e..a65215d2f288 100644 --- a/internal/services/maintenance/maintenance_assignment_virtual_machine_resource_test.go +++ b/internal/services/maintenance/maintenance_assignment_virtual_machine_resource_test.go @@ -5,6 +5,7 @@ import ( "fmt" "testing" + "github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/configurationassignments" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" @@ -47,17 +48,19 @@ func TestAccMaintenanceAssignmentVirtualMachine_requiresImport(t *testing.T) { } func (MaintenanceAssignmentVirtualMachineResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.MaintenanceAssignmentVirtualMachineID(state.ID) + maintenanceAssignmentVirtualMachineId, err := parse.MaintenanceAssignmentVirtualMachineID(state.ID) if err != nil { return nil, err } - resp, err := clients.Maintenance.ConfigurationAssignmentsClient.List(ctx, id.VirtualMachineId.ResourceGroup, "Microsoft.Compute", "virtualMachines", id.VirtualMachineId.Name) + id := configurationassignments.NewProviderID(maintenanceAssignmentVirtualMachineId.VirtualMachineId.SubscriptionId, maintenanceAssignmentVirtualMachineId.VirtualMachineId.ResourceGroup, "Microsoft.Compute", "virtualMachines", maintenanceAssignmentVirtualMachineId.VirtualMachineId.Name) + + resp, err := clients.Maintenance.ConfigurationAssignmentsClient.List(ctx, id) if err != nil { - return nil, fmt.Errorf("retrieving Maintenance Assignment Virtual Machine (target resource id: %q): %v", id.VirtualMachineIdRaw, err) + return nil, fmt.Errorf("retrieving Maintenance Assignment Virtual Machine (target resource id: %q): %v", maintenanceAssignmentVirtualMachineId.VirtualMachineIdRaw, err) } - return utils.Bool(resp.Value != nil && len(*resp.Value) != 0), nil + return utils.Bool(resp.Model != nil && resp.Model.Value != nil && len(*resp.Model.Value) != 0), nil } func (r MaintenanceAssignmentVirtualMachineResource) basic(data acceptance.TestData) string { @@ -99,7 +102,7 @@ resource "azurerm_maintenance_configuration" "test" { name = "acctest-MC%[1]d" resource_group_name = azurerm_resource_group.test.name location = azurerm_resource_group.test.location - scope = "All" + scope = "SQLDB" } resource "azurerm_virtual_network" "test" { diff --git a/internal/services/maintenance/maintenance_assignment_virtual_machine_scale_set_resource.go b/internal/services/maintenance/maintenance_assignment_virtual_machine_scale_set_resource.go index a98abe2ca8c8..ad1f667c525f 100644 --- a/internal/services/maintenance/maintenance_assignment_virtual_machine_scale_set_resource.go +++ b/internal/services/maintenance/maintenance_assignment_virtual_machine_scale_set_resource.go @@ -5,15 +5,16 @@ import ( "fmt" "time" - "github.com/Azure/azure-sdk-for-go/services/maintenance/mgmt/2021-05-01/maintenance" + "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/configurationassignments" + "github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/maintenanceconfigurations" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" parseCompute "github.com/hashicorp/terraform-provider-azurerm/internal/services/compute/parse" validateCompute "github.com/hashicorp/terraform-provider-azurerm/internal/services/compute/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/services/maintenance/parse" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/maintenance/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/suppress" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" @@ -41,10 +42,11 @@ func resourceArmMaintenanceAssignmentVirtualMachineScaleSet() *pluginsdk.Resourc "location": azure.SchemaLocation(), "maintenance_configuration_id": { - Type: pluginsdk.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validate.MaintenanceConfigurationID, + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: maintenanceconfigurations.ValidateMaintenanceConfigurationID, + DiffSuppressFunc: suppress.CaseDifference, // TODO remove in 4.0 with a work around or when https://github.com/Azure/azure-rest-api-specs/issues/8653 is fixed }, "virtual_machine_scale_set_id": { @@ -52,7 +54,7 @@ func resourceArmMaintenanceAssignmentVirtualMachineScaleSet() *pluginsdk.Resourc Required: true, ForceNew: true, ValidateFunc: validateCompute.VirtualMachineScaleSetID, - DiffSuppressFunc: suppress.CaseDifference, + DiffSuppressFunc: suppress.CaseDifference, // TODO remove in 4.0 }, }, } @@ -63,52 +65,44 @@ func resourceArmMaintenanceAssignmentVirtualMachineScaleSetCreate(d *pluginsdk.R ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) defer cancel() - virtualMachineScaleSetIdRaw := d.Get("virtual_machine_scale_set_id").(string) - virtualMachineScaleSetId, _ := parseCompute.VirtualMachineScaleSetID(virtualMachineScaleSetIdRaw) + virtualMachineScaleSetId, err := parseCompute.VirtualMachineScaleSetID(d.Get("virtual_machine_scale_set_id").(string)) + if err != nil { + return err + } - existingList, err := getMaintenanceAssignmentVirtualMachineScaleSet(ctx, client, virtualMachineScaleSetId, virtualMachineScaleSetIdRaw) + maintenanceConfigurationID, err := maintenanceconfigurations.ParseMaintenanceConfigurationID(d.Get("maintenance_configuration_id").(string)) + if err != nil { + return err + } + + configAssignmentId := configurationassignments.NewConfigurationAssignmentID(virtualMachineScaleSetId.SubscriptionId, virtualMachineScaleSetId.ResourceGroup, "Microsoft.Compute", "virtualMachineScaleSets", virtualMachineScaleSetId.Name, maintenanceConfigurationID.ResourceName) + + existingList, err := getMaintenanceAssignmentVirtualMachineScaleSet(ctx, client, virtualMachineScaleSetId) if err != nil { return err } if existingList != nil && len(*existingList) > 0 { existing := (*existingList)[0] - if existing.ID != nil && *existing.ID != "" { - return tf.ImportAsExistsError("azurerm_maintenance_assignment_virtual_machine_scale_set", *existing.ID) + if existing.Id != nil && *existing.Id != "" { + return tf.ImportAsExistsError("azurerm_maintenance_assignment_virtual_machine_scale_set", configAssignmentId.ID()) } } - maintenanceConfigurationID := d.Get("maintenance_configuration_id").(string) - configurationId, _ := parse.MaintenanceConfigurationIDInsensitively(maintenanceConfigurationID) - - // set assignment name to configuration name - assignmentName := configurationId.Name - configurationAssignment := maintenance.ConfigurationAssignment{ - Name: utils.String(assignmentName), + configurationAssignment := configurationassignments.ConfigurationAssignment{ + Name: utils.String(maintenanceConfigurationID.ResourceName), Location: utils.String(location.Normalize(d.Get("location").(string))), - ConfigurationAssignmentProperties: &maintenance.ConfigurationAssignmentProperties{ - MaintenanceConfigurationID: utils.String(maintenanceConfigurationID), - ResourceID: utils.String(virtualMachineScaleSetIdRaw), + Properties: &configurationassignments.ConfigurationAssignmentProperties{ + MaintenanceConfigurationId: utils.String(maintenanceConfigurationID.ID()), + ResourceId: utils.String(virtualMachineScaleSetId.ID()), }, } - _, err = client.CreateOrUpdate(ctx, virtualMachineScaleSetId.ResourceGroup, "Microsoft.Compute", "virtualMachineScaleSets", virtualMachineScaleSetId.Name, assignmentName, configurationAssignment) + _, err = client.CreateOrUpdate(ctx, configAssignmentId, configurationAssignment) if err != nil { return err } - resp, err := getMaintenanceAssignmentVirtualMachineScaleSet(ctx, client, virtualMachineScaleSetId, virtualMachineScaleSetIdRaw) - if err != nil { - return err - } - if resp == nil || len(*resp) == 0 { - return fmt.Errorf("could not find Maintenance assignment (virtual machine scale set ID: %q)", virtualMachineScaleSetIdRaw) - } - assignment := (*resp)[0] - if assignment.ID == nil || *assignment.ID == "" { - return fmt.Errorf("empty or nil ID of Maintenance Assignment (virtual machine scale set ID %q)", virtualMachineScaleSetIdRaw) - } - - d.SetId(*assignment.ID) + d.SetId(configAssignmentId.ID()) return resourceArmMaintenanceAssignmentVirtualMachineScaleSetRead(d, meta) } @@ -122,7 +116,7 @@ func resourceArmMaintenanceAssignmentVirtualMachineScaleSetRead(d *pluginsdk.Res return err } - resp, err := getMaintenanceAssignmentVirtualMachineScaleSet(ctx, client, id.VirtualMachineScaleSetId, id.VirtualMachineScaleSetIdRaw) + resp, err := getMaintenanceAssignmentVirtualMachineScaleSet(ctx, client, id.VirtualMachineScaleSetId) if err != nil { return err } @@ -131,7 +125,7 @@ func resourceArmMaintenanceAssignmentVirtualMachineScaleSetRead(d *pluginsdk.Res return nil } assignment := (*resp)[0] - if assignment.ID == nil || *assignment.ID == "" { + if assignment.Id == nil || *assignment.Id == "" { return fmt.Errorf("empty or nil ID of Maintenance Assignment (virtual machine scale set ID id: %q", id.VirtualMachineScaleSetIdRaw) } @@ -141,8 +135,16 @@ func resourceArmMaintenanceAssignmentVirtualMachineScaleSetRead(d *pluginsdk.Res virtualMachineScaleSetId = id.VirtualMachineScaleSetId.ID() } d.Set("virtual_machine_scale_set_id", virtualMachineScaleSetId) - if props := assignment.ConfigurationAssignmentProperties; props != nil { - d.Set("maintenance_configuration_id", props.MaintenanceConfigurationID) + if props := assignment.Properties; props != nil { + maintenanceConfigurationId := "" + if props.MaintenanceConfigurationId != nil { + parsedId, err := maintenanceconfigurations.ParseMaintenanceConfigurationIDInsensitively(*props.MaintenanceConfigurationId) + if err != nil { + return fmt.Errorf("parsing %q: %+v", *props.MaintenanceConfigurationId, err) + } + maintenanceConfigurationId = parsedId.ID() + } + d.Set("maintenance_configuration_id", maintenanceConfigurationId) } return nil } @@ -152,25 +154,30 @@ func resourceArmMaintenanceAssignmentVirtualMachineScaleSetDelete(d *pluginsdk.R ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.MaintenanceAssignmentVirtualMachineScaleSetID(d.Id()) + maintenanceAssignmentVmScaleSetId, err := parse.MaintenanceAssignmentVirtualMachineScaleSetID(d.Id()) if err != nil { return err } - if _, err := client.Delete(ctx, id.VirtualMachineScaleSetId.ResourceGroup, "Microsoft.Compute", "virtualMachineScaleSets", id.VirtualMachineScaleSetId.Name, id.Name); err != nil { - return fmt.Errorf("deleting Maintenance Assignment to resource %q: %+v", id.VirtualMachineScaleSetIdRaw, err) + id := configurationassignments.NewConfigurationAssignmentID(maintenanceAssignmentVmScaleSetId.VirtualMachineScaleSetId.SubscriptionId, maintenanceAssignmentVmScaleSetId.VirtualMachineScaleSetId.ResourceGroup, "Microsoft.Compute", "virtualMachineScaleSets", maintenanceAssignmentVmScaleSetId.VirtualMachineScaleSetId.Name, maintenanceAssignmentVmScaleSetId.Name) + + if _, err := client.Delete(ctx, id); err != nil { + return fmt.Errorf("deleting Maintenance Assignment to resource %q: %+v", maintenanceAssignmentVmScaleSetId.VirtualMachineScaleSetIdRaw, err) } return nil } -func getMaintenanceAssignmentVirtualMachineScaleSet(ctx context.Context, client *maintenance.ConfigurationAssignmentsClient, id *parseCompute.VirtualMachineScaleSetId, virtualMachineScaleSetId string) (result *[]maintenance.ConfigurationAssignment, err error) { - resp, err := client.List(ctx, id.ResourceGroup, "Microsoft.Compute", "virtualMachineScaleSets", id.Name) +func getMaintenanceAssignmentVirtualMachineScaleSet(ctx context.Context, client *configurationassignments.ConfigurationAssignmentsClient, vmScaleSetId *parseCompute.VirtualMachineScaleSetId) (result *[]configurationassignments.ConfigurationAssignment, err error) { + + id := configurationassignments.NewProviderID(vmScaleSetId.SubscriptionId, vmScaleSetId.ResourceGroup, "Microsoft.Compute", "virtualMachineScaleSets", vmScaleSetId.Name) + + resp, err := client.List(ctx, id) if err != nil { - if !utils.ResponseWasNotFound(resp.Response) { - err = fmt.Errorf("checking for presence of existing Maintenance assignment (virtual machine scale set ID: %q): %+v", virtualMachineScaleSetId, err) + if !response.WasNotFound(resp.HttpResponse) { + err = fmt.Errorf("checking for presence of existing Maintenance assignment (virtual machine scale set ID: %q): %+v", vmScaleSetId.ID(), err) return } } - return resp.Value, nil + return resp.Model.Value, nil } diff --git a/internal/services/maintenance/maintenance_assignment_virtual_machine_scale_set_resource_test.go b/internal/services/maintenance/maintenance_assignment_virtual_machine_scale_set_resource_test.go index c4953a476159..2636c7bed85e 100644 --- a/internal/services/maintenance/maintenance_assignment_virtual_machine_scale_set_resource_test.go +++ b/internal/services/maintenance/maintenance_assignment_virtual_machine_scale_set_resource_test.go @@ -5,6 +5,7 @@ import ( "fmt" "testing" + "github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/configurationassignments" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" @@ -47,17 +48,19 @@ func TestAccMaintenanceAssignmentVirtualMachineScaleSet_requiresImport(t *testin } func (MaintenanceAssignmentVirtualMachineScaleSetResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.MaintenanceAssignmentVirtualMachineScaleSetID(state.ID) + maVmScaleSetID, err := parse.MaintenanceAssignmentVirtualMachineScaleSetID(state.ID) if err != nil { return nil, err } - resp, err := clients.Maintenance.ConfigurationAssignmentsClient.List(ctx, id.VirtualMachineScaleSetId.ResourceGroup, "Microsoft.Compute", "virtualMachineScaleSets", id.VirtualMachineScaleSetId.Name) + id := configurationassignments.NewProviderID(maVmScaleSetID.VirtualMachineScaleSetId.SubscriptionId, maVmScaleSetID.VirtualMachineScaleSetId.ResourceGroup, "Microsoft.Compute", "virtualMachineScaleSets", maVmScaleSetID.VirtualMachineScaleSetId.Name) + + resp, err := clients.Maintenance.ConfigurationAssignmentsClient.List(ctx, id) if err != nil { - return nil, fmt.Errorf("retrieving Maintenance Assignment Virtual Machine Scale Set (target resource id: %q): %v", id.VirtualMachineScaleSetIdRaw, err) + return nil, fmt.Errorf("retrieving Maintenance Assignment Virtual Machine Scale Set (target resource id: %q): %v", maVmScaleSetID.VirtualMachineScaleSetIdRaw, err) } - return utils.Bool(resp.Value != nil && len(*resp.Value) != 0), nil + return utils.Bool(resp.Model != nil && resp.Model.Value != nil && len(*resp.Model.Value) != 0), nil } func (r MaintenanceAssignmentVirtualMachineScaleSetResource) basic(data acceptance.TestData) string { diff --git a/internal/services/maintenance/maintenance_configuration_data_source.go b/internal/services/maintenance/maintenance_configuration_data_source.go index bc58a751ce0a..f4bffb7fde7a 100644 --- a/internal/services/maintenance/maintenance_configuration_data_source.go +++ b/internal/services/maintenance/maintenance_configuration_data_source.go @@ -4,15 +4,15 @@ import ( "fmt" "time" + "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/maintenanceconfigurations" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/maintenance/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" - "github.com/hashicorp/terraform-provider-azurerm/utils" ) func dataSourceMaintenanceConfiguration() *pluginsdk.Resource { @@ -92,10 +92,10 @@ func dataSourceArmMaintenanceConfigurationRead(d *pluginsdk.ResourceData, meta i ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id := parse.NewMaintenanceConfigurationID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) - resp, err := client.Get(ctx, id.ResourceGroup, id.Name) + id := maintenanceconfigurations.NewMaintenanceConfigurationID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) + resp, err := client.Get(ctx, id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { return fmt.Errorf("%s was not found", id) } @@ -103,20 +103,25 @@ func dataSourceArmMaintenanceConfigurationRead(d *pluginsdk.ResourceData, meta i } d.SetId(id.ID()) - d.Set("name", id.Name) - d.Set("resource_group_name", id.ResourceGroup) - d.Set("location", location.NormalizeNilable(resp.Location)) - - if props := resp.ConfigurationProperties; props != nil { - d.Set("scope", props.MaintenanceScope) - d.Set("visibility", props.Visibility) - d.Set("properties", props.ExtensionProperties) - - window := flattenMaintenanceConfigurationWindow(props.Window) - if err := d.Set("window", window); err != nil { - return fmt.Errorf("setting `window`: %+v", err) + d.Set("name", id.ResourceName) + d.Set("resource_group_name", id.ResourceGroupName) + + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("scope", props.MaintenanceScope) + d.Set("visibility", props.Visibility) + d.Set("properties", props.ExtensionProperties) + + window := flattenMaintenanceConfigurationWindow(props.MaintenanceWindow) + if err := d.Set("window", window); err != nil { + return fmt.Errorf("setting `window`: %+v", err) + } + } + d.Set("location", location.NormalizeNilable(model.Location)) + if err = tags.FlattenAndSet(d, flattenTags(model.Tags)); err != nil { + return err } } - return tags.FlattenAndSet(d, resp.Tags) + return nil } diff --git a/internal/services/maintenance/maintenance_configuration_resource.go b/internal/services/maintenance/maintenance_configuration_resource.go index 59c7a00757b7..94d3d90172f2 100644 --- a/internal/services/maintenance/maintenance_configuration_resource.go +++ b/internal/services/maintenance/maintenance_configuration_resource.go @@ -6,13 +6,13 @@ import ( "regexp" "time" - "github.com/Azure/azure-sdk-for-go/services/maintenance/mgmt/2021-05-01/maintenance" + "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/maintenanceconfigurations" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/services/maintenance/migration" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/maintenance/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/maintenance/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" @@ -41,7 +41,7 @@ func resourceArmMaintenanceConfiguration() *pluginsdk.Resource { }, Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - _, err := parse.MaintenanceConfigurationIDInsensitively(id) + _, err := maintenanceconfigurations.ParseMaintenanceConfigurationIDInsensitively(id) return err }), @@ -59,25 +59,23 @@ func resourceArmMaintenanceConfiguration() *pluginsdk.Resource { "scope": { Type: pluginsdk.TypeString, - Optional: true, - Default: "All", + Required: true, ValidateFunc: validation.StringInSlice([]string{ - "All", // All is still accepted by the API - string(maintenance.ScopeExtension), - string(maintenance.ScopeHost), - string(maintenance.ScopeInGuestPatch), - string(maintenance.ScopeOSImage), - string(maintenance.ScopeSQLDB), - string(maintenance.ScopeSQLManagedInstance), + string(maintenanceconfigurations.MaintenanceScopeExtension), + string(maintenanceconfigurations.MaintenanceScopeHost), + string(maintenanceconfigurations.MaintenanceScopeInGuestPatch), + string(maintenanceconfigurations.MaintenanceScopeOSImage), + string(maintenanceconfigurations.MaintenanceScopeSQLDB), + string(maintenanceconfigurations.MaintenanceScopeSQLManagedInstance), }, false), }, "visibility": { Type: pluginsdk.TypeString, Optional: true, - Default: string(maintenance.VisibilityCustom), + Default: string(maintenanceconfigurations.VisibilityCustom), ValidateFunc: validation.StringInSlice([]string{ - string(maintenance.VisibilityCustom), + string(maintenanceconfigurations.VisibilityCustom), // Creating public configurations doesn't appear to be supported, API returns `Public Maintenance Configuration must set correct properties` // string(maintenance.VisibilityPublic), }, false), @@ -139,40 +137,38 @@ func resourceArmMaintenanceConfigurationCreateUpdate(d *pluginsdk.ResourceData, ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - id := parse.NewMaintenanceConfigurationID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) + id := maintenanceconfigurations.NewMaintenanceConfigurationID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) if d.IsNewResource() { - existing, err := client.Get(ctx, id.ResourceGroup, id.Name) + existing, err := client.Get(ctx, id) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return fmt.Errorf("checking for presence of existing %s: %+v", id, err) } } - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return tf.ImportAsExistsError("azurerm_maintenance_configuration", id.ID()) } } - scope := d.Get("scope").(string) - visibility := d.Get("visibility").(string) + scope := maintenanceconfigurations.MaintenanceScope(d.Get("scope").(string)) + visibility := maintenanceconfigurations.Visibility(d.Get("visibility").(string)) windowRaw := d.Get("window").([]interface{}) window := expandMaintenanceConfigurationWindow(windowRaw) - extensionProperties := utils.ExpandMapStringPtrString(d.Get("properties").(map[string]interface{})) - - configuration := maintenance.Configuration{ - Name: utils.String(id.Name), + configuration := maintenanceconfigurations.MaintenanceConfiguration{ + Name: utils.String(id.ResourceName), Location: utils.String(location.Normalize(d.Get("location").(string))), - ConfigurationProperties: &maintenance.ConfigurationProperties{ - MaintenanceScope: maintenance.Scope(scope), - Visibility: maintenance.Visibility(visibility), + Properties: &maintenanceconfigurations.MaintenanceConfigurationProperties{ + MaintenanceScope: &scope, + Visibility: &visibility, Namespace: utils.String("Microsoft.Maintenance"), - Window: window, - ExtensionProperties: extensionProperties, + MaintenanceWindow: window, + ExtensionProperties: expandExtensionProperties(d.Get("properties").(map[string]interface{})), }, - Tags: tags.Expand(d.Get("tags").(map[string]interface{})), + Tags: expandTags(d.Get("tags").(map[string]interface{})), } - if _, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.Name, configuration); err != nil { + if _, err := client.CreateOrUpdate(ctx, id, configuration); err != nil { return fmt.Errorf("creating/updating %s: %+v", id, err) } @@ -185,14 +181,14 @@ func resourceArmMaintenanceConfigurationRead(d *pluginsdk.ResourceData, meta int ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.MaintenanceConfigurationIDInsensitively(d.Id()) + id, err := maintenanceconfigurations.ParseMaintenanceConfigurationID(d.Id()) if err != nil { return err } - resp, err := client.Get(ctx, id.ResourceGroup, id.Name) + resp, err := client.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { log.Printf("[INFO] maintenance %q does not exist - removing from state", d.Id()) d.SetId("") return nil @@ -200,20 +196,26 @@ func resourceArmMaintenanceConfigurationRead(d *pluginsdk.ResourceData, meta int return fmt.Errorf("retrieving %s: %+v", id, err) } - d.Set("name", id.Name) - d.Set("resource_group_name", id.ResourceGroup) - d.Set("location", location.NormalizeNilable(resp.Location)) - if props := resp.ConfigurationProperties; props != nil { - d.Set("scope", props.MaintenanceScope) - d.Set("visibility", props.Visibility) - d.Set("properties", props.ExtensionProperties) - - window := flattenMaintenanceConfigurationWindow(props.Window) - if err := d.Set("window", window); err != nil { - return fmt.Errorf("setting `window`: %+v", err) + d.Set("name", id.ResourceName) + d.Set("resource_group_name", id.ResourceGroupName) + + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("scope", props.MaintenanceScope) + d.Set("visibility", props.Visibility) + d.Set("properties", props.ExtensionProperties) + + window := flattenMaintenanceConfigurationWindow(props.MaintenanceWindow) + if err := d.Set("window", window); err != nil { + return fmt.Errorf("setting `window`: %+v", err) + } + } + d.Set("location", location.NormalizeNilable(model.Location)) + if err = tags.FlattenAndSet(d, flattenTags(model.Tags)); err != nil { + return err } } - return tags.FlattenAndSet(d, resp.Tags) + return nil } func resourceArmMaintenanceConfigurationDelete(d *pluginsdk.ResourceData, meta interface{}) error { @@ -221,18 +223,18 @@ func resourceArmMaintenanceConfigurationDelete(d *pluginsdk.ResourceData, meta i ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.MaintenanceConfigurationIDInsensitively(d.Id()) + id, err := maintenanceconfigurations.ParseMaintenanceConfigurationIDInsensitively(d.Id()) if err != nil { return err } - if _, err := client.Delete(ctx, id.ResourceGroup, id.Name); err != nil { + if _, err := client.Delete(ctx, *id); err != nil { return fmt.Errorf("deleting %s: %+v", id, err) } return nil } -func expandMaintenanceConfigurationWindow(input []interface{}) *maintenance.Window { +func expandMaintenanceConfigurationWindow(input []interface{}) *maintenanceconfigurations.MaintenanceWindow { if len(input) == 0 { return nil } @@ -243,7 +245,7 @@ func expandMaintenanceConfigurationWindow(input []interface{}) *maintenance.Wind duration := v["duration"].(string) timeZone := v["time_zone"].(string) recurEvery := v["recur_every"].(string) - window := maintenance.Window{ + window := maintenanceconfigurations.MaintenanceWindow{ StartDateTime: utils.String(startDateTime), ExpirationDateTime: utils.String(expirationDateTime), Duration: utils.String(duration), @@ -253,7 +255,7 @@ func expandMaintenanceConfigurationWindow(input []interface{}) *maintenance.Wind return &window } -func flattenMaintenanceConfigurationWindow(input *maintenance.Window) []interface{} { +func flattenMaintenanceConfigurationWindow(input *maintenanceconfigurations.MaintenanceWindow) []interface{} { results := make([]interface{}, 0) if v := input; v != nil { @@ -284,3 +286,11 @@ func flattenMaintenanceConfigurationWindow(input *maintenance.Window) []interfac return results } + +func expandExtensionProperties(input map[string]interface{}) *map[string]string { + output := make(map[string]string) + for k, v := range input { + output[k] = v.(string) + } + return &output +} diff --git a/internal/services/maintenance/maintenance_configuration_resource_test.go b/internal/services/maintenance/maintenance_configuration_resource_test.go index 5696b78b802b..d621c0cf3101 100644 --- a/internal/services/maintenance/maintenance_configuration_resource_test.go +++ b/internal/services/maintenance/maintenance_configuration_resource_test.go @@ -5,10 +5,10 @@ import ( "fmt" "testing" + "github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/maintenanceconfigurations" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/maintenance/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -24,7 +24,7 @@ func TestAccMaintenanceConfiguration_basic(t *testing.T) { Config: r.basic(data), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), - check.That(data.ResourceName).Key("scope").HasValue("All"), + check.That(data.ResourceName).Key("scope").HasValue("SQLDB"), check.That(data.ResourceName).Key("visibility").HasValue("Custom"), ), }, @@ -82,7 +82,7 @@ func TestAccMaintenanceConfiguration_update(t *testing.T) { Config: r.basic(data), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), - check.That(data.ResourceName).Key("scope").HasValue("All"), + check.That(data.ResourceName).Key("scope").HasValue("SQLDB"), check.That(data.ResourceName).Key("visibility").HasValue("Custom"), check.That(data.ResourceName).Key("tags.%").HasValue("0"), check.That(data.ResourceName).Key("window.#").HasValue("0"), @@ -112,7 +112,7 @@ func TestAccMaintenanceConfiguration_update(t *testing.T) { Config: r.basic(data), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), - check.That(data.ResourceName).Key("scope").HasValue("All"), + check.That(data.ResourceName).Key("scope").HasValue("SQLDB"), check.That(data.ResourceName).Key("visibility").HasValue("Custom"), check.That(data.ResourceName).Key("tags.%").HasValue("0"), check.That(data.ResourceName).Key("window.#").HasValue("0"), @@ -124,17 +124,17 @@ func TestAccMaintenanceConfiguration_update(t *testing.T) { } func (MaintenanceConfigurationResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.MaintenanceConfigurationIDInsensitively(state.ID) + id, err := maintenanceconfigurations.ParseMaintenanceConfigurationIDInsensitively(state.ID) if err != nil { return nil, err } - resp, err := clients.Maintenance.ConfigurationsClient.Get(ctx, id.ResourceGroup, id.Name) + resp, err := clients.Maintenance.ConfigurationsClient.Get(ctx, *id) if err != nil { - return nil, fmt.Errorf("retrieving Maintenance Configuration %s (resource group: %s): %v", id.Name, id.ResourceGroup, err) + return nil, fmt.Errorf("retrieving %s: %v", *id, err) } - return utils.Bool(resp.ConfigurationProperties != nil), nil + return utils.Bool(resp.Model != nil && resp.Model.Properties != nil), nil } func (MaintenanceConfigurationResource) basic(data acceptance.TestData) string { @@ -152,7 +152,7 @@ resource "azurerm_maintenance_configuration" "test" { name = "acctest-MC%d" resource_group_name = azurerm_resource_group.test.name location = azurerm_resource_group.test.location - scope = "All" + scope = "SQLDB" visibility = "Custom" } `, data.RandomInteger, data.Locations.Primary, data.RandomInteger) diff --git a/internal/services/maintenance/migration/configuration_v0_to_v1.go b/internal/services/maintenance/migration/configuration_v0_to_v1.go index e446451fce9e..02cfd60786e3 100644 --- a/internal/services/maintenance/migration/configuration_v0_to_v1.go +++ b/internal/services/maintenance/migration/configuration_v0_to_v1.go @@ -4,8 +4,8 @@ import ( "context" "log" + "github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/maintenanceconfigurations" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/maintenance/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" ) @@ -57,7 +57,7 @@ func (ConfigurationV0ToV1) UpgradeFunc() pluginsdk.StateUpgraderFunc { name := rawState["name"].(string) resourceGroup := rawState["resource_group_name"].(string) - id := parse.NewMaintenanceConfigurationID(subscriptionId, resourceGroup, name) + id := maintenanceconfigurations.NewMaintenanceConfigurationID(subscriptionId, resourceGroup, name) rawState["id"] = id.ID() diff --git a/internal/services/maintenance/parse/maintenance_assignment_dedicated_host.go b/internal/services/maintenance/parse/maintenance_assignment_dedicated_host.go index 1aeb0b31897c..0335b7f1d436 100644 --- a/internal/services/maintenance/parse/maintenance_assignment_dedicated_host.go +++ b/internal/services/maintenance/parse/maintenance_assignment_dedicated_host.go @@ -4,11 +4,11 @@ import ( "fmt" "regexp" - parseCompute "github.com/hashicorp/terraform-provider-azurerm/internal/services/compute/parse" + "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhosts" ) type MaintenanceAssignmentDedicatedHostId struct { - DedicatedHostId *parseCompute.DedicatedHostId + DedicatedHostId dedicatedhosts.HostId DedicatedHostIdRaw string Name string } @@ -20,13 +20,13 @@ func MaintenanceAssignmentDedicatedHostID(input string) (*MaintenanceAssignmentD } targetResourceId, name := groups[1], groups[2] - dedicatedHostID, err := parseCompute.DedicatedHostID(targetResourceId) + dedicatedHostID, err := dedicatedhosts.ParseHostIDInsensitively(targetResourceId) if err != nil { return nil, fmt.Errorf("parsing Maintenance Assignment Dedicated Host ID: %q: Expected valid Dedicated Host ID", input) } return &MaintenanceAssignmentDedicatedHostId{ - DedicatedHostId: dedicatedHostID, + DedicatedHostId: *dedicatedHostID, DedicatedHostIdRaw: targetResourceId, Name: name, }, nil diff --git a/internal/services/maintenance/parse/maintenance_assignment_dedicated_host_test.go b/internal/services/maintenance/parse/maintenance_assignment_dedicated_host_test.go index 2c47d2a31039..1ef18a12f9e6 100644 --- a/internal/services/maintenance/parse/maintenance_assignment_dedicated_host_test.go +++ b/internal/services/maintenance/parse/maintenance_assignment_dedicated_host_test.go @@ -4,7 +4,7 @@ import ( "reflect" "testing" - parseCompute "github.com/hashicorp/terraform-provider-azurerm/internal/services/compute/parse" + "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2021-11-01/dedicatedhosts" ) func TestMaintenanceAssignmentDedicatedHostID(t *testing.T) { @@ -55,11 +55,11 @@ func TestMaintenanceAssignmentDedicatedHostID(t *testing.T) { Error: false, Expect: &MaintenanceAssignmentDedicatedHostId{ DedicatedHostIdRaw: "/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/resGroup1/providers/microsoft.compute/hostGroups/group1/hosts/host1", - DedicatedHostId: &parseCompute.DedicatedHostId{ - SubscriptionId: "00000000-0000-0000-0000-000000000000", - ResourceGroup: "resGroup1", - HostGroupName: "group1", - HostName: "host1", + DedicatedHostId: dedicatedhosts.HostId{ + SubscriptionId: "00000000-0000-0000-0000-000000000000", + ResourceGroupName: "resGroup1", + HostGroupName: "group1", + HostName: "host1", }, Name: "assign1", }, diff --git a/internal/services/maintenance/parse/maintenance_configuration.go b/internal/services/maintenance/parse/maintenance_configuration.go deleted file mode 100644 index 06a7602d2dd1..000000000000 --- a/internal/services/maintenance/parse/maintenance_configuration.go +++ /dev/null @@ -1,113 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - "strings" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -type MaintenanceConfigurationId struct { - SubscriptionId string - ResourceGroup string - Name string -} - -func NewMaintenanceConfigurationID(subscriptionId, resourceGroup, name string) MaintenanceConfigurationId { - return MaintenanceConfigurationId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourceGroup, - Name: name, - } -} - -func (id MaintenanceConfigurationId) String() string { - segments := []string{ - fmt.Sprintf("Name %q", id.Name), - fmt.Sprintf("Resource Group %q", id.ResourceGroup), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Maintenance Configuration", segmentsStr) -} - -func (id MaintenanceConfigurationId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Maintenance/maintenanceConfigurations/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.Name) -} - -// MaintenanceConfigurationID parses a MaintenanceConfiguration ID into an MaintenanceConfigurationId struct -func MaintenanceConfigurationID(input string) (*MaintenanceConfigurationId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := MaintenanceConfigurationId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - if resourceId.Name, err = id.PopSegment("maintenanceConfigurations"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} - -// MaintenanceConfigurationIDInsensitively parses an MaintenanceConfiguration ID into an MaintenanceConfigurationId struct, insensitively -// This should only be used to parse an ID for rewriting, the MaintenanceConfigurationID -// method should be used instead for validation etc. -// -// Whilst this may seem strange, this enables Terraform have consistent casing -// which works around issues in Core, whilst handling broken API responses. -func MaintenanceConfigurationIDInsensitively(input string) (*MaintenanceConfigurationId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := MaintenanceConfigurationId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - // find the correct casing for the 'maintenanceConfigurations' segment - maintenanceConfigurationsKey := "maintenanceConfigurations" - for key := range id.Path { - if strings.EqualFold(key, maintenanceConfigurationsKey) { - maintenanceConfigurationsKey = key - break - } - } - if resourceId.Name, err = id.PopSegment(maintenanceConfigurationsKey); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/maintenance/parse/maintenance_configuration_test.go b/internal/services/maintenance/parse/maintenance_configuration_test.go deleted file mode 100644 index 3f89fe685581..000000000000 --- a/internal/services/maintenance/parse/maintenance_configuration_test.go +++ /dev/null @@ -1,229 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "testing" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -var _ resourceids.Id = MaintenanceConfigurationId{} - -func TestMaintenanceConfigurationIDFormatter(t *testing.T) { - actual := NewMaintenanceConfigurationID("12345678-1234-9876-4563-123456789012", "resGroup1", "maintenanceConfiguration1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Maintenance/maintenanceConfigurations/maintenanceConfiguration1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestMaintenanceConfigurationID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *MaintenanceConfigurationId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - - { - // missing Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Maintenance/", - Error: true, - }, - - { - // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Maintenance/maintenanceConfigurations/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Maintenance/maintenanceConfigurations/maintenanceConfiguration1", - Expected: &MaintenanceConfigurationId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - Name: "maintenanceConfiguration1", - }, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.MAINTENANCE/MAINTENANCECONFIGURATIONS/MAINTENANCECONFIGURATION1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := MaintenanceConfigurationID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - if actual.Name != v.Expected.Name { - t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name) - } - } -} - -func TestMaintenanceConfigurationIDInsensitively(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *MaintenanceConfigurationId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - - { - // missing Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Maintenance/", - Error: true, - }, - - { - // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Maintenance/maintenanceConfigurations/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Maintenance/maintenanceConfigurations/maintenanceConfiguration1", - Expected: &MaintenanceConfigurationId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - Name: "maintenanceConfiguration1", - }, - }, - - { - // lower-cased segment names - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Maintenance/maintenanceconfigurations/maintenanceConfiguration1", - Expected: &MaintenanceConfigurationId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - Name: "maintenanceConfiguration1", - }, - }, - - { - // upper-cased segment names - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Maintenance/MAINTENANCECONFIGURATIONS/maintenanceConfiguration1", - Expected: &MaintenanceConfigurationId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - Name: "maintenanceConfiguration1", - }, - }, - - { - // mixed-cased segment names - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Maintenance/MaInTeNaNcEcOnFiGuRaTiOnS/maintenanceConfiguration1", - Expected: &MaintenanceConfigurationId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - Name: "maintenanceConfiguration1", - }, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := MaintenanceConfigurationIDInsensitively(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - if actual.Name != v.Expected.Name { - t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name) - } - } -} diff --git a/internal/services/maintenance/parse/public_maintenance_configuration.go b/internal/services/maintenance/parse/public_maintenance_configuration.go deleted file mode 100644 index da48a54c8c4a..000000000000 --- a/internal/services/maintenance/parse/public_maintenance_configuration.go +++ /dev/null @@ -1,61 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - "strings" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -type PublicMaintenanceConfigurationId struct { - SubscriptionId string - Name string -} - -func NewPublicMaintenanceConfigurationID(subscriptionId, name string) PublicMaintenanceConfigurationId { - return PublicMaintenanceConfigurationId{ - SubscriptionId: subscriptionId, - Name: name, - } -} - -func (id PublicMaintenanceConfigurationId) String() string { - segments := []string{ - fmt.Sprintf("Name %q", id.Name), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Public Maintenance Configuration", segmentsStr) -} - -func (id PublicMaintenanceConfigurationId) ID() string { - fmtString := "/subscriptions/%s/providers/Microsoft.Maintenance/publicMaintenanceConfigurations/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.Name) -} - -// PublicMaintenanceConfigurationID parses a PublicMaintenanceConfiguration ID into an PublicMaintenanceConfigurationId struct -func PublicMaintenanceConfigurationID(input string) (*PublicMaintenanceConfigurationId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := PublicMaintenanceConfigurationId{ - SubscriptionId: id.SubscriptionID, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.Name, err = id.PopSegment("publicMaintenanceConfigurations"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/maintenance/parse/public_maintenance_configuration_test.go b/internal/services/maintenance/parse/public_maintenance_configuration_test.go deleted file mode 100644 index 1773538c7b18..000000000000 --- a/internal/services/maintenance/parse/public_maintenance_configuration_test.go +++ /dev/null @@ -1,96 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "testing" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -var _ resourceids.Id = PublicMaintenanceConfigurationId{} - -func TestPublicMaintenanceConfigurationIDFormatter(t *testing.T) { - actual := NewPublicMaintenanceConfigurationID("12345678-1234-9876-4563-123456789012", "publicMaintenanceConfiguration1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/providers/Microsoft.Maintenance/publicMaintenanceConfigurations/publicMaintenanceConfiguration1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestPublicMaintenanceConfigurationID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *PublicMaintenanceConfigurationId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/providers/Microsoft.Maintenance/", - Error: true, - }, - - { - // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/providers/Microsoft.Maintenance/publicMaintenanceConfigurations/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/providers/Microsoft.Maintenance/publicMaintenanceConfigurations/publicMaintenanceConfiguration1", - Expected: &PublicMaintenanceConfigurationId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - Name: "publicMaintenanceConfiguration1", - }, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/PROVIDERS/MICROSOFT.MAINTENANCE/PUBLICMAINTENANCECONFIGURATIONS/PUBLICMAINTENANCECONFIGURATION1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := PublicMaintenanceConfigurationID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.Name != v.Expected.Name { - t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name) - } - } -} diff --git a/internal/services/maintenance/public_maintenance_configurations_data_source.go b/internal/services/maintenance/public_maintenance_configurations_data_source.go index 9b4f02fd4a88..dacbedc9ccc9 100644 --- a/internal/services/maintenance/public_maintenance_configurations_data_source.go +++ b/internal/services/maintenance/public_maintenance_configurations_data_source.go @@ -4,13 +4,14 @@ import ( "fmt" "time" - "github.com/Azure/azure-sdk-for-go/services/maintenance/mgmt/2021-05-01/maintenance" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" + "github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/publicmaintenanceconfigurations" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" - "github.com/hashicorp/terraform-provider-azurerm/utils" ) const recurMondayToThursday = "Monday-Thursday" @@ -36,13 +37,12 @@ func dataSourcePublicMaintenanceConfigurations() *pluginsdk.Resource { Type: pluginsdk.TypeString, Optional: true, ValidateFunc: validation.StringInSlice([]string{ - "All", // All is still accepted by the API - string(maintenance.ScopeExtension), - string(maintenance.ScopeHost), - string(maintenance.ScopeInGuestPatch), - string(maintenance.ScopeOSImage), - string(maintenance.ScopeSQLDB), - string(maintenance.ScopeSQLManagedInstance), + string(publicmaintenanceconfigurations.MaintenanceScopeExtension), + string(publicmaintenanceconfigurations.MaintenanceScopeHost), + string(publicmaintenanceconfigurations.MaintenanceScopeInGuestPatch), + string(publicmaintenanceconfigurations.MaintenanceScopeOSImage), + string(publicmaintenanceconfigurations.MaintenanceScopeSQLDB), + string(publicmaintenanceconfigurations.MaintenanceScopeSQLManagedInstance), }, false), }, @@ -108,12 +108,14 @@ func dataSourcePublicMaintenanceConfigurations() *pluginsdk.Resource { func dataSourcePublicMaintenanceConfigurationsRead(d *pluginsdk.ResourceData, meta interface{}) error { client := meta.(*clients.Client).Maintenance.PublicConfigurationsClient + subscriptionId := meta.(*clients.Client).Account.SubscriptionId ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - resp, err := client.List(ctx) + subId := commonids.NewSubscriptionID(subscriptionId) + resp, err := client.List(ctx, subId) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { return fmt.Errorf("no Public Maintenance Configurations were found") } return fmt.Errorf("retrieving Public Maintenance Configurations: %+v", err) @@ -131,36 +133,38 @@ func dataSourcePublicMaintenanceConfigurationsRead(d *pluginsdk.ResourceData, me locationFilter := azure.NormalizeLocation(d.Get("location").(string)) scopeFilter := d.Get("scope").(string) - if resp.Value != nil { - for _, maintenanceConfig := range *resp.Value { + if resp.Model != nil { + if resp.Model.Value != nil { + for _, maintenanceConfig := range *resp.Model.Value { - var configLocation, configRecurEvery, configScope string - if maintenanceConfig.Location != nil { - configLocation = azure.NormalizeLocation(*maintenanceConfig.Location) - } - if props := maintenanceConfig.ConfigurationProperties; props != nil { - if props.Window != nil && props.Window.RecurEvery != nil { - configRecurEvery = *props.Window.RecurEvery + var configLocation, configRecurEvery, configScope string + if maintenanceConfig.Location != nil { + configLocation = azure.NormalizeLocation(*maintenanceConfig.Location) } - if string(props.MaintenanceScope) != "" { - configScope = string(props.MaintenanceScope) + if props := maintenanceConfig.Properties; props != nil { + if props.MaintenanceWindow != nil && props.MaintenanceWindow.RecurEvery != nil { + configRecurEvery = *props.MaintenanceWindow.RecurEvery + } + + if props.MaintenanceScope != nil { + configScope = string(*props.MaintenanceScope) + } } - } - if locationFilter != "" && locationFilter != configLocation { - continue - } - if recurEveryFilter != "" && recurEveryFilter != configRecurEvery { - continue - } - if scopeFilter != "" && scopeFilter != configScope { - continue - } + if locationFilter != "" && locationFilter != configLocation { + continue + } + if recurEveryFilter != "" && recurEveryFilter != configRecurEvery { + continue + } + if scopeFilter != "" && scopeFilter != configScope { + continue + } - filteredPublicConfigs = append(filteredPublicConfigs, flattenPublicMaintenanceConfiguration(maintenanceConfig)) + filteredPublicConfigs = append(filteredPublicConfigs, flattenPublicMaintenanceConfiguration(maintenanceConfig)) + } } } - if len(filteredPublicConfigs) == 0 { return fmt.Errorf("no Public Maintenance Configurations were found") } @@ -173,7 +177,7 @@ func dataSourcePublicMaintenanceConfigurationsRead(d *pluginsdk.ResourceData, me return nil } -func flattenPublicMaintenanceConfiguration(config maintenance.Configuration) map[string]interface{} { +func flattenPublicMaintenanceConfiguration(config publicmaintenanceconfigurations.MaintenanceConfiguration) map[string]interface{} { output := make(map[string]interface{}) output["name"] = "" @@ -182,8 +186,8 @@ func flattenPublicMaintenanceConfiguration(config maintenance.Configuration) map } output["id"] = "" - if config.ID != nil { - output["id"] = *config.ID + if config.Id != nil { + output["id"] = *config.Id } output["location"] = "" @@ -191,24 +195,28 @@ func flattenPublicMaintenanceConfiguration(config maintenance.Configuration) map output["location"] = azure.NormalizeLocation(*config.Location) } - output["maintenance_scope"] = string(config.MaintenanceScope) - - var description, recurEvery, timeZone, duration string - if props := config.ConfigurationProperties; props != nil { + var description, recurEvery, timeZone, duration, scope string + if props := config.Properties; props != nil { if props.ExtensionProperties != nil { - if configDescription, ok := props.ExtensionProperties["description"]; ok { - description = *configDescription + extensionProperties := *props.ExtensionProperties + if configDescription, ok := extensionProperties["description"]; ok { + description = configDescription } } - if props.Window != nil { - if props.Window.RecurEvery != nil { - recurEvery = *props.Window.RecurEvery + + if config.Properties.MaintenanceScope != nil { + scope = string(*config.Properties.MaintenanceScope) + } + + if props.MaintenanceWindow != nil { + if props.MaintenanceWindow.RecurEvery != nil { + recurEvery = *props.MaintenanceWindow.RecurEvery } - if props.Window.TimeZone != nil { - timeZone = *props.Window.TimeZone + if props.MaintenanceWindow.TimeZone != nil { + timeZone = *props.MaintenanceWindow.TimeZone } - if props.Window.Duration != nil { - duration = *props.Window.Duration + if props.MaintenanceWindow.Duration != nil { + duration = *props.MaintenanceWindow.Duration } } } @@ -217,6 +225,7 @@ func flattenPublicMaintenanceConfiguration(config maintenance.Configuration) map output["recur_every"] = recurEvery output["time_zone"] = timeZone output["duration"] = duration + output["maintenance_scope"] = scope return output } diff --git a/internal/services/maintenance/resourceids.go b/internal/services/maintenance/resourceids.go deleted file mode 100644 index 359b0603e7f4..000000000000 --- a/internal/services/maintenance/resourceids.go +++ /dev/null @@ -1,4 +0,0 @@ -package maintenance - -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=MaintenanceConfiguration -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Maintenance/maintenanceConfigurations/maintenanceConfiguration1 -rewrite=true -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=PublicMaintenanceConfiguration -id=/subscriptions/12345678-1234-9876-4563-123456789012/providers/Microsoft.Maintenance/publicMaintenanceConfigurations/publicMaintenanceConfiguration1 diff --git a/internal/services/maintenance/transition.go b/internal/services/maintenance/transition.go new file mode 100644 index 000000000000..4ff4895f8431 --- /dev/null +++ b/internal/services/maintenance/transition.go @@ -0,0 +1,23 @@ +package maintenance + +import "github.com/hashicorp/terraform-provider-azurerm/utils" + +func expandTags(input map[string]interface{}) *map[string]string { + output := make(map[string]string) + for k, v := range input { + output[k] = v.(string) + } + return &output +} + +func flattenTags(input *map[string]string) map[string]*string { + output := make(map[string]*string) + + if input != nil { + for k, v := range *input { + output[k] = utils.String(v) + } + } + + return output +} diff --git a/internal/services/maintenance/validate/maintenance_configuration_id.go b/internal/services/maintenance/validate/maintenance_configuration_id.go deleted file mode 100644 index e4917c1f227b..000000000000 --- a/internal/services/maintenance/validate/maintenance_configuration_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/maintenance/parse" -) - -func MaintenanceConfigurationID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.MaintenanceConfigurationID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/maintenance/validate/maintenance_configuration_id_test.go b/internal/services/maintenance/validate/maintenance_configuration_id_test.go deleted file mode 100644 index f893d393070c..000000000000 --- a/internal/services/maintenance/validate/maintenance_configuration_id_test.go +++ /dev/null @@ -1,76 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestMaintenanceConfigurationID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - - { - // empty - Input: "", - Valid: false, - }, - - { - // missing SubscriptionId - Input: "/", - Valid: false, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Valid: false, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Valid: false, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Valid: false, - }, - - { - // missing Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Maintenance/", - Valid: false, - }, - - { - // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Maintenance/maintenanceConfigurations/", - Valid: false, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Maintenance/maintenanceConfigurations/maintenanceConfiguration1", - Valid: true, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.MAINTENANCE/MAINTENANCECONFIGURATIONS/MAINTENANCECONFIGURATION1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := MaintenanceConfigurationID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/maintenance/validate/public_maintenance_configuration_id.go b/internal/services/maintenance/validate/public_maintenance_configuration_id.go deleted file mode 100644 index 14898cb15959..000000000000 --- a/internal/services/maintenance/validate/public_maintenance_configuration_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/maintenance/parse" -) - -func PublicMaintenanceConfigurationID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.PublicMaintenanceConfigurationID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/maintenance/validate/public_maintenance_configuration_id_test.go b/internal/services/maintenance/validate/public_maintenance_configuration_id_test.go deleted file mode 100644 index b5df41d3362b..000000000000 --- a/internal/services/maintenance/validate/public_maintenance_configuration_id_test.go +++ /dev/null @@ -1,64 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestPublicMaintenanceConfigurationID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - - { - // empty - Input: "", - Valid: false, - }, - - { - // missing SubscriptionId - Input: "/", - Valid: false, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Valid: false, - }, - - { - // missing Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/providers/Microsoft.Maintenance/", - Valid: false, - }, - - { - // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/providers/Microsoft.Maintenance/publicMaintenanceConfigurations/", - Valid: false, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/providers/Microsoft.Maintenance/publicMaintenanceConfigurations/publicMaintenanceConfiguration1", - Valid: true, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/PROVIDERS/MICROSOFT.MAINTENANCE/PUBLICMAINTENANCECONFIGURATIONS/PUBLICMAINTENANCECONFIGURATION1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := PublicMaintenanceConfigurationID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/managementgroup/management_group_data_source.go b/internal/services/managementgroup/management_group_data_source.go index d69ec737f846..88b0de7ee328 100644 --- a/internal/services/managementgroup/management_group_data_source.go +++ b/internal/services/managementgroup/management_group_data_source.go @@ -44,10 +44,27 @@ func dataSourceManagementGroup() *pluginsdk.Resource { }, "subscription_ids": { - Type: pluginsdk.TypeSet, + Type: pluginsdk.TypeList, + Computed: true, + Elem: &pluginsdk.Schema{Type: pluginsdk.TypeString}, + }, + + "management_group_ids": { + Type: pluginsdk.TypeList, + Computed: true, + Elem: &pluginsdk.Schema{Type: pluginsdk.TypeString}, + }, + + "all_subscription_ids": { + Type: pluginsdk.TypeList, + Computed: true, + Elem: &pluginsdk.Schema{Type: pluginsdk.TypeString}, + }, + + "all_management_group_ids": { + Type: pluginsdk.TypeList, Computed: true, Elem: &pluginsdk.Schema{Type: pluginsdk.TypeString}, - Set: pluginsdk.HashString, }, }, } @@ -90,11 +107,29 @@ func dataSourceManagementGroupRead(d *pluginsdk.ResourceData, meta interface{}) if props := resp.Properties; props != nil { d.Set("display_name", props.DisplayName) - subscriptionIds, err := flattenManagementGroupDataSourceSubscriptionIds(props.Children) - if err != nil { - return fmt.Errorf("flattening `subscription_ids`: %+v", err) + subscriptionIds := []interface{}{} + mgmtgroupIds := []interface{}{} + if err := flattenManagementGroupDataSourceChildren(&subscriptionIds, &mgmtgroupIds, props.Children, false); err != nil { + return fmt.Errorf("flattening direct children resources: %+v", err) + } + if err := d.Set("subscription_ids", subscriptionIds); err != nil { + return fmt.Errorf("setting `subscription_ids`: %v", err) + } + if err := d.Set("management_group_ids", mgmtgroupIds); err != nil { + return fmt.Errorf("setting `management_group_ids`: %v", err) + } + + subscriptionIds = []interface{}{} + mgmtgroupIds = []interface{}{} + if err := flattenManagementGroupDataSourceChildren(&subscriptionIds, &mgmtgroupIds, props.Children, true); err != nil { + return fmt.Errorf("flattening all children resources: %+v", err) + } + if err := d.Set("all_subscription_ids", subscriptionIds); err != nil { + return fmt.Errorf("setting `all_subscription_ids`: %v", err) + } + if err := d.Set("all_management_group_ids", mgmtgroupIds); err != nil { + return fmt.Errorf("setting `all_management_group_ids`: %v", err) } - d.Set("subscription_ids", subscriptionIds) parentId := "" if details := props.Details; details != nil { @@ -141,26 +176,37 @@ func getManagementGroupNameByDisplayName(ctx context.Context, client *management return results[0], nil } -func flattenManagementGroupDataSourceSubscriptionIds(input *[]managementgroups.ChildInfo) (*pluginsdk.Set, error) { - subscriptionIds := &pluginsdk.Set{F: pluginsdk.HashString} +func flattenManagementGroupDataSourceChildren(subscriptionIds, mgmtgroupIds *[]interface{}, input *[]managementgroups.ChildInfo, recursive bool) error { if input == nil { - return subscriptionIds, nil + return nil } for _, child := range *input { if child.ID == nil { continue } - - id, err := parseManagementGroupSubscriptionID(*child.ID) - if err != nil { - return nil, fmt.Errorf("Unable to parse child Subscription ID %+v", err) + switch child.Type { + case managementgroups.Type1MicrosoftManagementmanagementGroups: + id, err := parse.ManagementGroupID(*child.ID) + if err != nil { + return fmt.Errorf("Unable to parse child Management Group ID %+v", err) + } + *mgmtgroupIds = append(*mgmtgroupIds, id.ID()) + case managementgroups.Type1Subscriptions: + id, err := parseManagementGroupSubscriptionID(*child.ID) + if err != nil { + return fmt.Errorf("Unable to parse child Subscription ID %+v", err) + } + *subscriptionIds = append(*subscriptionIds, id.subscriptionId) + default: + continue } - - if id != nil { - subscriptionIds.Add(id.subscriptionId) + if recursive { + if err := flattenManagementGroupDataSourceChildren(subscriptionIds, mgmtgroupIds, child.Children, recursive); err != nil { + return err + } } } - return subscriptionIds, nil + return nil } diff --git a/internal/services/managementgroup/management_group_data_source_test.go b/internal/services/managementgroup/management_group_data_source_test.go index 5a2ffd3b5e5c..7d041eb88e39 100644 --- a/internal/services/managementgroup/management_group_data_source_test.go +++ b/internal/services/managementgroup/management_group_data_source_test.go @@ -40,6 +40,22 @@ func TestAccManagementGroupDataSource_basicByDisplayName(t *testing.T) { }) } +func TestAccManagementGroupDataSource_nestedManagmentGroup(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_management_group", "test") + r := ManagementGroupDataSource{} + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: r.nestedManagementGroup(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("display_name").HasValue(fmt.Sprintf("acctest Management Group %d", data.RandomInteger)), + check.That(data.ResourceName).Key("management_group_ids.#").HasValue("1"), + check.That(data.ResourceName).Key("all_management_group_ids.#").HasValue("2"), + ), + }, + }) +} + func (ManagementGroupDataSource) basicByName(data acceptance.TestData) string { return fmt.Sprintf(` provider "azurerm" { @@ -71,3 +87,30 @@ data "azurerm_management_group" "test" { } `, data.RandomInteger) } + +func (ManagementGroupDataSource) nestedManagementGroup(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_management_group" "test" { + display_name = "acctest Management Group %[1]d" +} + +resource "azurerm_management_group" "child" { + display_name = "acctest child Management Group %[1]d" + parent_management_group_id = azurerm_management_group.test.id +} + +resource "azurerm_management_group" "grand_child" { + display_name = "acctest grand child Management Group %[1]d" + parent_management_group_id = azurerm_management_group.child.id +} + +data "azurerm_management_group" "test" { + name = azurerm_management_group.test.name + depends_on = [azurerm_management_group.grand_child] +} +`, data.RandomInteger) +} diff --git a/internal/services/mariadb/client/client.go b/internal/services/mariadb/client/client.go index 0e1cb2344c0d..deba55b33098 100644 --- a/internal/services/mariadb/client/client.go +++ b/internal/services/mariadb/client/client.go @@ -1,32 +1,36 @@ package client import ( - "github.com/Azure/azure-sdk-for-go/services/mariadb/mgmt/2018-06-01/mariadb" + "github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/configurations" + "github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/databases" + "github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/firewallrules" + "github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers" + "github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/virtualnetworkrules" "github.com/hashicorp/terraform-provider-azurerm/internal/common" ) type Client struct { - ConfigurationsClient *mariadb.ConfigurationsClient - DatabasesClient *mariadb.DatabasesClient - FirewallRulesClient *mariadb.FirewallRulesClient - ServersClient *mariadb.ServersClient - VirtualNetworkRulesClient *mariadb.VirtualNetworkRulesClient + ConfigurationsClient *configurations.ConfigurationsClient + DatabasesClient *databases.DatabasesClient + FirewallRulesClient *firewallrules.FirewallRulesClient + ServersClient *servers.ServersClient + VirtualNetworkRulesClient *virtualnetworkrules.VirtualNetworkRulesClient } func NewClient(o *common.ClientOptions) *Client { - configurationsClient := mariadb.NewConfigurationsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + configurationsClient := configurations.NewConfigurationsClientWithBaseURI(o.ResourceManagerEndpoint) o.ConfigureClient(&configurationsClient.Client, o.ResourceManagerAuthorizer) - DatabasesClient := mariadb.NewDatabasesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + DatabasesClient := databases.NewDatabasesClientWithBaseURI(o.ResourceManagerEndpoint) o.ConfigureClient(&DatabasesClient.Client, o.ResourceManagerAuthorizer) - FirewallRulesClient := mariadb.NewFirewallRulesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + FirewallRulesClient := firewallrules.NewFirewallRulesClientWithBaseURI(o.ResourceManagerEndpoint) o.ConfigureClient(&FirewallRulesClient.Client, o.ResourceManagerAuthorizer) - ServersClient := mariadb.NewServersClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + ServersClient := servers.NewServersClientWithBaseURI(o.ResourceManagerEndpoint) o.ConfigureClient(&ServersClient.Client, o.ResourceManagerAuthorizer) - VirtualNetworkRulesClient := mariadb.NewVirtualNetworkRulesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + VirtualNetworkRulesClient := virtualnetworkrules.NewVirtualNetworkRulesClientWithBaseURI(o.ResourceManagerEndpoint) o.ConfigureClient(&VirtualNetworkRulesClient.Client, o.ResourceManagerAuthorizer) return &Client{ diff --git a/internal/services/mariadb/mariadb_configuration_resource.go b/internal/services/mariadb/mariadb_configuration_resource.go index abedc306decc..f16ad1325046 100644 --- a/internal/services/mariadb/mariadb_configuration_resource.go +++ b/internal/services/mariadb/mariadb_configuration_resource.go @@ -5,10 +5,10 @@ import ( "log" "time" - "github.com/Azure/azure-sdk-for-go/services/mariadb/mgmt/2018-06-01/mariadb" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/configurations" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/mariadb/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/mariadb/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" @@ -22,7 +22,7 @@ func resourceMariaDbConfiguration() *pluginsdk.Resource { Read: resourceMariaDbConfigurationRead, Delete: resourceMariaDbConfigurationDelete, Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - _, err := parse.MariaDBConfigurationID(id) + _, err := configurations.ParseConfigurationID(id) return err }), @@ -65,23 +65,17 @@ func resourceMariaDbConfigurationCreateUpdate(d *pluginsdk.ResourceData, meta in ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - log.Printf("[INFO] preparing arguments for AzureRM MariaDb Configuration creation.") - id := parse.NewMariaDBConfigurationID(subscriptionId, d.Get("resource_group_name").(string), d.Get("server_name").(string), d.Get("name").(string)) + id := configurations.NewConfigurationID(subscriptionId, d.Get("resource_group_name").(string), d.Get("server_name").(string), d.Get("name").(string)) value := d.Get("value").(string) - properties := mariadb.Configuration{ - ConfigurationProperties: &mariadb.ConfigurationProperties{ + properties := configurations.Configuration{ + Properties: &configurations.ConfigurationProperties{ Value: utils.String(value), }, } - future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.ServerName, id.ConfigurationName, properties) - if err != nil { - return fmt.Errorf("issuing create/update request for %s: %v", id, err) - } - - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for create/update of %s: %v", id, err) + if err := client.CreateOrUpdateThenPoll(ctx, id, properties); err != nil { + return fmt.Errorf("creating/updating %s: %+v", id, err) } d.SetId(id.ID()) @@ -94,26 +88,35 @@ func resourceMariaDbConfigurationRead(d *pluginsdk.ResourceData, meta interface{ ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.MariaDBConfigurationID(d.Id()) + id, err := configurations.ParseConfigurationID(d.Id()) if err != nil { return err } - resp, err := client.Get(ctx, id.ResourceGroup, id.ServerName, id.ConfigurationName) + resp, err := client.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { log.Printf("[WARN] %s was not found", *id) d.SetId("") return nil } - return fmt.Errorf("making Read request on %s: %+v", *id, err) + return fmt.Errorf("retrieving %s: %+v", *id, err) } d.Set("name", id.ConfigurationName) d.Set("server_name", id.ServerName) - d.Set("resource_group_name", id.ResourceGroup) - d.Set("value", resp.ConfigurationProperties.Value) + d.Set("resource_group_name", id.ResourceGroupName) + + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + value := "" + if v := props.Value; v != nil { + value = *v + } + d.Set("value", value) + } + } return nil } @@ -123,28 +126,37 @@ func resourceMariaDbConfigurationDelete(d *pluginsdk.ResourceData, meta interfac ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.MariaDBConfigurationID(d.Id()) + id, err := configurations.ParseConfigurationID(d.Id()) if err != nil { return err } // "delete" = resetting this to the default value - resp, err := client.Get(ctx, id.ResourceGroup, id.ServerName, id.ConfigurationName) + resp, err := client.Get(ctx, *id) if err != nil { return fmt.Errorf("retrieving %s: %+v", *id, err) } - properties := mariadb.Configuration{ - ConfigurationProperties: &mariadb.ConfigurationProperties{ + defaultValue := "" + + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + if v := props.DefaultValue; v != nil { + defaultValue = *v + } + } + } + + properties := configurations.Configuration{ + Properties: &configurations.ConfigurationProperties{ // we can alternatively set `source: "system-default"` - Value: resp.DefaultValue, + Value: &defaultValue, }, } - future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.ServerName, id.ConfigurationName, properties) - if err != nil { - return err + if err := client.CreateOrUpdateThenPoll(ctx, *id, properties); err != nil { + return fmt.Errorf("deleting %s: %+v", id, err) } - return future.WaitForCompletionRef(ctx, client.Client) + return nil } diff --git a/internal/services/mariadb/mariadb_configuration_resource_test.go b/internal/services/mariadb/mariadb_configuration_resource_test.go index b6ec842f3a80..70af8fccc732 100644 --- a/internal/services/mariadb/mariadb_configuration_resource_test.go +++ b/internal/services/mariadb/mariadb_configuration_resource_test.go @@ -5,9 +5,10 @@ import ( "fmt" "testing" + "github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/configurations" + "github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/mariadb/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -84,39 +85,41 @@ func TestAccMariaDbConfiguration_logSlowAdminStatements(t *testing.T) { } func (MariaDbConfigurationResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.MariaDBConfigurationID(state.ID) + id, err := configurations.ParseConfigurationID(state.ID) if err != nil { return nil, err } - resp, err := clients.MariaDB.ConfigurationsClient.Get(ctx, id.ResourceGroup, id.ServerName, id.ConfigurationName) + resp, err := clients.MariaDB.ConfigurationsClient.Get(ctx, *id) if err != nil { return nil, fmt.Errorf("retrieving %s: %v", *id, err) } - return utils.Bool(resp.ConfigurationProperties != nil), nil + return utils.Bool(resp.Model != nil), nil } func checkValueIs(value string) acceptance.ClientCheckFunc { return func(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) error { - id, err := parse.MariaDBConfigurationID(state.ID) + id, err := configurations.ParseConfigurationID(state.ID) if err != nil { return err } - resp, err := clients.MariaDB.ConfigurationsClient.Get(ctx, id.ResourceGroup, id.ServerName, id.ConfigurationName) + resp, err := clients.MariaDB.ConfigurationsClient.Get(ctx, *id) if err != nil { return fmt.Errorf("retrieving %s: %v", *id, err) } - if resp.Value == nil { - return fmt.Errorf("%s Value is nil", *id) - } - - actualValue := *resp.Value - - if value != actualValue { - return fmt.Errorf("%s Value (%s) != expected (%s)", *id, actualValue, value) + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + if v := props.Value; v != nil { + if value != *v { + return fmt.Errorf("%s Value (%s) != expected (%s)", *id, *v, value) + } + } else { + return fmt.Errorf("%s Value is nil", *id) + } + } } return nil @@ -125,28 +128,41 @@ func checkValueIs(value string) acceptance.ClientCheckFunc { func checkValueIsReset(configurationName string) acceptance.ClientCheckFunc { return func(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) error { - id, err := parse.ServerID(state.ID) + serverId, err := servers.ParseServerID(state.ID) if err != nil { return err } - resp, err := clients.MariaDB.ConfigurationsClient.Get(ctx, id.ResourceGroup, id.Name, configurationName) + id := configurations.NewConfigurationID(serverId.SubscriptionId, serverId.ResourceGroupName, serverId.ServerName, configurationName) + + resp, err := clients.MariaDB.ConfigurationsClient.Get(ctx, id) if err != nil { - return fmt.Errorf("retrieving MariaDB Configuration %q (Server %q / Resource Group %q): %v", configurationName, id.Name, id.ResourceGroup, err) + return fmt.Errorf("retrieving %s: %v", id, err) + } + + actualValue := "" + defaultValue := "" + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + if v := props.Value; v != nil { + actualValue = *v + } + if v := props.DefaultValue; v != nil { + defaultValue = *v + } + } } - if resp.Value == nil { - return fmt.Errorf("MariaDB Configuration %q (Server %q / Resource Group %q) Value is nil", configurationName, id.Name, id.ResourceGroup) + if actualValue == "" { + return fmt.Errorf("%s Value is nil", id) } - if resp.DefaultValue == nil { - return fmt.Errorf("MariaDB Configuration %q (Server %q / Resource Group %q) Default Value is nil", configurationName, id.Name, id.ResourceGroup) + if defaultValue == "" { + return fmt.Errorf("%s Default Value is nil", id) } - actualValue := *resp.Value - defaultValue := *resp.DefaultValue if defaultValue != actualValue { - return fmt.Errorf("MariaDB Configuration %q (Server %q / Resource Group %q) Value (%s) != Default (%s)", configurationName, id.Name, id.ResourceGroup, actualValue, defaultValue) + return fmt.Errorf("%s Value (%s) != Default (%s)", id, actualValue, defaultValue) } return nil diff --git a/internal/services/mariadb/mariadb_database_resource.go b/internal/services/mariadb/mariadb_database_resource.go index 4c3226a63ecf..391a05b861df 100644 --- a/internal/services/mariadb/mariadb_database_resource.go +++ b/internal/services/mariadb/mariadb_database_resource.go @@ -6,11 +6,11 @@ import ( "regexp" "time" - "github.com/Azure/azure-sdk-for-go/services/mariadb/mgmt/2018-06-01/mariadb" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/databases" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/mariadb/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/mariadb/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" @@ -25,7 +25,7 @@ func resourceMariaDbDatabase() *pluginsdk.Resource { Delete: resourceMariaDbDatabaseDelete, Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - _, err := parse.MariaDBDatabaseID(id) + _, err := databases.ParseDatabaseID(id) return err }), @@ -87,17 +87,17 @@ func resourceMariaDbDatabaseCreateUpdate(d *pluginsdk.ResourceData, meta interfa log.Printf("[INFO] preparing arguments for AzureRM MariaDB database creation") - id := parse.NewMariaDBDatabaseID(subscriptionId, d.Get("resource_group_name").(string), d.Get("server_name").(string), d.Get("name").(string)) + id := databases.NewDatabaseID(subscriptionId, d.Get("resource_group_name").(string), d.Get("server_name").(string), d.Get("name").(string)) if d.IsNewResource() { - existing, err := client.Get(ctx, id.ResourceGroup, id.ServerName, id.DatabaseName) + existing, err := client.Get(ctx, id) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return fmt.Errorf("checking for presence of existing %s: %s", id, err) } } - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return tf.ImportAsExistsError("azurerm_mariadb_database", id.ID()) } } @@ -105,22 +105,17 @@ func resourceMariaDbDatabaseCreateUpdate(d *pluginsdk.ResourceData, meta interfa charset := d.Get("charset").(string) collation := d.Get("collation").(string) - properties := mariadb.Database{ - DatabaseProperties: &mariadb.DatabaseProperties{ + properties := databases.Database{ + Properties: &databases.DatabaseProperties{ Charset: utils.String(charset), Collation: utils.String(collation), }, } - future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.ServerName, id.DatabaseName, properties) - if err != nil { + if err := client.CreateOrUpdateThenPoll(ctx, id, properties); err != nil { return fmt.Errorf("creating %s: %+v", id, err) } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for completion of %s: %+v", id, err) - } - d.SetId(id.ID()) return resourceMariaDbDatabaseRead(d, meta) @@ -131,31 +126,43 @@ func resourceMariaDbDatabaseRead(d *pluginsdk.ResourceData, meta interface{}) er ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.MariaDBDatabaseID(d.Id()) + id, err := databases.ParseDatabaseID(d.Id()) if err != nil { - return fmt.Errorf("cannot parse MariaDB database %q ID:\n%+v", d.Id(), err) + return err } - resp, err := client.Get(ctx, id.ResourceGroup, id.ServerName, id.DatabaseName) + resp, err := client.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { log.Printf("[WARN] %s was not found", *id) d.SetId("") return nil } - return fmt.Errorf("making read request on %s:\n%+v", *id, err) + return fmt.Errorf("retrieving %s: %+v", *id, err) } d.Set("name", id.DatabaseName) - d.Set("resource_group_name", id.ResourceGroup) + d.Set("resource_group_name", id.ResourceGroupName) d.Set("server_name", id.ServerName) - if properties := resp.DatabaseProperties; properties != nil { - d.Set("charset", properties.Charset) - d.Set("collation", properties.Collation) + charset := "" + collation := "" + + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + if v := props.Charset; v != nil { + charset = *v + } + if v := props.Collation; v != nil { + collation = *v + } + } } + d.Set("charset", charset) + d.Set("collation", collation) + return nil } @@ -164,18 +171,13 @@ func resourceMariaDbDatabaseDelete(d *pluginsdk.ResourceData, meta interface{}) ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.MariaDBDatabaseID(d.Id()) - if err != nil { - return fmt.Errorf("cannot parse MariaDB database %q ID:\n%+v", d.Id(), err) - } - - future, err := client.Delete(ctx, id.ResourceGroup, id.ServerName, id.DatabaseName) + id, err := databases.ParseDatabaseID(d.Id()) if err != nil { - return fmt.Errorf("making delete request on %s:\n%+v", *id, err) + return err } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for deletion of %s:\n%+v", *id, err) + if err := client.DeleteThenPoll(ctx, *id); err != nil { + return fmt.Errorf("deleting %s: %+v", *id, err) } return nil diff --git a/internal/services/mariadb/mariadb_database_resource_test.go b/internal/services/mariadb/mariadb_database_resource_test.go index 1c67f2b7fbed..6a124f3a00a6 100644 --- a/internal/services/mariadb/mariadb_database_resource_test.go +++ b/internal/services/mariadb/mariadb_database_resource_test.go @@ -5,10 +5,10 @@ import ( "fmt" "testing" + "github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/databases" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/mariadb/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -51,17 +51,17 @@ func TestAccMariaDbDatabase_requiresImport(t *testing.T) { } func (MariaDbDatabaseResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.MariaDBDatabaseID(state.ID) + id, err := databases.ParseDatabaseID(state.ID) if err != nil { return nil, err } - resp, err := clients.MariaDB.DatabasesClient.Get(ctx, id.ResourceGroup, id.ServerName, id.DatabaseName) + resp, err := clients.MariaDB.DatabasesClient.Get(ctx, *id) if err != nil { return nil, fmt.Errorf("retrieving %s: %v", *id, err) } - return utils.Bool(resp.DatabaseProperties != nil), nil + return utils.Bool(resp.Model != nil), nil } func (MariaDbDatabaseResource) basic(data acceptance.TestData) string { diff --git a/internal/services/mariadb/mariadb_firewall_rule_resource.go b/internal/services/mariadb/mariadb_firewall_rule_resource.go index 50a217f36203..14a9a8fc64bb 100644 --- a/internal/services/mariadb/mariadb_firewall_rule_resource.go +++ b/internal/services/mariadb/mariadb_firewall_rule_resource.go @@ -5,16 +5,15 @@ import ( "log" "time" - "github.com/Azure/azure-sdk-for-go/services/mariadb/mgmt/2018-06-01/mariadb" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/firewallrules" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" azValidate "github.com/hashicorp/terraform-provider-azurerm/helpers/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/mariadb/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/mariadb/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" - "github.com/hashicorp/terraform-provider-azurerm/utils" ) func resourceArmMariaDBFirewallRule() *pluginsdk.Resource { @@ -24,7 +23,7 @@ func resourceArmMariaDBFirewallRule() *pluginsdk.Resource { Update: resourceArmMariaDBFirewallRuleCreateUpdate, Delete: resourceArmMariaDBFirewallRuleDelete, Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - _, err := parse.MariaDBFirewallRuleID(id) + _, err := firewallrules.ParseFirewallRuleID(id) return err }), @@ -75,37 +74,32 @@ func resourceArmMariaDBFirewallRuleCreateUpdate(d *pluginsdk.ResourceData, meta log.Printf("[INFO] preparing arguments for AzureRM MariaDB Firewall Rule creation.") - id := parse.NewMariaDBFirewallRuleID(subscriptionId, d.Get("resource_group_name").(string), d.Get("server_name").(string), d.Get("name").(string)) + id := firewallrules.NewFirewallRuleID(subscriptionId, d.Get("resource_group_name").(string), d.Get("server_name").(string), d.Get("name").(string)) startIPAddress := d.Get("start_ip_address").(string) endIPAddress := d.Get("end_ip_address").(string) if d.IsNewResource() { - existing, err := client.Get(ctx, id.ResourceGroup, id.ServerName, id.FirewallRuleName) + existing, err := client.Get(ctx, id) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return fmt.Errorf("checking for presence of existing %s: %v", id, err) } } - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return tf.ImportAsExistsError("azurerm_mariadb_firewall_rule", id.ID()) } } - properties := mariadb.FirewallRule{ - FirewallRuleProperties: &mariadb.FirewallRuleProperties{ - StartIPAddress: utils.String(startIPAddress), - EndIPAddress: utils.String(endIPAddress), + properties := firewallrules.FirewallRule{ + Properties: firewallrules.FirewallRuleProperties{ + StartIPAddress: startIPAddress, + EndIPAddress: endIPAddress, }, } - future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.ServerName, id.FirewallRuleName, properties) - if err != nil { - return fmt.Errorf("issuing create/update request for %s: %v", id, err) - } - - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting on create/update future for %s: %v", id, err) + if err := client.CreateOrUpdateThenPoll(ctx, id, properties); err != nil { + return fmt.Errorf("creating/updated %s: %v", id, err) } d.SetId(id.ID()) @@ -118,25 +112,28 @@ func resourceArmMariaDBFirewallRuleRead(d *pluginsdk.ResourceData, meta interfac ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.MariaDBFirewallRuleID(d.Id()) + id, err := firewallrules.ParseFirewallRuleID(d.Id()) if err != nil { return err } - resp, err := client.Get(ctx, id.ResourceGroup, id.ServerName, id.FirewallRuleName) + resp, err := client.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { d.SetId("") return nil } - return fmt.Errorf("making Read request on %s: %+v", *id, err) + return fmt.Errorf("retrieving %s: %+v", *id, err) } d.Set("name", id.FirewallRuleName) - d.Set("resource_group_name", id.ResourceGroup) + d.Set("resource_group_name", id.ResourceGroupName) d.Set("server_name", id.ServerName) - d.Set("start_ip_address", resp.StartIPAddress) - d.Set("end_ip_address", resp.EndIPAddress) + + if model := resp.Model; model != nil { + d.Set("start_ip_address", model.Properties.StartIPAddress) + d.Set("end_ip_address", model.Properties.EndIPAddress) + } return nil } @@ -146,15 +143,14 @@ func resourceArmMariaDBFirewallRuleDelete(d *pluginsdk.ResourceData, meta interf ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.MariaDBFirewallRuleID(d.Id()) + id, err := firewallrules.ParseFirewallRuleID(d.Id()) if err != nil { return err } - future, err := client.Delete(ctx, id.ResourceGroup, id.ServerName, id.FirewallRuleName) - if err != nil { - return err + if err := client.DeleteThenPoll(ctx, *id); err != nil { + return fmt.Errorf("deleting %s: %+v", *id, err) } - return future.WaitForCompletionRef(ctx, client.Client) + return nil } diff --git a/internal/services/mariadb/mariadb_firewall_rule_resource_test.go b/internal/services/mariadb/mariadb_firewall_rule_resource_test.go index b0e1b50c8c61..0dcfa0c465dd 100644 --- a/internal/services/mariadb/mariadb_firewall_rule_resource_test.go +++ b/internal/services/mariadb/mariadb_firewall_rule_resource_test.go @@ -5,10 +5,10 @@ import ( "fmt" "testing" + "github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/firewallrules" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/mariadb/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -49,17 +49,17 @@ func TestAccMariaDbFirewallRule_requiresImport(t *testing.T) { } func (MariaDbFirewallRuleResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.MariaDBFirewallRuleID(state.ID) + id, err := firewallrules.ParseFirewallRuleID(state.ID) if err != nil { return nil, err } - resp, err := clients.MariaDB.FirewallRulesClient.Get(ctx, id.ResourceGroup, id.ServerName, id.FirewallRuleName) + resp, err := clients.MariaDB.FirewallRulesClient.Get(ctx, *id) if err != nil { return nil, fmt.Errorf("retrieving %s: %v", *id, err) } - return utils.Bool(resp.FirewallRuleProperties != nil), nil + return utils.Bool(resp.Model != nil), nil } func (MariaDbFirewallRuleResource) basic(data acceptance.TestData) string { diff --git a/internal/services/mariadb/mariadb_server_data_source.go b/internal/services/mariadb/mariadb_server_data_source.go index 287aef2f68e1..180c47d9f7c3 100644 --- a/internal/services/mariadb/mariadb_server_data_source.go +++ b/internal/services/mariadb/mariadb_server_data_source.go @@ -5,15 +5,15 @@ import ( "regexp" "time" + "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/mariadb/parse" - "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" - "github.com/hashicorp/terraform-provider-azurerm/utils" ) func dataSourceMariaDbServer() *pluginsdk.Resource { @@ -91,7 +91,7 @@ func dataSourceMariaDbServer() *pluginsdk.Resource { Computed: true, }, - "tags": tags.SchemaDataSource(), + "tags": commonschema.TagsDataSource(), }, } } @@ -102,10 +102,10 @@ func dataSourceMariaDbServerRead(d *pluginsdk.ResourceData, meta interface{}) er ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id := parse.NewServerID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) - resp, err := client.Get(ctx, id.ResourceGroup, id.Name) + id := servers.NewServerID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) + resp, err := client.Get(ctx, id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { return fmt.Errorf("%s was not found", id) } @@ -113,18 +113,45 @@ func dataSourceMariaDbServerRead(d *pluginsdk.ResourceData, meta interface{}) er } d.SetId(id.ID()) - d.Set("name", id.Name) - d.Set("resource_group_name", id.ResourceGroup) - d.Set("location", location.NormalizeNilable(resp.Location)) - if sku := resp.Sku; sku != nil { - d.Set("sku_name", sku.Name) - } + d.Set("name", id.ServerName) + d.Set("resource_group_name", id.ResourceGroupName) + + if model := resp.Model; model != nil { + d.Set("location", location.Normalize(model.Location)) + + if sku := model.Sku; sku != nil { + d.Set("sku_name", sku.Name) + } - if props := resp.ServerProperties; props != nil { - d.Set("administrator_login", props.AdministratorLogin) - d.Set("fqdn", props.FullyQualifiedDomainName) - d.Set("ssl_enforcement", string(props.SslEnforcement)) - d.Set("version", string(props.Version)) + if props := model.Properties; props != nil { + adminLogin := "" + if v := props.AdministratorLogin; v != nil { + adminLogin = *v + } + + fqdn := "" + if v := props.FullyQualifiedDomainName; v != nil { + fqdn = *v + } + + sslEnforcement := "" + if v := props.SslEnforcement; v != nil { + sslEnforcement = string(*v) + } + + version := "" + if v := props.Version; v != nil { + version = string(*v) + } + + d.Set("administrator_login", adminLogin) + d.Set("fqdn", fqdn) + d.Set("ssl_enforcement", sslEnforcement) + d.Set("version", version) + } + + return tags.FlattenAndSet(d, model.Tags) } - return tags.FlattenAndSet(d, resp.Tags) + + return nil } diff --git a/internal/services/mariadb/mariadb_server_resource.go b/internal/services/mariadb/mariadb_server_resource.go index 3f31eee1774e..424e5f58cf7b 100644 --- a/internal/services/mariadb/mariadb_server_resource.go +++ b/internal/services/mariadb/mariadb_server_resource.go @@ -8,14 +8,14 @@ import ( "strings" "time" - "github.com/Azure/azure-sdk-for-go/services/mariadb/mgmt/2018-06-01/mariadb" - "github.com/Azure/go-autorest/autorest/date" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/mariadb/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/mariadb/validate" - "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" @@ -30,7 +30,7 @@ func resourceMariaDbServer() *pluginsdk.Resource { Delete: resourceMariaDbServerDelete, Importer: pluginsdk.ImporterValidatingResourceIdThen(func(id string) error { - _, err := parse.ServerID(id) + _, err := servers.ParseServerID(id) return err }, func(ctx context.Context, d *pluginsdk.ResourceData, meta interface{}) ([]*pluginsdk.ResourceData, error) { d.Set("create_mode", "Default") @@ -42,7 +42,7 @@ func resourceMariaDbServer() *pluginsdk.Resource { }), Timeouts: &pluginsdk.ResourceTimeout{ - Create: pluginsdk.DefaultTimeout(60 * time.Minute), + Create: pluginsdk.DefaultTimeout(90 * time.Minute), Read: pluginsdk.DefaultTimeout(5 * time.Minute), Update: pluginsdk.DefaultTimeout(60 * time.Minute), Delete: pluginsdk.DefaultTimeout(60 * time.Minute), @@ -85,19 +85,19 @@ func resourceMariaDbServer() *pluginsdk.Resource { "create_mode": { Type: pluginsdk.TypeString, Optional: true, - Default: string(mariadb.CreateModeDefault), + Default: string(servers.CreateModeDefault), ValidateFunc: validation.StringInSlice([]string{ - string(mariadb.CreateModeDefault), - string(mariadb.CreateModeGeoRestore), - string(mariadb.CreateModePointInTimeRestore), - string(mariadb.CreateModeReplica), + string(servers.CreateModeDefault), + string(servers.CreateModeGeoRestore), + string(servers.CreateModePointInTimeRestore), + string(servers.CreateModeReplica), }, false), }, "creation_source_server_id": { Type: pluginsdk.TypeString, Optional: true, - ValidateFunc: validate.ServerID, + ValidateFunc: servers.ValidateServerID, }, "fqdn": { @@ -160,7 +160,7 @@ func resourceMariaDbServer() *pluginsdk.Resource { ), }, - "tags": tags.Schema(), + "tags": commonschema.Tags(), "version": { Type: pluginsdk.TypeString, @@ -181,45 +181,45 @@ func resourceMariaDbServerCreate(d *pluginsdk.ResourceData, meta interface{}) er ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - id := parse.NewServerID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) + id := servers.NewServerID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) if d.IsNewResource() { - existing, err := client.Get(ctx, id.ResourceGroup, id.Name) + existing, err := client.Get(ctx, id) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return fmt.Errorf("checking for presence of existing %s: %+v", id, err) } } - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return tf.ImportAsExistsError("azurerm_mariadb_server", id.ID()) } } location := azure.NormalizeLocation(d.Get("location").(string)) - mode := mariadb.CreateMode(d.Get("create_mode").(string)) + mode := servers.CreateMode(d.Get("create_mode").(string)) source := d.Get("creation_source_server_id").(string) - version := mariadb.ServerVersion(d.Get("version").(string)) + version := servers.ServerVersion(d.Get("version").(string)) sku, err := expandServerSkuName(d.Get("sku_name").(string)) if err != nil { return fmt.Errorf("expanding `sku_name`: %+v", err) } - publicAccess := mariadb.PublicNetworkAccessEnumEnabled + publicAccess := servers.PublicNetworkAccessEnumEnabled if v := d.Get("public_network_access_enabled"); !v.(bool) { - publicAccess = mariadb.PublicNetworkAccessEnumDisabled + publicAccess = servers.PublicNetworkAccessEnumDisabled } - ssl := mariadb.SslEnforcementEnumEnabled + ssl := servers.SslEnforcementEnumEnabled if v := d.Get("ssl_enforcement_enabled").(bool); !v { - ssl = mariadb.SslEnforcementEnumDisabled + ssl = servers.SslEnforcementEnumDisabled } storage := expandMariaDbStorageProfile(d) - var props mariadb.BasicServerPropertiesForCreate + var props servers.ServerPropertiesForCreate switch mode { - case mariadb.CreateModeDefault: + case servers.CreateModeDefault: admin := d.Get("administrator_login").(string) pass := d.Get("administrator_login_password").(string) @@ -234,68 +234,57 @@ func resourceMariaDbServerCreate(d *pluginsdk.ResourceData, meta interface{}) er return fmt.Errorf("`restore_point_in_time` cannot be set when `create_mode` is `default`") } - props = &mariadb.ServerPropertiesForDefaultCreate{ - AdministratorLogin: &admin, - AdministratorLoginPassword: &pass, - CreateMode: mode, - PublicNetworkAccess: publicAccess, - SslEnforcement: ssl, + props = servers.ServerPropertiesForDefaultCreate{ + AdministratorLogin: admin, + AdministratorLoginPassword: pass, + PublicNetworkAccess: &publicAccess, + SslEnforcement: &ssl, StorageProfile: storage, - Version: version, + Version: &version, } - case mariadb.CreateModePointInTimeRestore: + + case servers.CreateModePointInTimeRestore: v, ok := d.GetOk("restore_point_in_time") if !ok || v.(string) == "" { return fmt.Errorf("restore_point_in_time must be set when create_mode is PointInTimeRestore") } - time, _ := time.Parse(time.RFC3339, v.(string)) // should be validated by the schema - props = &mariadb.ServerPropertiesForRestore{ - CreateMode: mode, - SourceServerID: &source, - RestorePointInTime: &date.Time{ - Time: time, - }, - PublicNetworkAccess: publicAccess, - SslEnforcement: ssl, + props = &servers.ServerPropertiesForRestore{ + SourceServerId: source, + RestorePointInTime: v.(string), + PublicNetworkAccess: &publicAccess, + SslEnforcement: &ssl, StorageProfile: storage, - Version: version, + Version: &version, } - case mariadb.CreateModeGeoRestore: - props = &mariadb.ServerPropertiesForGeoRestore{ - CreateMode: mode, - SourceServerID: &source, - PublicNetworkAccess: publicAccess, - SslEnforcement: ssl, + case servers.CreateModeGeoRestore: + props = &servers.ServerPropertiesForGeoRestore{ + SourceServerId: source, + PublicNetworkAccess: &publicAccess, + SslEnforcement: &ssl, StorageProfile: storage, - Version: version, + Version: &version, } - case mariadb.CreateModeReplica: - props = &mariadb.ServerPropertiesForReplica{ - CreateMode: mode, - SourceServerID: &source, - PublicNetworkAccess: publicAccess, - SslEnforcement: ssl, - Version: version, + case servers.CreateModeReplica: + props = &servers.ServerPropertiesForReplica{ + SourceServerId: source, + PublicNetworkAccess: &publicAccess, + SslEnforcement: &ssl, + Version: &version, } } - server := mariadb.ServerForCreate{ - Location: &location, + server := servers.ServerForCreate{ + Location: location, Properties: props, Sku: sku, Tags: tags.Expand(d.Get("tags").(map[string]interface{})), } - future, err := client.Create(ctx, id.ResourceGroup, id.Name, server) - if err != nil { + if err := client.CreateThenPoll(ctx, id, server); err != nil { return fmt.Errorf("creating %s: %+v", id, err) } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for the creation of %s: %+v", id, err) - } - d.SetId(id.ID()) return resourceMariaDbServerRead(d, meta) } @@ -307,7 +296,7 @@ func resourceMariaDbServerUpdate(d *pluginsdk.ResourceData, meta interface{}) er log.Printf("[INFO] preparing arguments for AzureRM MariaDB Server update.") - id, err := parse.ServerID(d.Id()) + id, err := servers.ParseServerID(d.Id()) if err != nil { return err } @@ -317,39 +306,34 @@ func resourceMariaDbServerUpdate(d *pluginsdk.ResourceData, meta interface{}) er return fmt.Errorf("expanding `sku_name`: %+v", err) } - publicAccess := mariadb.PublicNetworkAccessEnumEnabled + publicAccess := servers.PublicNetworkAccessEnumEnabled if v := d.Get("public_network_access_enabled").(bool); !v { - publicAccess = mariadb.PublicNetworkAccessEnumDisabled + publicAccess = servers.PublicNetworkAccessEnumDisabled } - ssl := mariadb.SslEnforcementEnumEnabled + ssl := servers.SslEnforcementEnumEnabled if v := d.Get("ssl_enforcement_enabled").(bool); !v { - ssl = mariadb.SslEnforcementEnumDisabled + ssl = servers.SslEnforcementEnumDisabled } storageProfile := expandMariaDbStorageProfile(d) - - properties := mariadb.ServerUpdateParameters{ - ServerUpdateParametersProperties: &mariadb.ServerUpdateParametersProperties{ + serverVersion := servers.ServerVersion(d.Get("version").(string)) + properties := servers.ServerUpdateParameters{ + Properties: &servers.ServerUpdateParametersProperties{ AdministratorLoginPassword: utils.String(d.Get("administrator_login_password").(string)), - PublicNetworkAccess: publicAccess, - SslEnforcement: ssl, + PublicNetworkAccess: &publicAccess, + SslEnforcement: &ssl, StorageProfile: storageProfile, - Version: mariadb.ServerVersion(d.Get("version").(string)), + Version: &serverVersion, }, Sku: sku, Tags: tags.Expand(d.Get("tags").(map[string]interface{})), } - future, err := client.Update(ctx, id.ResourceGroup, id.Name, properties) - if err != nil { + if err := client.UpdateThenPoll(ctx, *id, properties); err != nil { return fmt.Errorf("updating %s: %+v", *id, err) } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for update of %s: %+v", *id, err) - } - return resourceMariaDbServerRead(d, meta) } @@ -358,14 +342,14 @@ func resourceMariaDbServerRead(d *pluginsdk.ResourceData, meta interface{}) erro ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.ServerID(d.Id()) + id, err := servers.ParseServerID(d.Id()) if err != nil { return err } - resp, err := client.Get(ctx, id.ResourceGroup, id.Name) + resp, err := client.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { log.Printf("[WARN] %s was not found - removing from state", *id) d.SetId("") return nil @@ -374,35 +358,60 @@ func resourceMariaDbServerRead(d *pluginsdk.ResourceData, meta interface{}) erro return fmt.Errorf("retrieving %s: %+v", *id, err) } - d.Set("name", id.Name) - d.Set("resource_group_name", id.ResourceGroup) + d.Set("name", id.ServerName) + d.Set("resource_group_name", id.ResourceGroupName) - if location := resp.Location; location != nil { - d.Set("location", azure.NormalizeLocation(*location)) - } + if model := resp.Model; model != nil { + d.Set("location", azure.NormalizeLocation(model.Location)) - if sku := resp.Sku; sku != nil { - d.Set("sku_name", sku.Name) - } - - if props := resp.ServerProperties; props != nil { - d.Set("administrator_login", props.AdministratorLogin) - d.Set("public_network_access_enabled", props.PublicNetworkAccess == mariadb.PublicNetworkAccessEnumEnabled) - d.Set("ssl_enforcement_enabled", props.SslEnforcement == mariadb.SslEnforcementEnumEnabled) - d.Set("version", string(props.Version)) - - if storage := props.StorageProfile; storage != nil { - d.Set("auto_grow_enabled", storage.StorageAutogrow == mariadb.StorageAutogrowEnabled) - d.Set("backup_retention_days", storage.BackupRetentionDays) - d.Set("geo_redundant_backup_enabled", storage.GeoRedundantBackup == mariadb.Enabled) - d.Set("storage_mb", storage.StorageMB) + if sku := model.Sku; sku != nil { + d.Set("sku_name", sku.Name) } - // Computed - d.Set("fqdn", props.FullyQualifiedDomainName) - } + if props := model.Properties; props != nil { + d.Set("administrator_login", props.AdministratorLogin) - return tags.FlattenAndSet(d, resp.Tags) + publicNetworkAccess := false + if props.PublicNetworkAccess != nil { + publicNetworkAccess = *props.PublicNetworkAccess == servers.PublicNetworkAccessEnumEnabled + } + d.Set("public_network_access_enabled", publicNetworkAccess) + + sslEnforcement := false + if props.SslEnforcement != nil { + sslEnforcement = *props.SslEnforcement == servers.SslEnforcementEnumEnabled + } + d.Set("ssl_enforcement_enabled", sslEnforcement) + + version := "" + if props.Version != nil { + version = string(*props.Version) + } + d.Set("version", version) + + if storage := props.StorageProfile; storage != nil { + autoGrow := false + if storage.StorageAutogrow != nil { + autoGrow = *storage.StorageAutogrow == servers.StorageAutogrowEnabled + } + d.Set("auto_grow_enabled", autoGrow) + + geoRedundant := false + if storage.GeoRedundantBackup != nil { + geoRedundant = *storage.GeoRedundantBackup == servers.GeoRedundantBackupEnabled + } + d.Set("geo_redundant_backup_enabled", geoRedundant) + d.Set("backup_retention_days", storage.BackupRetentionDays) + d.Set("storage_mb", storage.StorageMB) + + } + + // Computed + d.Set("fqdn", props.FullyQualifiedDomainName) + } + return tags.FlattenAndSet(d, model.Tags) + } + return nil } func resourceMariaDbServerDelete(d *pluginsdk.ResourceData, meta interface{}) error { @@ -410,37 +419,32 @@ func resourceMariaDbServerDelete(d *pluginsdk.ResourceData, meta interface{}) er ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.ServerID(d.Id()) + id, err := servers.ParseServerID(d.Id()) if err != nil { return err } - future, err := client.Delete(ctx, id.ResourceGroup, id.Name) - if err != nil { + if err := client.DeleteThenPoll(ctx, *id); err != nil { return fmt.Errorf("deleting %s: %+v", *id, err) } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for the deletion of %s: %+v", *id, err) - } - return nil } -func expandServerSkuName(skuName string) (*mariadb.Sku, error) { +func expandServerSkuName(skuName string) (*servers.Sku, error) { parts := strings.Split(skuName, "_") if len(parts) != 3 { return nil, fmt.Errorf("sku_name (%s) has the wrong number of parts (%d) after splitting on _", skuName, len(parts)) } - var tier mariadb.SkuTier + var tier servers.SkuTier switch parts[0] { case "B": - tier = mariadb.Basic + tier = servers.SkuTierBasic case "GP": - tier = mariadb.GeneralPurpose + tier = servers.SkuTierGeneralPurpose case "MO": - tier = mariadb.MemoryOptimized + tier = servers.SkuTierMemoryOptimized default: return nil, fmt.Errorf("sku_name %s has unknown sku tier %s", skuName, parts[0]) } @@ -450,37 +454,39 @@ func expandServerSkuName(skuName string) (*mariadb.Sku, error) { return nil, fmt.Errorf("cannot convert `sku_name` %q capacity %s to int", skuName, parts[2]) } - return &mariadb.Sku{ - Name: utils.String(skuName), - Tier: tier, - Capacity: utils.Int32(int32(capacity)), + return &servers.Sku{ + Name: skuName, + Tier: &tier, + Capacity: utils.Int64(int64(capacity)), Family: utils.String(parts[1]), }, nil } -func expandMariaDbStorageProfile(d *pluginsdk.ResourceData) *mariadb.StorageProfile { - storage := mariadb.StorageProfile{} +func expandMariaDbStorageProfile(d *pluginsdk.ResourceData) *servers.StorageProfile { + storage := servers.StorageProfile{} // now override whatever we may have from the block with the top level properties if v, ok := d.GetOk("auto_grow_enabled"); ok { - storage.StorageAutogrow = mariadb.StorageAutogrowDisabled + autogrowEnabled := servers.StorageAutogrowDisabled if v.(bool) { - storage.StorageAutogrow = mariadb.StorageAutogrowEnabled + autogrowEnabled = servers.StorageAutogrowEnabled } + storage.StorageAutogrow = &autogrowEnabled } if v, ok := d.GetOk("backup_retention_days"); ok { - storage.BackupRetentionDays = utils.Int32(int32(v.(int))) + storage.BackupRetentionDays = utils.Int64(int64(v.(int))) } if v, ok := d.GetOk("geo_redundant_backup_enabled"); ok { - storage.GeoRedundantBackup = mariadb.Disabled + geoRedundantBackup := servers.GeoRedundantBackupDisabled if v.(bool) { - storage.GeoRedundantBackup = mariadb.Enabled + geoRedundantBackup = servers.GeoRedundantBackupEnabled } + storage.GeoRedundantBackup = &geoRedundantBackup } if v, ok := d.GetOk("storage_mb"); ok { - storage.StorageMB = utils.Int32(int32(v.(int))) + storage.StorageMB = utils.Int64(int64(v.(int))) } return &storage diff --git a/internal/services/mariadb/mariadb_server_resource_test.go b/internal/services/mariadb/mariadb_server_resource_test.go index 45b2bde401a7..25e2f5b3b064 100644 --- a/internal/services/mariadb/mariadb_server_resource_test.go +++ b/internal/services/mariadb/mariadb_server_resource_test.go @@ -6,10 +6,10 @@ import ( "testing" "time" + "github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/mariadb/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -199,17 +199,17 @@ func TestAccMariaDbServer_createPointInTimeRestore(t *testing.T) { } func (MariaDbServerResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.ServerID(state.ID) + id, err := servers.ParseServerID(state.ID) if err != nil { return nil, err } - resp, err := clients.MariaDB.ServersClient.Get(ctx, id.ResourceGroup, id.Name) + resp, err := clients.MariaDB.ServersClient.Get(ctx, *id) if err != nil { - return nil, fmt.Errorf("retrieving MariaDB Server %q (Resource Group %q): %v", id.Name, id.ResourceGroup, err) + return nil, fmt.Errorf("retrieving %s: %v", *id, err) } - return utils.Bool(resp.ServerProperties != nil), nil + return utils.Bool(resp.Model != nil), nil } func (MariaDbServerResource) basic(data acceptance.TestData, version string) string { diff --git a/internal/services/mariadb/mariadb_virtual_network_rule_resource.go b/internal/services/mariadb/mariadb_virtual_network_rule_resource.go index c7af2b36673a..00347fe43794 100644 --- a/internal/services/mariadb/mariadb_virtual_network_rule_resource.go +++ b/internal/services/mariadb/mariadb_virtual_network_rule_resource.go @@ -6,12 +6,11 @@ import ( "log" "time" - "github.com/Azure/azure-sdk-for-go/services/mariadb/mgmt/2018-06-01/mariadb" "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/virtualnetworkrules" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/mariadb/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/mariadb/validate" validate2 "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" @@ -26,7 +25,7 @@ func resourceMariaDbVirtualNetworkRule() *pluginsdk.Resource { Update: resourceMariaDbVirtualNetworkRuleCreateUpdate, Delete: resourceMariaDbVirtualNetworkRuleDelete, Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - _, err := parse.MariaDBVirtualNetworkRuleID(id) + _, err := virtualnetworkrules.ParseVirtualNetworkRuleID(id) return err }), @@ -69,44 +68,40 @@ func resourceMariaDbVirtualNetworkRuleCreateUpdate(d *pluginsdk.ResourceData, me ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - id := parse.NewMariaDBVirtualNetworkRuleID(subscriptionId, d.Get("resource_group_name").(string), d.Get("server_name").(string), d.Get("name").(string)) + id := virtualnetworkrules.NewVirtualNetworkRuleID(subscriptionId, d.Get("resource_group_name").(string), d.Get("server_name").(string), d.Get("name").(string)) subnetId := d.Get("subnet_id").(string) if d.IsNewResource() { - existing, err := client.Get(ctx, id.ResourceGroup, id.ServerName, id.VirtualNetworkRuleName) + existing, err := client.Get(ctx, id) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return fmt.Errorf("checking for presence of existing %s: %+v", id, err) } } - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return tf.ImportAsExistsError("azurerm_mariadb_virtual_network_rule", id.ID()) } } - parameters := mariadb.VirtualNetworkRule{ - VirtualNetworkRuleProperties: &mariadb.VirtualNetworkRuleProperties{ - VirtualNetworkSubnetID: utils.String(subnetId), + parameters := virtualnetworkrules.VirtualNetworkRule{ + Properties: &virtualnetworkrules.VirtualNetworkRuleProperties{ + VirtualNetworkSubnetId: subnetId, IgnoreMissingVnetServiceEndpoint: utils.Bool(false), }, } - future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.ServerName, id.VirtualNetworkRuleName, parameters) - if err != nil { + if err := client.CreateOrUpdateThenPoll(ctx, id, parameters); err != nil { return fmt.Errorf("creating %s: %+v", id, err) } - if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for creation/update of %q: %+v", id, err) - } // Wait for the provisioning state to become ready log.Printf("[DEBUG] Waiting for %s to become ready", id) stateConf := &pluginsdk.StateChangeConf{ Pending: []string{"Initializing", "InProgress", "Unknown", "ResponseNotFound"}, Target: []string{"Ready"}, - Refresh: mariaDbVirtualNetworkStateStatusCodeRefreshFunc(ctx, client, id.ResourceGroup, id.ServerName, id.VirtualNetworkRuleName), + Refresh: mariaDbVirtualNetworkStateStatusCodeRefreshFunc(ctx, client, id), MinTimeout: 1 * time.Minute, ContinuousTargetOccurence: 5, } @@ -130,14 +125,14 @@ func resourceMariaDbVirtualNetworkRuleRead(d *pluginsdk.ResourceData, meta inter ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.MariaDBVirtualNetworkRuleID(d.Id()) + id, err := virtualnetworkrules.ParseVirtualNetworkRuleID(d.Id()) if err != nil { return err } - resp, err := client.Get(ctx, id.ResourceGroup, id.ServerName, id.VirtualNetworkRuleName) + resp, err := client.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { log.Printf("[INFO] Error reading MariaDb Virtual Network Rule %q - removing from state", d.Id()) d.SetId("") return nil @@ -147,11 +142,13 @@ func resourceMariaDbVirtualNetworkRuleRead(d *pluginsdk.ResourceData, meta inter } d.Set("name", id.VirtualNetworkRuleName) - d.Set("resource_group_name", id.ResourceGroup) + d.Set("resource_group_name", id.ResourceGroupName) d.Set("server_name", id.ServerName) - if props := resp.VirtualNetworkRuleProperties; props != nil { - d.Set("subnet_id", props.VirtualNetworkSubnetID) + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("subnet_id", props.VirtualNetworkSubnetId) + } } return nil @@ -162,44 +159,40 @@ func resourceMariaDbVirtualNetworkRuleDelete(d *pluginsdk.ResourceData, meta int ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.MariaDBVirtualNetworkRuleID(d.Id()) + id, err := virtualnetworkrules.ParseVirtualNetworkRuleID(d.Id()) if err != nil { return err } - future, err := client.Delete(ctx, id.ResourceGroup, id.ServerName, id.VirtualNetworkRuleName) - if err != nil { + if err := client.DeleteThenPoll(ctx, *id); err != nil { return fmt.Errorf("deleting %s: %+v", *id, err) } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - if !response.WasNotFound(future.Response()) { - return fmt.Errorf("waiting for deletion of %s: %+v", *id, err) - } - } - return nil } -func mariaDbVirtualNetworkStateStatusCodeRefreshFunc(ctx context.Context, client *mariadb.VirtualNetworkRulesClient, resourceGroup string, serverName string, name string) pluginsdk.StateRefreshFunc { +func mariaDbVirtualNetworkStateStatusCodeRefreshFunc(ctx context.Context, client *virtualnetworkrules.VirtualNetworkRulesClient, id virtualnetworkrules.VirtualNetworkRuleId) pluginsdk.StateRefreshFunc { return func() (interface{}, string, error) { - resp, err := client.Get(ctx, resourceGroup, serverName, name) + resp, err := client.Get(ctx, id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { - log.Printf("[DEBUG] Retrieving MariaDb Virtual Network Rule %q (MariaDb Server: %q, Resource Group: %q) returned 404.", resourceGroup, serverName, name) + if response.WasNotFound(resp.HttpResponse) { + log.Printf("[DEBUG] Retrieving %s returned 404.", id) return nil, "ResponseNotFound", nil } - return nil, "", fmt.Errorf("polling for the state of the MariaDb Virtual Network Rule %q (MariaDb Server: %q, Resource Group: %q): %+v", name, serverName, resourceGroup, err) + return nil, "", fmt.Errorf("polling for the state of %s: %+v", id, err) } - if props := resp.VirtualNetworkRuleProperties; props != nil { - log.Printf("[DEBUG] Retrieving MariaDb Virtual Network Rule %q (MariaDb Server: %q, Resource Group: %q) returned Status %s", resourceGroup, serverName, name, props.State) - return resp, string(props.State), nil + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + log.Printf("[DEBUG] Retrieving %s returned Status %s", id, *props.State) + return resp, string(*props.State), nil + + } } // Valid response was returned but VirtualNetworkRuleProperties was nil. Basically the rule exists, but with no properties for some reason. Assume Unknown instead of returning error. - log.Printf("[DEBUG] Retrieving MariaDb Virtual Network Rule %q (MariaDb Server: %q, Resource Group: %q) returned empty VirtualNetworkRuleProperties", resourceGroup, serverName, name) + log.Printf("[DEBUG] Retrieving %s returned empty VirtualNetworkRuleProperties", id) return resp, "Unknown", nil } } diff --git a/internal/services/mariadb/mariadb_virtual_network_rule_resource_test.go b/internal/services/mariadb/mariadb_virtual_network_rule_resource_test.go index b399f8fdbb93..aa37b5bbd321 100644 --- a/internal/services/mariadb/mariadb_virtual_network_rule_resource_test.go +++ b/internal/services/mariadb/mariadb_virtual_network_rule_resource_test.go @@ -6,10 +6,10 @@ import ( "regexp" "testing" + "github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/virtualnetworkrules" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/mariadb/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -91,17 +91,17 @@ func TestAccMariaDbVirtualNetworkRule_multipleSubnets(t *testing.T) { } func (MariaDbVirtualNetworkRuleResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.MariaDBVirtualNetworkRuleID(state.ID) + id, err := virtualnetworkrules.ParseVirtualNetworkRuleID(state.ID) if err != nil { return nil, err } - resp, err := clients.MariaDB.VirtualNetworkRulesClient.Get(ctx, id.ResourceGroup, id.ServerName, id.VirtualNetworkRuleName) + resp, err := clients.MariaDB.VirtualNetworkRulesClient.Get(ctx, *id) if err != nil { return nil, fmt.Errorf("retrieving %s: %v", *id, err) } - return utils.Bool(resp.VirtualNetworkRuleProperties != nil), nil + return utils.Bool(resp.Model != nil), nil } func (MariaDbVirtualNetworkRuleResource) basic(data acceptance.TestData) string { diff --git a/internal/services/mariadb/parse/maria_db_configuration.go b/internal/services/mariadb/parse/maria_db_configuration.go deleted file mode 100644 index 5f3140e28630..000000000000 --- a/internal/services/mariadb/parse/maria_db_configuration.go +++ /dev/null @@ -1,75 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - "strings" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -type MariaDBConfigurationId struct { - SubscriptionId string - ResourceGroup string - ServerName string - ConfigurationName string -} - -func NewMariaDBConfigurationID(subscriptionId, resourceGroup, serverName, configurationName string) MariaDBConfigurationId { - return MariaDBConfigurationId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourceGroup, - ServerName: serverName, - ConfigurationName: configurationName, - } -} - -func (id MariaDBConfigurationId) String() string { - segments := []string{ - fmt.Sprintf("Configuration Name %q", id.ConfigurationName), - fmt.Sprintf("Server Name %q", id.ServerName), - fmt.Sprintf("Resource Group %q", id.ResourceGroup), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Maria D B Configuration", segmentsStr) -} - -func (id MariaDBConfigurationId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.DBforMariaDB/servers/%s/configurations/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.ServerName, id.ConfigurationName) -} - -// MariaDBConfigurationID parses a MariaDBConfiguration ID into an MariaDBConfigurationId struct -func MariaDBConfigurationID(input string) (*MariaDBConfigurationId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := MariaDBConfigurationId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - if resourceId.ServerName, err = id.PopSegment("servers"); err != nil { - return nil, err - } - if resourceId.ConfigurationName, err = id.PopSegment("configurations"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/mariadb/parse/maria_db_configuration_test.go b/internal/services/mariadb/parse/maria_db_configuration_test.go deleted file mode 100644 index 63e32230b1c1..000000000000 --- a/internal/services/mariadb/parse/maria_db_configuration_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "testing" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -var _ resourceids.Id = MariaDBConfigurationId{} - -func TestMariaDBConfigurationIDFormatter(t *testing.T) { - actual := NewMariaDBConfigurationID("12345678-1234-9876-4563-123456789012", "resGroup1", "server1", "config1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1/configurations/config1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestMariaDBConfigurationID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *MariaDBConfigurationId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - - { - // missing ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/", - Error: true, - }, - - { - // missing value for ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/", - Error: true, - }, - - { - // missing ConfigurationName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1/", - Error: true, - }, - - { - // missing value for ConfigurationName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1/configurations/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1/configurations/config1", - Expected: &MariaDBConfigurationId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - ServerName: "server1", - ConfigurationName: "config1", - }, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.DBFORMARIADB/SERVERS/SERVER1/CONFIGURATIONS/CONFIG1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := MariaDBConfigurationID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - if actual.ServerName != v.Expected.ServerName { - t.Fatalf("Expected %q but got %q for ServerName", v.Expected.ServerName, actual.ServerName) - } - if actual.ConfigurationName != v.Expected.ConfigurationName { - t.Fatalf("Expected %q but got %q for ConfigurationName", v.Expected.ConfigurationName, actual.ConfigurationName) - } - } -} diff --git a/internal/services/mariadb/parse/maria_db_database.go b/internal/services/mariadb/parse/maria_db_database.go deleted file mode 100644 index 6dd9d3339acc..000000000000 --- a/internal/services/mariadb/parse/maria_db_database.go +++ /dev/null @@ -1,75 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - "strings" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -type MariaDBDatabaseId struct { - SubscriptionId string - ResourceGroup string - ServerName string - DatabaseName string -} - -func NewMariaDBDatabaseID(subscriptionId, resourceGroup, serverName, databaseName string) MariaDBDatabaseId { - return MariaDBDatabaseId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourceGroup, - ServerName: serverName, - DatabaseName: databaseName, - } -} - -func (id MariaDBDatabaseId) String() string { - segments := []string{ - fmt.Sprintf("Database Name %q", id.DatabaseName), - fmt.Sprintf("Server Name %q", id.ServerName), - fmt.Sprintf("Resource Group %q", id.ResourceGroup), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Maria D B Database", segmentsStr) -} - -func (id MariaDBDatabaseId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.DBforMariaDB/servers/%s/databases/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.ServerName, id.DatabaseName) -} - -// MariaDBDatabaseID parses a MariaDBDatabase ID into an MariaDBDatabaseId struct -func MariaDBDatabaseID(input string) (*MariaDBDatabaseId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := MariaDBDatabaseId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - if resourceId.ServerName, err = id.PopSegment("servers"); err != nil { - return nil, err - } - if resourceId.DatabaseName, err = id.PopSegment("databases"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/mariadb/parse/maria_db_database_test.go b/internal/services/mariadb/parse/maria_db_database_test.go deleted file mode 100644 index c5d9b1b08c95..000000000000 --- a/internal/services/mariadb/parse/maria_db_database_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "testing" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -var _ resourceids.Id = MariaDBDatabaseId{} - -func TestMariaDBDatabaseIDFormatter(t *testing.T) { - actual := NewMariaDBDatabaseID("12345678-1234-9876-4563-123456789012", "resGroup1", "server1", "db1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1/databases/db1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestMariaDBDatabaseID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *MariaDBDatabaseId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - - { - // missing ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/", - Error: true, - }, - - { - // missing value for ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/", - Error: true, - }, - - { - // missing DatabaseName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1/", - Error: true, - }, - - { - // missing value for DatabaseName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1/databases/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1/databases/db1", - Expected: &MariaDBDatabaseId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - ServerName: "server1", - DatabaseName: "db1", - }, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.DBFORMARIADB/SERVERS/SERVER1/DATABASES/DB1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := MariaDBDatabaseID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - if actual.ServerName != v.Expected.ServerName { - t.Fatalf("Expected %q but got %q for ServerName", v.Expected.ServerName, actual.ServerName) - } - if actual.DatabaseName != v.Expected.DatabaseName { - t.Fatalf("Expected %q but got %q for DatabaseName", v.Expected.DatabaseName, actual.DatabaseName) - } - } -} diff --git a/internal/services/mariadb/parse/maria_db_firewall_rule.go b/internal/services/mariadb/parse/maria_db_firewall_rule.go deleted file mode 100644 index 3153fd283942..000000000000 --- a/internal/services/mariadb/parse/maria_db_firewall_rule.go +++ /dev/null @@ -1,75 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - "strings" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -type MariaDBFirewallRuleId struct { - SubscriptionId string - ResourceGroup string - ServerName string - FirewallRuleName string -} - -func NewMariaDBFirewallRuleID(subscriptionId, resourceGroup, serverName, firewallRuleName string) MariaDBFirewallRuleId { - return MariaDBFirewallRuleId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourceGroup, - ServerName: serverName, - FirewallRuleName: firewallRuleName, - } -} - -func (id MariaDBFirewallRuleId) String() string { - segments := []string{ - fmt.Sprintf("Firewall Rule Name %q", id.FirewallRuleName), - fmt.Sprintf("Server Name %q", id.ServerName), - fmt.Sprintf("Resource Group %q", id.ResourceGroup), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Maria D B Firewall Rule", segmentsStr) -} - -func (id MariaDBFirewallRuleId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.DBforMariaDB/servers/%s/firewallRules/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.ServerName, id.FirewallRuleName) -} - -// MariaDBFirewallRuleID parses a MariaDBFirewallRule ID into an MariaDBFirewallRuleId struct -func MariaDBFirewallRuleID(input string) (*MariaDBFirewallRuleId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := MariaDBFirewallRuleId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - if resourceId.ServerName, err = id.PopSegment("servers"); err != nil { - return nil, err - } - if resourceId.FirewallRuleName, err = id.PopSegment("firewallRules"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/mariadb/parse/maria_db_firewall_rule_test.go b/internal/services/mariadb/parse/maria_db_firewall_rule_test.go deleted file mode 100644 index 86aaca3e4ec4..000000000000 --- a/internal/services/mariadb/parse/maria_db_firewall_rule_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "testing" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -var _ resourceids.Id = MariaDBFirewallRuleId{} - -func TestMariaDBFirewallRuleIDFormatter(t *testing.T) { - actual := NewMariaDBFirewallRuleID("12345678-1234-9876-4563-123456789012", "resGroup1", "server1", "firewallRule1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1/firewallRules/firewallRule1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestMariaDBFirewallRuleID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *MariaDBFirewallRuleId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - - { - // missing ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/", - Error: true, - }, - - { - // missing value for ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/", - Error: true, - }, - - { - // missing FirewallRuleName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1/", - Error: true, - }, - - { - // missing value for FirewallRuleName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1/firewallRules/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1/firewallRules/firewallRule1", - Expected: &MariaDBFirewallRuleId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - ServerName: "server1", - FirewallRuleName: "firewallRule1", - }, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.DBFORMARIADB/SERVERS/SERVER1/FIREWALLRULES/FIREWALLRULE1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := MariaDBFirewallRuleID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - if actual.ServerName != v.Expected.ServerName { - t.Fatalf("Expected %q but got %q for ServerName", v.Expected.ServerName, actual.ServerName) - } - if actual.FirewallRuleName != v.Expected.FirewallRuleName { - t.Fatalf("Expected %q but got %q for FirewallRuleName", v.Expected.FirewallRuleName, actual.FirewallRuleName) - } - } -} diff --git a/internal/services/mariadb/parse/maria_db_virtual_network_rule.go b/internal/services/mariadb/parse/maria_db_virtual_network_rule.go deleted file mode 100644 index c1ef6a2c7d1a..000000000000 --- a/internal/services/mariadb/parse/maria_db_virtual_network_rule.go +++ /dev/null @@ -1,75 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - "strings" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -type MariaDBVirtualNetworkRuleId struct { - SubscriptionId string - ResourceGroup string - ServerName string - VirtualNetworkRuleName string -} - -func NewMariaDBVirtualNetworkRuleID(subscriptionId, resourceGroup, serverName, virtualNetworkRuleName string) MariaDBVirtualNetworkRuleId { - return MariaDBVirtualNetworkRuleId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourceGroup, - ServerName: serverName, - VirtualNetworkRuleName: virtualNetworkRuleName, - } -} - -func (id MariaDBVirtualNetworkRuleId) String() string { - segments := []string{ - fmt.Sprintf("Virtual Network Rule Name %q", id.VirtualNetworkRuleName), - fmt.Sprintf("Server Name %q", id.ServerName), - fmt.Sprintf("Resource Group %q", id.ResourceGroup), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Maria D B Virtual Network Rule", segmentsStr) -} - -func (id MariaDBVirtualNetworkRuleId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.DBforMariaDB/servers/%s/virtualNetworkRules/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.ServerName, id.VirtualNetworkRuleName) -} - -// MariaDBVirtualNetworkRuleID parses a MariaDBVirtualNetworkRule ID into an MariaDBVirtualNetworkRuleId struct -func MariaDBVirtualNetworkRuleID(input string) (*MariaDBVirtualNetworkRuleId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := MariaDBVirtualNetworkRuleId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - if resourceId.ServerName, err = id.PopSegment("servers"); err != nil { - return nil, err - } - if resourceId.VirtualNetworkRuleName, err = id.PopSegment("virtualNetworkRules"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/mariadb/parse/maria_db_virtual_network_rule_test.go b/internal/services/mariadb/parse/maria_db_virtual_network_rule_test.go deleted file mode 100644 index 245d578ecd4d..000000000000 --- a/internal/services/mariadb/parse/maria_db_virtual_network_rule_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "testing" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -var _ resourceids.Id = MariaDBVirtualNetworkRuleId{} - -func TestMariaDBVirtualNetworkRuleIDFormatter(t *testing.T) { - actual := NewMariaDBVirtualNetworkRuleID("12345678-1234-9876-4563-123456789012", "resGroup1", "server1", "vnetrule1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1/virtualNetworkRules/vnetrule1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestMariaDBVirtualNetworkRuleID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *MariaDBVirtualNetworkRuleId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - - { - // missing ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/", - Error: true, - }, - - { - // missing value for ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/", - Error: true, - }, - - { - // missing VirtualNetworkRuleName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1/", - Error: true, - }, - - { - // missing value for VirtualNetworkRuleName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1/virtualNetworkRules/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1/virtualNetworkRules/vnetrule1", - Expected: &MariaDBVirtualNetworkRuleId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - ServerName: "server1", - VirtualNetworkRuleName: "vnetrule1", - }, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.DBFORMARIADB/SERVERS/SERVER1/VIRTUALNETWORKRULES/VNETRULE1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := MariaDBVirtualNetworkRuleID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - if actual.ServerName != v.Expected.ServerName { - t.Fatalf("Expected %q but got %q for ServerName", v.Expected.ServerName, actual.ServerName) - } - if actual.VirtualNetworkRuleName != v.Expected.VirtualNetworkRuleName { - t.Fatalf("Expected %q but got %q for VirtualNetworkRuleName", v.Expected.VirtualNetworkRuleName, actual.VirtualNetworkRuleName) - } - } -} diff --git a/internal/services/mariadb/parse/server.go b/internal/services/mariadb/parse/server.go deleted file mode 100644 index 20bc1f33fa3d..000000000000 --- a/internal/services/mariadb/parse/server.go +++ /dev/null @@ -1,69 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - "strings" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -type ServerId struct { - SubscriptionId string - ResourceGroup string - Name string -} - -func NewServerID(subscriptionId, resourceGroup, name string) ServerId { - return ServerId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourceGroup, - Name: name, - } -} - -func (id ServerId) String() string { - segments := []string{ - fmt.Sprintf("Name %q", id.Name), - fmt.Sprintf("Resource Group %q", id.ResourceGroup), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Server", segmentsStr) -} - -func (id ServerId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.DBforMariaDB/servers/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.Name) -} - -// ServerID parses a Server ID into an ServerId struct -func ServerID(input string) (*ServerId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := ServerId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - if resourceId.Name, err = id.PopSegment("servers"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/mariadb/parse/server_test.go b/internal/services/mariadb/parse/server_test.go deleted file mode 100644 index 5a8802e54766..000000000000 --- a/internal/services/mariadb/parse/server_test.go +++ /dev/null @@ -1,112 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "testing" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -var _ resourceids.Id = ServerId{} - -func TestServerIDFormatter(t *testing.T) { - actual := NewServerID("12345678-1234-9876-4563-123456789012", "resGroup1", "server1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestServerID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *ServerId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - - { - // missing Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/", - Error: true, - }, - - { - // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1", - Expected: &ServerId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - Name: "server1", - }, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.DBFORMARIADB/SERVERS/SERVER1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := ServerID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - if actual.Name != v.Expected.Name { - t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name) - } - } -} diff --git a/internal/services/mariadb/resourceids.go b/internal/services/mariadb/resourceids.go deleted file mode 100644 index da078e4831b7..000000000000 --- a/internal/services/mariadb/resourceids.go +++ /dev/null @@ -1,7 +0,0 @@ -package mariadb - -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Server -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=MariaDBFirewallRule -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1/firewallRules/firewallRule1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=MariaDBVirtualNetworkRule -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1/virtualNetworkRules/vnetrule1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=MariaDBConfiguration -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1/configurations/config1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=MariaDBDatabase -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1/databases/db1 diff --git a/internal/services/mariadb/validate/maria_db_configuration_id.go b/internal/services/mariadb/validate/maria_db_configuration_id.go deleted file mode 100644 index cb4f33723c41..000000000000 --- a/internal/services/mariadb/validate/maria_db_configuration_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/mariadb/parse" -) - -func MariaDBConfigurationID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.MariaDBConfigurationID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/mariadb/validate/maria_db_configuration_id_test.go b/internal/services/mariadb/validate/maria_db_configuration_id_test.go deleted file mode 100644 index c92c8b16023d..000000000000 --- a/internal/services/mariadb/validate/maria_db_configuration_id_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestMariaDBConfigurationID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - - { - // empty - Input: "", - Valid: false, - }, - - { - // missing SubscriptionId - Input: "/", - Valid: false, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Valid: false, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Valid: false, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Valid: false, - }, - - { - // missing ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/", - Valid: false, - }, - - { - // missing value for ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/", - Valid: false, - }, - - { - // missing ConfigurationName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1/", - Valid: false, - }, - - { - // missing value for ConfigurationName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1/configurations/", - Valid: false, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1/configurations/config1", - Valid: true, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.DBFORMARIADB/SERVERS/SERVER1/CONFIGURATIONS/CONFIG1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := MariaDBConfigurationID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/mariadb/validate/maria_db_database_id.go b/internal/services/mariadb/validate/maria_db_database_id.go deleted file mode 100644 index 72ace30d7eab..000000000000 --- a/internal/services/mariadb/validate/maria_db_database_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/mariadb/parse" -) - -func MariaDBDatabaseID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.MariaDBDatabaseID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/mariadb/validate/maria_db_database_id_test.go b/internal/services/mariadb/validate/maria_db_database_id_test.go deleted file mode 100644 index 860f79311e1b..000000000000 --- a/internal/services/mariadb/validate/maria_db_database_id_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestMariaDBDatabaseID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - - { - // empty - Input: "", - Valid: false, - }, - - { - // missing SubscriptionId - Input: "/", - Valid: false, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Valid: false, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Valid: false, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Valid: false, - }, - - { - // missing ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/", - Valid: false, - }, - - { - // missing value for ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/", - Valid: false, - }, - - { - // missing DatabaseName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1/", - Valid: false, - }, - - { - // missing value for DatabaseName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1/databases/", - Valid: false, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1/databases/db1", - Valid: true, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.DBFORMARIADB/SERVERS/SERVER1/DATABASES/DB1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := MariaDBDatabaseID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/mariadb/validate/maria_db_firewall_rule_id.go b/internal/services/mariadb/validate/maria_db_firewall_rule_id.go deleted file mode 100644 index 469e95bf6ac9..000000000000 --- a/internal/services/mariadb/validate/maria_db_firewall_rule_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/mariadb/parse" -) - -func MariaDBFirewallRuleID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.MariaDBFirewallRuleID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/mariadb/validate/maria_db_firewall_rule_id_test.go b/internal/services/mariadb/validate/maria_db_firewall_rule_id_test.go deleted file mode 100644 index 72cf474ee02f..000000000000 --- a/internal/services/mariadb/validate/maria_db_firewall_rule_id_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestMariaDBFirewallRuleID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - - { - // empty - Input: "", - Valid: false, - }, - - { - // missing SubscriptionId - Input: "/", - Valid: false, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Valid: false, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Valid: false, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Valid: false, - }, - - { - // missing ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/", - Valid: false, - }, - - { - // missing value for ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/", - Valid: false, - }, - - { - // missing FirewallRuleName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1/", - Valid: false, - }, - - { - // missing value for FirewallRuleName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1/firewallRules/", - Valid: false, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1/firewallRules/firewallRule1", - Valid: true, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.DBFORMARIADB/SERVERS/SERVER1/FIREWALLRULES/FIREWALLRULE1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := MariaDBFirewallRuleID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/mariadb/validate/maria_db_virtual_network_rule_id.go b/internal/services/mariadb/validate/maria_db_virtual_network_rule_id.go deleted file mode 100644 index 8da930b85a65..000000000000 --- a/internal/services/mariadb/validate/maria_db_virtual_network_rule_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/mariadb/parse" -) - -func MariaDBVirtualNetworkRuleID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.MariaDBVirtualNetworkRuleID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/mariadb/validate/maria_db_virtual_network_rule_id_test.go b/internal/services/mariadb/validate/maria_db_virtual_network_rule_id_test.go deleted file mode 100644 index 99e3013e5da4..000000000000 --- a/internal/services/mariadb/validate/maria_db_virtual_network_rule_id_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestMariaDBVirtualNetworkRuleID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - - { - // empty - Input: "", - Valid: false, - }, - - { - // missing SubscriptionId - Input: "/", - Valid: false, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Valid: false, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Valid: false, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Valid: false, - }, - - { - // missing ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/", - Valid: false, - }, - - { - // missing value for ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/", - Valid: false, - }, - - { - // missing VirtualNetworkRuleName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1/", - Valid: false, - }, - - { - // missing value for VirtualNetworkRuleName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1/virtualNetworkRules/", - Valid: false, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1/virtualNetworkRules/vnetrule1", - Valid: true, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.DBFORMARIADB/SERVERS/SERVER1/VIRTUALNETWORKRULES/VNETRULE1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := MariaDBVirtualNetworkRuleID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/mariadb/validate/server_id.go b/internal/services/mariadb/validate/server_id.go deleted file mode 100644 index e3c030471093..000000000000 --- a/internal/services/mariadb/validate/server_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/mariadb/parse" -) - -func ServerID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.ServerID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/mariadb/validate/server_id_test.go b/internal/services/mariadb/validate/server_id_test.go deleted file mode 100644 index 2f1d7e91db3e..000000000000 --- a/internal/services/mariadb/validate/server_id_test.go +++ /dev/null @@ -1,76 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestServerID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - - { - // empty - Input: "", - Valid: false, - }, - - { - // missing SubscriptionId - Input: "/", - Valid: false, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Valid: false, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Valid: false, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Valid: false, - }, - - { - // missing Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/", - Valid: false, - }, - - { - // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/", - Valid: false, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMariaDB/servers/server1", - Valid: true, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.DBFORMARIADB/SERVERS/SERVER1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := ServerID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/monitor/client/client.go b/internal/services/monitor/client/client.go index 0d4f28d31723..58aceebf24d1 100644 --- a/internal/services/monitor/client/client.go +++ b/internal/services/monitor/client/client.go @@ -6,6 +6,11 @@ import ( "github.com/Azure/azure-sdk-for-go/services/preview/alertsmanagement/mgmt/2019-06-01-preview/alertsmanagement" classic "github.com/Azure/azure-sdk-for-go/services/preview/monitor/mgmt/2021-07-01-preview/insights" newActionGroupClient "github.com/Azure/azure-sdk-for-go/services/preview/monitor/mgmt/2021-09-01-preview/insights" + "github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionendpoints" + "github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionrules" + diagnosticSettingClient "github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-05-01-preview/diagnosticsettings" + diagnosticCategoryClient "github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-05-01-preview/diagnosticsettingscategories" + "github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-08-01/scheduledqueryrules" "github.com/hashicorp/terraform-provider-azurerm/internal/common" ) @@ -24,13 +29,16 @@ type Client struct { ActionGroupsClient *newActionGroupClient.ActionGroupsClient ActivityLogAlertsClient *insights.ActivityLogAlertsClient AlertRulesClient *classic.AlertRulesClient - DiagnosticSettingsClient *classic.DiagnosticSettingsClient - DiagnosticSettingsCategoryClient *classic.DiagnosticSettingsCategoryClient + DataCollectionRulesClient *datacollectionrules.DataCollectionRulesClient + DataCollectionEndpointsClient *datacollectionendpoints.DataCollectionEndpointsClient + DiagnosticSettingsClient *diagnosticSettingClient.DiagnosticSettingsClient + DiagnosticSettingsCategoryClient *diagnosticCategoryClient.DiagnosticSettingsCategoriesClient LogProfilesClient *classic.LogProfilesClient MetricAlertsClient *classic.MetricAlertsClient PrivateLinkScopesClient *classic.PrivateLinkScopesClient PrivateLinkScopedResourcesClient *classic.PrivateLinkScopedResourcesClient ScheduledQueryRulesClient *classic.ScheduledQueryRulesClient + ScheduledQueryRulesV2Client *scheduledqueryrules.ScheduledQueryRulesClient } func NewClient(o *common.ClientOptions) *Client { @@ -55,10 +63,16 @@ func NewClient(o *common.ClientOptions) *Client { AlertRulesClient := classic.NewAlertRulesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&AlertRulesClient.Client, o.ResourceManagerAuthorizer) - DiagnosticSettingsClient := classic.NewDiagnosticSettingsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + DataCollectionEndpointsClient := datacollectionendpoints.NewDataCollectionEndpointsClientWithBaseURI(o.ResourceManagerEndpoint) + o.ConfigureClient(&DataCollectionEndpointsClient.Client, o.ResourceManagerAuthorizer) + + DataCollectionRulesClient := datacollectionrules.NewDataCollectionRulesClientWithBaseURI(o.ResourceManagerEndpoint) + o.ConfigureClient(&DataCollectionRulesClient.Client, o.ResourceManagerAuthorizer) + + DiagnosticSettingsClient := diagnosticSettingClient.NewDiagnosticSettingsClientWithBaseURI(o.ResourceManagerEndpoint) o.ConfigureClient(&DiagnosticSettingsClient.Client, o.ResourceManagerAuthorizer) - DiagnosticSettingsCategoryClient := classic.NewDiagnosticSettingsCategoryClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + DiagnosticSettingsCategoryClient := diagnosticCategoryClient.NewDiagnosticSettingsCategoriesClientWithBaseURI(o.ResourceManagerEndpoint) o.ConfigureClient(&DiagnosticSettingsCategoryClient.Client, o.ResourceManagerAuthorizer) LogProfilesClient := classic.NewLogProfilesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) @@ -76,6 +90,9 @@ func NewClient(o *common.ClientOptions) *Client { ScheduledQueryRulesClient := classic.NewScheduledQueryRulesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&ScheduledQueryRulesClient.Client, o.ResourceManagerAuthorizer) + ScheduledQueryRulesV2Client := scheduledqueryrules.NewScheduledQueryRulesClientWithBaseURI(o.ResourceManagerEndpoint) + o.ConfigureClient(&ScheduledQueryRulesV2Client.Client, o.ResourceManagerAuthorizer) + return &Client{ AADDiagnosticSettingsClient: &AADDiagnosticSettingsClient, AutoscaleSettingsClient: &AutoscaleSettingsClient, @@ -84,6 +101,8 @@ func NewClient(o *common.ClientOptions) *Client { ActionGroupsClient: &ActionGroupsClient, ActivityLogAlertsClient: &ActivityLogAlertsClient, AlertRulesClient: &AlertRulesClient, + DataCollectionEndpointsClient: &DataCollectionEndpointsClient, + DataCollectionRulesClient: &DataCollectionRulesClient, DiagnosticSettingsClient: &DiagnosticSettingsClient, DiagnosticSettingsCategoryClient: &DiagnosticSettingsCategoryClient, LogProfilesClient: &LogProfilesClient, @@ -91,5 +110,6 @@ func NewClient(o *common.ClientOptions) *Client { PrivateLinkScopesClient: &PrivateLinkScopesClient, PrivateLinkScopedResourcesClient: &PrivateLinkScopedResourcesClient, ScheduledQueryRulesClient: &ScheduledQueryRulesClient, + ScheduledQueryRulesV2Client: &ScheduledQueryRulesV2Client, } } diff --git a/internal/services/monitor/monitor_aad_diagnostic_setting_resource.go b/internal/services/monitor/monitor_aad_diagnostic_setting_resource.go index dc67c21b7e47..e136a2297adf 100644 --- a/internal/services/monitor/monitor_aad_diagnostic_setting_resource.go +++ b/internal/services/monitor/monitor_aad_diagnostic_setting_resource.go @@ -9,11 +9,10 @@ import ( "github.com/Azure/azure-sdk-for-go/services/aad/mgmt/2017-04-01/aad" "github.com/hashicorp/go-azure-helpers/lang/response" - authRuleParse "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/authorizationrulesnamespaces" + authRuleParse "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/authorizationrulesnamespaces" + "github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - logAnalyticsParse "github.com/hashicorp/terraform-provider-azurerm/internal/services/loganalytics/parse" - logAnalyticsValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/loganalytics/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/services/monitor/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/monitor/validate" storageParse "github.com/hashicorp/terraform-provider-azurerm/internal/services/storage/parse" @@ -72,7 +71,7 @@ func resourceMonitorAADDiagnosticSetting() *pluginsdk.Resource { "log_analytics_workspace_id": { Type: pluginsdk.TypeString, Optional: true, - ValidateFunc: logAnalyticsValidate.LogAnalyticsWorkspaceID, + ValidateFunc: workspaces.ValidateWorkspaceID, AtLeastOneOf: []string{"eventhub_authorization_rule_id", "log_analytics_workspace_id", "storage_account_id"}, }, @@ -233,7 +232,7 @@ func resourceMonitorAADDiagnosticSettingRead(d *pluginsdk.ResourceData, meta int workspaceId := "" if resp.WorkspaceID != nil && *resp.WorkspaceID != "" { - parsedId, err := logAnalyticsParse.LogAnalyticsWorkspaceID(*resp.WorkspaceID) + parsedId, err := workspaces.ParseWorkspaceID(*resp.WorkspaceID) if err != nil { return err } diff --git a/internal/services/monitor/monitor_action_group_data_source.go b/internal/services/monitor/monitor_action_group_data_source.go index 2534e632daf7..343fabad0d87 100644 --- a/internal/services/monitor/monitor_action_group_data_source.go +++ b/internal/services/monitor/monitor_action_group_data_source.go @@ -5,7 +5,7 @@ import ( "time" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/eventhubs" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/eventhubs" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/services/monitor/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" diff --git a/internal/services/monitor/monitor_action_group_resource.go b/internal/services/monitor/monitor_action_group_resource.go index befb477b696d..fff9ae22787f 100644 --- a/internal/services/monitor/monitor_action_group_resource.go +++ b/internal/services/monitor/monitor_action_group_resource.go @@ -7,7 +7,7 @@ import ( "github.com/Azure/azure-sdk-for-go/services/preview/monitor/mgmt/2021-09-01-preview/insights" "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" - "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/eventhubs" + "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/eventhubs" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" diff --git a/internal/services/monitor/monitor_data_collection_endpoint_data_source.go b/internal/services/monitor/monitor_data_collection_endpoint_data_source.go new file mode 100644 index 000000000000..8dac6f69cc94 --- /dev/null +++ b/internal/services/monitor/monitor_data_collection_endpoint_data_source.go @@ -0,0 +1,135 @@ +package monitor + +import ( + "context" + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionendpoints" + "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" + "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" +) + +type DataCollectionEndpointDataSource struct{} + +var _ sdk.DataSource = DataCollectionEndpointDataSource{} + +func (d DataCollectionEndpointDataSource) ModelObject() interface{} { + return &DataCollectionEndpoint{} +} + +func (d DataCollectionEndpointDataSource) ResourceType() string { + return "azurerm_monitor_data_collection_endpoint" +} + +func (d DataCollectionEndpointDataSource) Arguments() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "resource_group_name": commonschema.ResourceGroupNameForDataSource(), + } +} + +func (d DataCollectionEndpointDataSource) Attributes() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "configuration_access_endpoint": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "location": commonschema.LocationComputed(), + + "logs_ingestion_endpoint": { + Type: pluginsdk.TypeString, + Computed: true, + }, + "public_network_access_enabled": { + Type: pluginsdk.TypeBool, + Computed: true, + }, + + "description": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "kind": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "tags": commonschema.TagsDataSource(), + } +} + +func (d DataCollectionEndpointDataSource) Read() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.Monitor.DataCollectionEndpointsClient + subscriptionId := metadata.Client.Account.SubscriptionId + + var state DataCollectionEndpoint + if err := metadata.Decode(&state); err != nil { + return fmt.Errorf("decoding: %+v", err) + } + + id := datacollectionendpoints.NewDataCollectionEndpointID(subscriptionId, state.ResourceGroupName, state.Name) + metadata.Logger.Infof("retrieving %s", id) + resp, err := client.Get(ctx, id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + metadata.Logger.Infof("%s was not found - removing from state!", id) + return metadata.MarkAsGone(id) + } + return fmt.Errorf("retrieving %s: %+v", id, err) + } + + var enablePublicNetWorkAccess bool + var description, kind, location, configurationAccessEndpoint, logsIngestionEndpoint string + var tag map[string]interface{} + if model := resp.Model; model != nil { + kind = flattenDataCollectionEndpointKind(model.Kind) + location = azure.NormalizeLocation(model.Location) + tag = tags.Flatten(model.Tags) + if prop := model.Properties; prop != nil { + description = flattenDataCollectionEndpointDescription(prop.Description) + if networkAcls := prop.NetworkAcls; networkAcls != nil { + enablePublicNetWorkAccess = flattenDataCollectionEndpointPublicNetworkAccess(networkAcls.PublicNetworkAccess) + } + + if prop.ConfigurationAccess != nil && prop.ConfigurationAccess.Endpoint != nil { + configurationAccessEndpoint = *prop.ConfigurationAccess.Endpoint + } + + if prop.LogsIngestion != nil && prop.LogsIngestion.Endpoint != nil { + logsIngestionEndpoint = *prop.LogsIngestion.Endpoint + } + } + } + + metadata.SetID(id) + + return metadata.Encode(&DataCollectionEndpoint{ + ConfigurationAccessEndpoint: configurationAccessEndpoint, + Description: description, + Kind: kind, + Location: location, + LogsIngestionEndpoint: logsIngestionEndpoint, + Name: id.DataCollectionEndpointName, + EnablePublicNetworkAccess: enablePublicNetWorkAccess, + ResourceGroupName: id.ResourceGroupName, + Tags: tag, + }) + }, + Timeout: 5 * time.Minute, + } +} diff --git a/internal/services/monitor/monitor_data_collection_endpoint_data_source_test.go b/internal/services/monitor/monitor_data_collection_endpoint_data_source_test.go new file mode 100644 index 000000000000..01758c0762c4 --- /dev/null +++ b/internal/services/monitor/monitor_data_collection_endpoint_data_source_test.go @@ -0,0 +1,39 @@ +package monitor_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" +) + +type MonitorDataCollectionEndpointDataSource struct{} + +func TestAccMonitorDataCollectionEndpointDataSource_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_monitor_data_collection_endpoint", "test") + d := MonitorDataCollectionEndpointDataSource{} + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: d.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("kind").HasValue("Windows"), + check.That(data.ResourceName).Key("public_network_access_enabled").HasValue("false"), + check.That(data.ResourceName).Key("configuration_access_endpoint").Exists(), + check.That(data.ResourceName).Key("logs_ingestion_endpoint").Exists(), + ), + }, + }) +} + +func (d MonitorDataCollectionEndpointDataSource) complete(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +data "azurerm_monitor_data_collection_endpoint" "test" { + name = azurerm_monitor_data_collection_endpoint.test.name + resource_group_name = azurerm_monitor_data_collection_endpoint.test.resource_group_name +} +`, MonitorDataCollectionEndpointResource{}.complete(data)) +} diff --git a/internal/services/monitor/monitor_data_collection_endpoint_resource.go b/internal/services/monitor/monitor_data_collection_endpoint_resource.go new file mode 100644 index 000000000000..698dfdcb6af9 --- /dev/null +++ b/internal/services/monitor/monitor_data_collection_endpoint_resource.go @@ -0,0 +1,319 @@ +package monitor + +import ( + "context" + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionendpoints" + "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" + "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type DataCollectionEndpoint struct { + ConfigurationAccessEndpoint string `tfschema:"configuration_access_endpoint"` + Description string `tfschema:"description"` + Kind string `tfschema:"kind"` + Name string `tfschema:"name"` + Location string `tfschema:"location"` + LogsIngestionEndpoint string `tfschema:"logs_ingestion_endpoint"` + EnablePublicNetworkAccess bool `tfschema:"public_network_access_enabled"` + ResourceGroupName string `tfschema:"resource_group_name"` + Tags map[string]interface{} `tfschema:"tags"` +} + +type DataCollectionEndpointResource struct{} + +func (r DataCollectionEndpointResource) Arguments() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "resource_group_name": commonschema.ResourceGroupName(), + + "location": commonschema.Location(), + + "public_network_access_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: true, + }, + + "description": { + Type: pluginsdk.TypeString, + Optional: true, + }, + + "kind": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice( + datacollectionendpoints.PossibleValuesForKnownDataCollectionEndpointResourceKind(), false), + }, + + "tags": commonschema.Tags(), + } +} + +func (r DataCollectionEndpointResource) Attributes() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "configuration_access_endpoint": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "logs_ingestion_endpoint": { + Type: pluginsdk.TypeString, + Computed: true, + }, + } +} + +func (r DataCollectionEndpointResource) ResourceType() string { + return "azurerm_monitor_data_collection_endpoint" +} + +func (r DataCollectionEndpointResource) IDValidationFunc() pluginsdk.SchemaValidateFunc { + return datacollectionendpoints.ValidateDataCollectionEndpointID +} + +func (r DataCollectionEndpointResource) ModelObject() interface{} { + return &DataCollectionEndpoint{} +} + +func (r DataCollectionEndpointResource) Create() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + metadata.Logger.Info("Decoding state..") + var state DataCollectionEndpoint + if err := metadata.Decode(&state); err != nil { + return err + } + + client := metadata.Client.Monitor.DataCollectionEndpointsClient + subscriptionId := metadata.Client.Account.SubscriptionId + + id := datacollectionendpoints.NewDataCollectionEndpointID(subscriptionId, state.ResourceGroupName, state.Name) + metadata.Logger.Infof("creating %s", id) + + existing, err := client.Get(ctx, id) + if err != nil && !response.WasNotFound(existing.HttpResponse) { + return fmt.Errorf("checking for the presence of an existing %s: %+v", id, err) + } + if !response.WasNotFound(existing.HttpResponse) { + return metadata.ResourceRequiresImport(r.ResourceType(), id) + } + + input := datacollectionendpoints.DataCollectionEndpointResource{ + Kind: expandDataCollectionEndpointKind(state.Kind), + Location: azure.NormalizeLocation(state.Location), + Name: utils.String(state.Name), + Properties: &datacollectionendpoints.DataCollectionEndpoint{ + Description: utils.String(state.Description), + NetworkAcls: &datacollectionendpoints.NetworkRuleSet{ + PublicNetworkAccess: expandDataCollectionEndpointPublicNetworkAccess(state.EnablePublicNetworkAccess), + }, + }, + Tags: tags.Expand(state.Tags), + } + + if _, err := client.Create(ctx, id, input); err != nil { + return fmt.Errorf("creating %s: %+v", id, err) + } + + metadata.SetID(id) + return nil + }, + Timeout: 30 * time.Minute, + } +} + +func (r DataCollectionEndpointResource) Read() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.Monitor.DataCollectionEndpointsClient + id, err := datacollectionendpoints.ParseDataCollectionEndpointID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + metadata.Logger.Infof("retrieving %s", *id) + resp, err := client.Get(ctx, *id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + metadata.Logger.Infof("%s was not found - removing from state!", *id) + return metadata.MarkAsGone(id) + } + return fmt.Errorf("retrieving %s: %+v", *id, err) + } + var enablePublicNetWorkAccess bool + var description, kind, location, configurationAccessEndpoint, logsIngestionEndpoint string + var tag map[string]interface{} + if model := resp.Model; model != nil { + kind = flattenDataCollectionEndpointKind(model.Kind) + location = azure.NormalizeLocation(model.Location) + tag = tags.Flatten(model.Tags) + if prop := model.Properties; prop != nil { + description = flattenDataCollectionEndpointDescription(prop.Description) + if networkAcls := prop.NetworkAcls; networkAcls != nil { + enablePublicNetWorkAccess = flattenDataCollectionEndpointPublicNetworkAccess(networkAcls.PublicNetworkAccess) + } + + if prop.ConfigurationAccess != nil && prop.ConfigurationAccess.Endpoint != nil { + configurationAccessEndpoint = *prop.ConfigurationAccess.Endpoint + } + + if prop.LogsIngestion != nil && prop.LogsIngestion.Endpoint != nil { + logsIngestionEndpoint = *prop.LogsIngestion.Endpoint + } + } + } + + return metadata.Encode(&DataCollectionEndpoint{ + ConfigurationAccessEndpoint: configurationAccessEndpoint, + Description: description, + Kind: kind, + Location: location, + LogsIngestionEndpoint: logsIngestionEndpoint, + Name: id.DataCollectionEndpointName, + EnablePublicNetworkAccess: enablePublicNetWorkAccess, + ResourceGroupName: id.ResourceGroupName, + Tags: tag, + }) + }, + Timeout: 5 * time.Minute, + } +} + +func (r DataCollectionEndpointResource) Update() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + id, err := datacollectionendpoints.ParseDataCollectionEndpointID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + metadata.Logger.Infof("updating %s..", *id) + client := metadata.Client.Monitor.DataCollectionEndpointsClient + resp, err := client.Get(ctx, *id) + if err != nil { + return fmt.Errorf("retrieving %s: %+v", *id, err) + } + if resp.Model == nil { + return fmt.Errorf("unexpected null model of %s", *id) + } + existing := resp.Model + if existing.Properties == nil { + return fmt.Errorf("unexpected null properties of %s", *id) + } + + var state DataCollectionEndpoint + if err := metadata.Decode(&state); err != nil { + return err + } + + if metadata.ResourceData.HasChange("description") { + existing.Properties.Description = utils.String(state.Description) + } + + if metadata.ResourceData.HasChange("kind") { + existing.Kind = expandDataCollectionEndpointKind(state.Kind) + } + + if metadata.ResourceData.HasChange("public_network_access") { + existing.Properties.NetworkAcls = &datacollectionendpoints.NetworkRuleSet{ + PublicNetworkAccess: expandDataCollectionEndpointPublicNetworkAccess(state.EnablePublicNetworkAccess), + } + } + + if metadata.ResourceData.HasChange("tags") { + existing.Tags = tags.Expand(state.Tags) + } + + if _, err := client.Create(ctx, *id, *existing); err != nil { + return fmt.Errorf("updating %s: %+v", *id, err) + } + return nil + + }, + Timeout: 30 * time.Minute, + } +} + +func (r DataCollectionEndpointResource) Delete() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.Monitor.DataCollectionEndpointsClient + id, err := datacollectionendpoints.ParseDataCollectionEndpointID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + metadata.Logger.Infof("deleting %s..", *id) + resp, err := client.Delete(ctx, *id) + if err != nil && !response.WasNotFound(resp.HttpResponse) { + return fmt.Errorf("deleting %s: %+v", *id, err) + } + return nil + }, + Timeout: 30 * time.Minute, + } +} + +func expandDataCollectionEndpointKind(input string) *datacollectionendpoints.KnownDataCollectionEndpointResourceKind { + if input == "" { + return nil + } + + result := datacollectionendpoints.KnownDataCollectionEndpointResourceKind(input) + return &result +} + +func expandDataCollectionEndpointPublicNetworkAccess(input bool) *datacollectionendpoints.KnownPublicNetworkAccessOptions { + var result datacollectionendpoints.KnownPublicNetworkAccessOptions + if input { + result = datacollectionendpoints.KnownPublicNetworkAccessOptionsEnabled + } else { + result = datacollectionendpoints.KnownPublicNetworkAccessOptionsDisabled + } + return &result +} + +func flattenDataCollectionEndpointKind(input *datacollectionendpoints.KnownDataCollectionEndpointResourceKind) string { + if input == nil { + return "" + } + + return string(*input) +} + +func flattenDataCollectionEndpointDescription(input *string) string { + if input == nil { + return "" + } + + return *input +} + +func flattenDataCollectionEndpointPublicNetworkAccess(input *datacollectionendpoints.KnownPublicNetworkAccessOptions) bool { + if input == nil { + return false + } + var result bool + if *input == datacollectionendpoints.KnownPublicNetworkAccessOptionsEnabled { + result = true + } else if *input == datacollectionendpoints.KnownPublicNetworkAccessOptionsDisabled { + result = false + } + return result +} diff --git a/internal/services/monitor/monitor_data_collection_endpoint_resource_test.go b/internal/services/monitor/monitor_data_collection_endpoint_resource_test.go new file mode 100644 index 000000000000..0561fb1b929f --- /dev/null +++ b/internal/services/monitor/monitor_data_collection_endpoint_resource_test.go @@ -0,0 +1,158 @@ +package monitor_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionendpoints" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type MonitorDataCollectionEndpointResource struct{} + +func (r MonitorDataCollectionEndpointResource) Exists(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + id, err := datacollectionendpoints.ParseDataCollectionEndpointID(state.ID) + if err != nil { + return nil, err + } + + resp, err := client.Monitor.DataCollectionEndpointsClient.Get(ctx, *id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return utils.Bool(false), nil + } + return nil, fmt.Errorf("retrieving %s: %+v", *id, err) + } + return utils.Bool(true), nil +} + +func TestAccMonitorDataCollectionEndpoint_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_monitor_data_collection_endpoint", "test") + r := MonitorDataCollectionEndpointResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccMonitorDataCollectionEndpoint_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_monitor_data_collection_endpoint", "test") + r := MonitorDataCollectionEndpointResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func TestAccMonitorDataCollectionEndpoint_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_monitor_data_collection_endpoint", "test") + r := MonitorDataCollectionEndpointResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccMonitorDataCollectionEndpoint_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_monitor_data_collection_endpoint", "test") + r := MonitorDataCollectionEndpointResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func (r MonitorDataCollectionEndpointResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%[1]s +resource "azurerm_monitor_data_collection_endpoint" "test" { + name = "acctestmdcr-%[2]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location +} +`, r.template(data), data.RandomInteger) +} + +func (r MonitorDataCollectionEndpointResource) complete(data acceptance.TestData) string { + return fmt.Sprintf(` +%[1]s +resource "azurerm_monitor_data_collection_endpoint" "test" { + name = "acctestmdce-%[2]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + kind = "Windows" + public_network_access_enabled = false + description = "acc test monitor_data_collection_endpoint complete" + tags = { + ENV = "test" + } +} +`, r.template(data), data.RandomInteger) +} + +func (r MonitorDataCollectionEndpointResource) requiresImport(data acceptance.TestData) string { + return fmt.Sprintf(` +%s +resource "azurerm_monitor_data_collection_endpoint" "import" { + name = azurerm_monitor_data_collection_endpoint.test.name + resource_group_name = azurerm_monitor_data_collection_endpoint.test.resource_group_name + location = azurerm_monitor_data_collection_endpoint.test.location +} +`, r.basic(data)) +} + +func (r MonitorDataCollectionEndpointResource) template(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} +resource "azurerm_resource_group" "test" { + name = "acctestRG-DataCollectionEndpoint-%[1]d" + location = "%[2]s" +} +`, data.RandomInteger, data.Locations.Primary) +} diff --git a/internal/services/monitor/monitor_data_collection_rule_resource.go b/internal/services/monitor/monitor_data_collection_rule_resource.go new file mode 100644 index 000000000000..270b72a5af27 --- /dev/null +++ b/internal/services/monitor/monitor_data_collection_rule_resource.go @@ -0,0 +1,1016 @@ +package monitor + +import ( + "context" + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionrules" + "github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" + "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type DataCollectionRule struct { + DataFlows []DataFlow `tfschema:"data_flow"` + DataSources []DataSource `tfschema:"data_sources"` + Description string `tfschema:"description"` + Destinations []Destination `tfschema:"destinations"` + Kind string `tfschema:"kind"` + Name string `tfschema:"name"` + Location string `tfschema:"location"` + ResourceGroupName string `tfschema:"resource_group_name"` + Tags map[string]interface{} `tfschema:"tags"` +} + +type DataFlow struct { + Destinations []string `tfschema:"destinations"` + Streams []string `tfschema:"streams"` +} + +type DataSource struct { + Extensions []Extension `tfschema:"extension"` + PerformanceCounters []PerfCounter `tfschema:"performance_counter"` + Syslog []Syslog `tfschema:"syslog"` + WindowsEventLogs []WindowsEventLog `tfschema:"windows_event_log"` +} + +type Destination struct { + AzureMonitorMetrics []AzureMonitorMetric `tfschema:"azure_monitor_metrics"` + LogAnalytics []LogAnalytic `tfschema:"log_analytics"` +} + +type Extension struct { + ExtensionName string `tfschema:"extension_name"` + ExtensionSettings string `tfschema:"extension_json"` + InputDataSources []string `tfschema:"input_data_sources"` + Name string `tfschema:"name"` + Streams []string `tfschema:"streams"` +} + +type PerfCounter struct { + CounterSpecifiers []string `tfschema:"counter_specifiers"` + Name string `tfschema:"name"` + SamplingFrequencyInSeconds int64 `tfschema:"sampling_frequency_in_seconds"` + Streams []string `tfschema:"streams"` +} + +type Syslog struct { + FacilityNames []string `tfschema:"facility_names"` + LogLevels []string `tfschema:"log_levels"` + Name string `tfschema:"name"` +} + +type WindowsEventLog struct { + Name string `tfschema:"name"` + Streams []string `tfschema:"streams"` + XPathQueries []string `tfschema:"x_path_queries"` +} + +type AzureMonitorMetric struct { + Name string `tfschema:"name"` +} + +type LogAnalytic struct { + Name string `tfschema:"name"` + WorkspaceResourceId string `tfschema:"workspace_resource_id"` +} + +type DataCollectionRuleResource struct{} + +func (r DataCollectionRuleResource) Arguments() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "resource_group_name": commonschema.ResourceGroupName(), + + "location": commonschema.Location(), + + "data_flow": { + Type: pluginsdk.TypeList, + Required: true, + MinItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "destinations": { + Type: pluginsdk.TypeList, + Required: true, + MinItems: 1, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, + "streams": { + Type: pluginsdk.TypeList, + Required: true, + MinItems: 1, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringInSlice( + datacollectionrules.PossibleValuesForKnownDataFlowStreams(), false), + }, + }, + }, + }, + }, + + "destinations": { + Type: pluginsdk.TypeList, + Required: true, + MaxItems: 1, + MinItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*schema.Schema{ + "azure_monitor_metrics": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, + }, + AtLeastOneOf: []string{"destinations.0.azure_monitor_metrics", "destinations.0.log_analytics"}, + }, + "log_analytics": { + Type: pluginsdk.TypeList, + Optional: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + "workspace_resource_id": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: workspaces.ValidateWorkspaceID, + }, + }, + }, + AtLeastOneOf: []string{"destinations.0.azure_monitor_metrics", "destinations.0.log_analytics"}, + }, + }, + }, + }, + + "data_sources": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "extension": { + Type: pluginsdk.TypeList, + Optional: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + "extension_name": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + "streams": { + Type: pluginsdk.TypeList, + Required: true, + MinItems: 1, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringInSlice( + datacollectionrules.PossibleValuesForKnownExtensionDataSourceStreams(), + false), + }, + }, + "extension_json": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.StringIsJSON, + DiffSuppressFunc: pluginsdk.SuppressJsonDiff, + }, + "input_data_sources": { + Type: pluginsdk.TypeList, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, + }, + }, + }, + "performance_counter": { + Type: pluginsdk.TypeList, + Optional: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + "sampling_frequency_in_seconds": { + Type: pluginsdk.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(1, 300), + }, + "streams": { + Type: pluginsdk.TypeList, + Required: true, + MinItems: 1, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringInSlice( + datacollectionrules.PossibleValuesForKnownPerfCounterDataSourceStreams(), + false), + }, + }, + "counter_specifiers": { + Type: pluginsdk.TypeList, + Required: true, + MinItems: 1, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, + }, + }, + }, + "syslog": { + Type: pluginsdk.TypeList, + Optional: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + "facility_names": { + Type: pluginsdk.TypeList, + Required: true, + MinItems: 1, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringInSlice( + datacollectionrules.PossibleValuesForKnownSyslogDataSourceFacilityNames(), + false), + }, + }, + "log_levels": { + Type: pluginsdk.TypeList, + Required: true, + MinItems: 1, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringInSlice( + datacollectionrules.PossibleValuesForKnownSyslogDataSourceLogLevels(), false), + }, + }, + }, + }, + }, + "windows_event_log": { + Type: pluginsdk.TypeList, + Optional: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + "streams": { + Type: pluginsdk.TypeList, + Required: true, + MinItems: 1, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringInSlice( + datacollectionrules.PossibleValuesForKnownWindowsEventLogDataSourceStreams(), + false), + }, + }, + "x_path_queries": { + Type: pluginsdk.TypeList, + Required: true, + MinItems: 1, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, + }, + }, + }, + }, + }, + }, + + "description": { + Type: pluginsdk.TypeString, + Optional: true, + }, + + "kind": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice( + datacollectionrules.PossibleValuesForKnownDataCollectionRuleResourceKind(), false), + }, + + "tags": commonschema.Tags(), + } +} + +func (r DataCollectionRuleResource) Attributes() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{} +} + +func (r DataCollectionRuleResource) ResourceType() string { + return "azurerm_monitor_data_collection_rule" +} + +func (r DataCollectionRuleResource) IDValidationFunc() pluginsdk.SchemaValidateFunc { + return datacollectionrules.ValidateDataCollectionRuleID +} + +func (r DataCollectionRuleResource) ModelObject() interface{} { + return &DataCollectionRule{} +} + +func (r DataCollectionRuleResource) Create() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + metadata.Logger.Info("Decoding state..") + var state DataCollectionRule + if err := metadata.Decode(&state); err != nil { + return err + } + + client := metadata.Client.Monitor.DataCollectionRulesClient + subscriptionId := metadata.Client.Account.SubscriptionId + + id := datacollectionrules.NewDataCollectionRuleID(subscriptionId, state.ResourceGroupName, state.Name) + metadata.Logger.Infof("creating %s", id) + + existing, err := client.Get(ctx, id) + if err != nil && !response.WasNotFound(existing.HttpResponse) { + return fmt.Errorf("checking for the presence of an existing %s: %+v", id, err) + } + if !response.WasNotFound(existing.HttpResponse) { + return metadata.ResourceRequiresImport(r.ResourceType(), id) + } + + dataSources, err := expandDataCollectionRuleDataSources(state.DataSources) + if err != nil { + return err + } + + input := datacollectionrules.DataCollectionRuleResource{ + Kind: expandDataCollectionRuleKind(state.Kind), + Location: azure.NormalizeLocation(state.Location), + Name: utils.String(state.Name), + Properties: &datacollectionrules.DataCollectionRule{ + DataFlows: expandDataCollectionRuleDataFlows(state.DataFlows), + DataSources: dataSources, + Description: utils.String(state.Description), + Destinations: expandDataCollectionRuleDestinations(state.Destinations), + }, + Tags: tags.Expand(state.Tags), + } + + if _, err := client.Create(ctx, id, input); err != nil { + return fmt.Errorf("creating %s: %+v", id, err) + } + + metadata.SetID(id) + return nil + }, + Timeout: 30 * time.Minute, + } +} + +func (r DataCollectionRuleResource) Read() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.Monitor.DataCollectionRulesClient + id, err := datacollectionrules.ParseDataCollectionRuleID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + metadata.Logger.Infof("retrieving %s", *id) + resp, err := client.Get(ctx, *id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + metadata.Logger.Infof("%s was not found - removing from state!", *id) + return metadata.MarkAsGone(id) + } + return fmt.Errorf("retrieving %s: %+v", *id, err) + } + + var description, kind, location string + var tag map[string]interface{} + var dataFlows []DataFlow + var dataSources []DataSource + var destinations []Destination + + if model := resp.Model; model != nil { + kind = flattenDataCollectionRuleKind(model.Kind) + location = azure.NormalizeLocation(model.Location) + tag = tags.Flatten(model.Tags) + if prop := model.Properties; prop != nil { + description = flattenStringPtr(prop.Description) + dataFlows = flattenDataCollectionRuleDataFlows(prop.DataFlows) + dataSources = flattenDataCollectionRuleDataSources(prop.DataSources) + destinations = flattenDataCollectionRuleDestinations(prop.Destinations) + } + } + + return metadata.Encode(&DataCollectionRule{ + Name: id.DataCollectionRuleName, + ResourceGroupName: id.ResourceGroupName, + DataFlows: dataFlows, + DataSources: dataSources, + Description: description, + Destinations: destinations, + Kind: kind, + Location: location, + Tags: tag, + }) + }, + Timeout: 5 * time.Minute, + } +} + +func (r DataCollectionRuleResource) Update() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + id, err := datacollectionrules.ParseDataCollectionRuleID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + metadata.Logger.Infof("updating %s..", *id) + client := metadata.Client.Monitor.DataCollectionRulesClient + resp, err := client.Get(ctx, *id) + if err != nil { + return fmt.Errorf("retrieving %s: %+v", *id, err) + } + if resp.Model == nil { + return fmt.Errorf("unexpected null model of %s", *id) + } + existing := resp.Model + if existing.Properties == nil { + return fmt.Errorf("unexpected null properties of %s", *id) + } + + var state DataCollectionRule + if err := metadata.Decode(&state); err != nil { + return err + } + + if metadata.ResourceData.HasChange("kind") { + existing.Kind = expandDataCollectionRuleKind(state.Kind) + } + + if metadata.ResourceData.HasChange("tags") { + existing.Tags = tags.Expand(state.Tags) + } + + if metadata.ResourceData.HasChange("data_flow") { + existing.Properties.DataFlows = expandDataCollectionRuleDataFlows(state.DataFlows) + } + + if metadata.ResourceData.HasChange("data_sources") { + dataSource, err := expandDataCollectionRuleDataSources(state.DataSources) + if err != nil { + return err + } + existing.Properties.DataSources = dataSource + } + + if metadata.ResourceData.HasChange("description") { + existing.Properties.Description = utils.String(state.Description) + } + + if metadata.ResourceData.HasChange("destinations") { + existing.Properties.Destinations = expandDataCollectionRuleDestinations(state.Destinations) + } + + // otherwise Service will return an error: "The resource definition is invalid." + existing.SystemData = nil + + if _, err := client.Create(ctx, *id, *existing); err != nil { + return fmt.Errorf("updating %s: %+v", *id, err) + } + return nil + + }, + Timeout: 30 * time.Minute, + } +} + +func (r DataCollectionRuleResource) Delete() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.Monitor.DataCollectionRulesClient + id, err := datacollectionrules.ParseDataCollectionRuleID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + metadata.Logger.Infof("deleting %s..", *id) + resp, err := client.Delete(ctx, *id) + if err != nil && !response.WasNotFound(resp.HttpResponse) { + return fmt.Errorf("deleting %s: %+v", *id, err) + } + return nil + }, + Timeout: 30 * time.Minute, + } +} + +func expandDataCollectionRuleKind(input string) *datacollectionrules.KnownDataCollectionRuleResourceKind { + if input == "" { + return nil + } + + result := datacollectionrules.KnownDataCollectionRuleResourceKind(input) + return &result +} + +func stringSlice(input []string) *[]string { + return &input +} + +func expandDataCollectionRuleDataFlows(input []DataFlow) *[]datacollectionrules.DataFlow { + if len(input) == 0 { + return nil + } + + result := make([]datacollectionrules.DataFlow, 0) + for _, v := range input { + result = append(result, datacollectionrules.DataFlow{ + Destinations: stringSlice(v.Destinations), + Streams: expandDataCollectionRuleDataFlowStreams(v.Streams), + }) + } + return &result +} + +func expandDataCollectionRuleDataFlowStreams(input []string) *[]datacollectionrules.KnownDataFlowStreams { + if len(input) == 0 { + return nil + } + + result := make([]datacollectionrules.KnownDataFlowStreams, 0) + for _, v := range input { + result = append(result, datacollectionrules.KnownDataFlowStreams(v)) + } + return &result +} + +func expandDataCollectionRuleDataSources(input []DataSource) (*datacollectionrules.DataSourcesSpec, error) { + if len(input) == 0 { + return nil, nil + } + + extension, err := expandDataCollectionRuleDataSourceExtensions(input[0].Extensions) + if err != nil { + return nil, err + } + return &datacollectionrules.DataSourcesSpec{ + Extensions: extension, + PerformanceCounters: expandDataCollectionRuleDataSourcePerfCounters(input[0].PerformanceCounters), + Syslog: expandDataCollectionRuleDataSourceSyslog(input[0].Syslog), + WindowsEventLogs: expandDataCollectionRuleDataSourceWindowsEventLogs(input[0].WindowsEventLogs), + }, nil + +} + +func expandDataCollectionRuleDataSourceExtensions(input []Extension) (*[]datacollectionrules.ExtensionDataSource, error) { + if len(input) == 0 { + return nil, nil + } + + result := make([]datacollectionrules.ExtensionDataSource, 0) + for _, v := range input { + var extensionSettings interface{} + if v.ExtensionSettings != "" { + settings, err := pluginsdk.ExpandJsonFromString(v.ExtensionSettings) + if err != nil { + return nil, err + } + extensionSettings = settings + } + + result = append(result, datacollectionrules.ExtensionDataSource{ + ExtensionName: v.ExtensionName, + ExtensionSettings: &extensionSettings, + InputDataSources: stringSlice(v.InputDataSources), + Name: utils.String(v.Name), + Streams: expandDataCollectionRuleDataSourceExtensionStreams(v.Streams), + }) + } + return &result, nil +} + +func expandDataCollectionRuleDataSourceExtensionStreams(input []string) *[]datacollectionrules.KnownExtensionDataSourceStreams { + if len(input) == 0 { + return nil + } + + result := make([]datacollectionrules.KnownExtensionDataSourceStreams, 0) + for _, v := range input { + result = append(result, datacollectionrules.KnownExtensionDataSourceStreams(v)) + } + return &result +} + +func expandDataCollectionRuleDataSourcePerfCounters(input []PerfCounter) *[]datacollectionrules.PerfCounterDataSource { + if len(input) == 0 { + return nil + } + + result := make([]datacollectionrules.PerfCounterDataSource, 0) + for _, v := range input { + result = append(result, datacollectionrules.PerfCounterDataSource{ + CounterSpecifiers: stringSlice(v.CounterSpecifiers), + Name: utils.String(v.Name), + SamplingFrequencyInSeconds: utils.Int64(v.SamplingFrequencyInSeconds), + Streams: expandDataCollectionRuleDataSourcePerfCounterStreams(v.Streams), + }) + } + return &result +} + +func expandDataCollectionRuleDataSourcePerfCounterStreams(input []string) *[]datacollectionrules.KnownPerfCounterDataSourceStreams { + if len(input) == 0 { + return nil + } + + result := make([]datacollectionrules.KnownPerfCounterDataSourceStreams, 0) + for _, v := range input { + result = append(result, datacollectionrules.KnownPerfCounterDataSourceStreams(v)) + } + return &result +} + +func expandDataCollectionRuleDataSourceSyslog(input []Syslog) *[]datacollectionrules.SyslogDataSource { + if len(input) == 0 { + return nil + } + + result := make([]datacollectionrules.SyslogDataSource, 0) + for _, v := range input { + result = append(result, datacollectionrules.SyslogDataSource{ + FacilityNames: expandDataCollectionRuleDataSourceSyslogFacilityNames(v.FacilityNames), + LogLevels: expandDataCollectionRuleDataSourceSyslogLogLevels(v.LogLevels), + Name: utils.String(v.Name), + Streams: &[]datacollectionrules.KnownSyslogDataSourceStreams{datacollectionrules.KnownSyslogDataSourceStreamsMicrosoftNegativeSyslog}, + }) + } + return &result +} + +func expandDataCollectionRuleDataSourceSyslogFacilityNames(input []string) *[]datacollectionrules.KnownSyslogDataSourceFacilityNames { + if len(input) == 0 { + return nil + } + + result := make([]datacollectionrules.KnownSyslogDataSourceFacilityNames, 0) + for _, v := range input { + result = append(result, datacollectionrules.KnownSyslogDataSourceFacilityNames(v)) + } + return &result +} + +func expandDataCollectionRuleDataSourceSyslogLogLevels(input []string) *[]datacollectionrules.KnownSyslogDataSourceLogLevels { + if len(input) == 0 { + return nil + } + + result := make([]datacollectionrules.KnownSyslogDataSourceLogLevels, 0) + for _, v := range input { + result = append(result, datacollectionrules.KnownSyslogDataSourceLogLevels(v)) + } + return &result +} + +func expandDataCollectionRuleDataSourceWindowsEventLogs(input []WindowsEventLog) *[]datacollectionrules.WindowsEventLogDataSource { + if len(input) == 0 { + return nil + } + + result := make([]datacollectionrules.WindowsEventLogDataSource, 0) + for _, v := range input { + result = append(result, datacollectionrules.WindowsEventLogDataSource{ + Name: utils.String(v.Name), + Streams: expandDataCollectionRuleDataSourceWindowsEventLogsStreams(v.Streams), + XPathQueries: stringSlice(v.XPathQueries), + }) + } + return &result +} + +func expandDataCollectionRuleDataSourceWindowsEventLogsStreams(input []string) *[]datacollectionrules.KnownWindowsEventLogDataSourceStreams { + if len(input) == 0 { + return nil + } + + result := make([]datacollectionrules.KnownWindowsEventLogDataSourceStreams, 0) + for _, v := range input { + result = append(result, datacollectionrules.KnownWindowsEventLogDataSourceStreams(v)) + } + return &result +} + +func expandDataCollectionRuleDestinations(input []Destination) *datacollectionrules.DestinationsSpec { + if len(input) == 0 { + return nil + } + + return &datacollectionrules.DestinationsSpec{ + AzureMonitorMetrics: expandDataCollectionRuleDestinationMetrics(input[0].AzureMonitorMetrics), + LogAnalytics: expandDataCollectionRuleDestinationLogAnalytics(input[0].LogAnalytics), + } +} + +func expandDataCollectionRuleDestinationMetrics(input []AzureMonitorMetric) *datacollectionrules.AzureMonitorMetricsDestination { + if len(input) == 0 { + return nil + } + + return &datacollectionrules.AzureMonitorMetricsDestination{ + Name: utils.String(input[0].Name), + } +} + +func expandDataCollectionRuleDestinationLogAnalytics(input []LogAnalytic) *[]datacollectionrules.LogAnalyticsDestination { + if len(input) == 0 { + return nil + } + + result := make([]datacollectionrules.LogAnalyticsDestination, 0) + for _, v := range input { + result = append(result, datacollectionrules.LogAnalyticsDestination{ + Name: utils.String(v.Name), + WorkspaceResourceId: utils.String(v.WorkspaceResourceId), + }) + } + return &result +} + +func flattenDataCollectionRuleKind(input *datacollectionrules.KnownDataCollectionRuleResourceKind) string { + if input == nil { + return "" + } + return string(*input) +} + +func flattenStringPtr(input *string) string { + if input == nil { + return "" + } + return *input +} + +func flattenStringSlicePtr(input *[]string) []string { + if input == nil { + return make([]string, 0) + } + return *input +} + +func flattenDataCollectionRuleDataFlows(input *[]datacollectionrules.DataFlow) []DataFlow { + if input == nil { + return make([]DataFlow, 0) + } + + result := make([]DataFlow, 0) + for _, v := range *input { + result = append(result, DataFlow{ + Destinations: flattenStringSlicePtr(v.Destinations), + Streams: flattenDataCollectionRuleDataFlowStreams(v.Streams), + }) + } + return result +} + +func flattenDataCollectionRuleDataFlowStreams(input *[]datacollectionrules.KnownDataFlowStreams) []string { + if input == nil { + return make([]string, 0) + } + + result := make([]string, 0) + for _, v := range *input { + result = append(result, string(v)) + } + return result +} + +func flattenDataCollectionRuleDataSources(input *datacollectionrules.DataSourcesSpec) []DataSource { + if input == nil { + return make([]DataSource, 0) + } + + return []DataSource{{ + Extensions: flattenDataCollectionRuleDataSourceExtensions(input.Extensions), + PerformanceCounters: flattenDataCollectionRuleDataSourcePerfCounters(input.PerformanceCounters), + Syslog: flattenDataCollectionRuleDataSourceSyslog(input.Syslog), + WindowsEventLogs: flattenDataCollectionRuleWindowsEventLogs(input.WindowsEventLogs), + }} +} + +func flattenDataCollectionRuleDataSourceExtensions(input *[]datacollectionrules.ExtensionDataSource) []Extension { + if input == nil { + return make([]Extension, 0) + } + + result := make([]Extension, 0) + for _, v := range *input { + extensionSettings := "" + if v.ExtensionSettings != nil { + settingString, _ := pluginsdk.FlattenJsonToString((*v.ExtensionSettings).(map[string]interface{})) + extensionSettings = settingString + } + result = append(result, Extension{ + ExtensionName: v.ExtensionName, + Name: flattenStringPtr(v.Name), + ExtensionSettings: extensionSettings, + InputDataSources: flattenStringSlicePtr(v.InputDataSources), + Streams: flattenDataCollectionRuleDataSourceExtensionStreams(v.Streams), + }) + } + return result +} + +func flattenDataCollectionRuleDataSourceExtensionStreams(input *[]datacollectionrules.KnownExtensionDataSourceStreams) []string { + if input == nil { + return make([]string, 0) + } + + result := make([]string, 0) + for _, v := range *input { + result = append(result, string(v)) + } + return result +} + +func flattenDataCollectionRuleDataSourcePerfCounters(input *[]datacollectionrules.PerfCounterDataSource) []PerfCounter { + if input == nil { + return make([]PerfCounter, 0) + } + + result := make([]PerfCounter, 0) + for _, v := range *input { + result = append(result, PerfCounter{ + Name: flattenStringPtr(v.Name), + CounterSpecifiers: flattenStringSlicePtr(v.CounterSpecifiers), + SamplingFrequencyInSeconds: utils.NormaliseNilableInt64(v.SamplingFrequencyInSeconds), + Streams: flattenDataCollectionRuleDataSourcePerfCounterStreams(v.Streams), + }) + } + return result +} + +func flattenDataCollectionRuleDataSourcePerfCounterStreams(input *[]datacollectionrules.KnownPerfCounterDataSourceStreams) []string { + if input == nil { + return make([]string, 0) + } + + result := make([]string, 0) + for _, v := range *input { + result = append(result, string(v)) + } + return result +} + +func flattenDataCollectionRuleDataSourceSyslog(input *[]datacollectionrules.SyslogDataSource) []Syslog { + if input == nil { + return make([]Syslog, 0) + } + + result := make([]Syslog, 0) + for _, v := range *input { + result = append(result, Syslog{ + Name: flattenStringPtr(v.Name), + FacilityNames: flattenDataCollectionRuleDataSourceSyslogFacilityNames(v.FacilityNames), + LogLevels: flattenDataCollectionRuleDataSourceSyslogLogLevels(v.LogLevels), + }) + } + return result +} + +func flattenDataCollectionRuleDataSourceSyslogFacilityNames(input *[]datacollectionrules.KnownSyslogDataSourceFacilityNames) []string { + if input == nil { + return make([]string, 0) + } + + result := make([]string, 0) + for _, v := range *input { + result = append(result, string(v)) + } + return result +} + +func flattenDataCollectionRuleDataSourceSyslogLogLevels(input *[]datacollectionrules.KnownSyslogDataSourceLogLevels) []string { + if input == nil { + return make([]string, 0) + } + + result := make([]string, 0) + for _, v := range *input { + result = append(result, string(v)) + } + return result +} + +func flattenDataCollectionRuleWindowsEventLogs(input *[]datacollectionrules.WindowsEventLogDataSource) []WindowsEventLog { + if input == nil { + return make([]WindowsEventLog, 0) + } + + result := make([]WindowsEventLog, 0) + for _, v := range *input { + result = append(result, WindowsEventLog{ + Name: flattenStringPtr(v.Name), + XPathQueries: flattenStringSlicePtr(v.XPathQueries), + Streams: flattenDataCollectionRuleWindowsEventLogStreams(v.Streams), + }) + } + return result +} + +func flattenDataCollectionRuleWindowsEventLogStreams(input *[]datacollectionrules.KnownWindowsEventLogDataSourceStreams) []string { + if input == nil { + return make([]string, 0) + } + + result := make([]string, 0) + for _, v := range *input { + result = append(result, string(v)) + } + return result +} + +func flattenDataCollectionRuleDestinations(input *datacollectionrules.DestinationsSpec) []Destination { + if input == nil { + return make([]Destination, 0) + } + + return []Destination{{ + AzureMonitorMetrics: flattenDataCollectionRuleDestinationMetrics(input.AzureMonitorMetrics), + LogAnalytics: flattenDataCollectionRuleDestinationLogAnalytics(input.LogAnalytics), + }} +} + +func flattenDataCollectionRuleDestinationMetrics(input *datacollectionrules.AzureMonitorMetricsDestination) []AzureMonitorMetric { + if input == nil { + return make([]AzureMonitorMetric, 0) + } + + return []AzureMonitorMetric{{ + Name: flattenStringPtr(input.Name), + }} +} + +func flattenDataCollectionRuleDestinationLogAnalytics(input *[]datacollectionrules.LogAnalyticsDestination) []LogAnalytic { + if input == nil { + return make([]LogAnalytic, 0) + } + + result := make([]LogAnalytic, 0) + for _, v := range *input { + result = append(result, LogAnalytic{ + Name: flattenStringPtr(v.Name), + WorkspaceResourceId: flattenStringPtr(v.WorkspaceResourceId), + }) + } + return result +} diff --git a/internal/services/monitor/monitor_data_collection_rule_resource_test.go b/internal/services/monitor/monitor_data_collection_rule_resource_test.go new file mode 100644 index 000000000000..1ea51da7d069 --- /dev/null +++ b/internal/services/monitor/monitor_data_collection_rule_resource_test.go @@ -0,0 +1,387 @@ +package monitor_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-04-01/datacollectionrules" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type MonitorDataCollectionRuleResource struct{} + +func (r MonitorDataCollectionRuleResource) Exists(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + id, err := datacollectionrules.ParseDataCollectionRuleID(state.ID) + if err != nil { + return nil, err + } + + resp, err := client.Monitor.DataCollectionRulesClient.Get(ctx, *id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return utils.Bool(false), nil + } + return nil, fmt.Errorf("retrieving %s: %+v", *id, err) + } + return utils.Bool(true), nil +} + +func TestAccMonitorDataCollectionRule_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_monitor_data_collection_rule", "test") + r := MonitorDataCollectionRuleResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccMonitorDataCollectionRule_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_monitor_data_collection_rule", "test") + r := MonitorDataCollectionRuleResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func TestAccMonitorDataCollectionRule_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_monitor_data_collection_rule", "test") + r := MonitorDataCollectionRuleResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.update(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccMonitorDataCollectionRule_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_monitor_data_collection_rule", "test") + r := MonitorDataCollectionRuleResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func (r MonitorDataCollectionRuleResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%[1]s + +resource "azurerm_monitor_data_collection_rule" "test" { + name = "acctestmdcr-%[2]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + destinations { + azure_monitor_metrics { + name = "test-destination-metrics" + } + } + data_flow { + streams = ["Microsoft-InsightsMetrics"] + destinations = ["test-destination-metrics"] + } +} +`, r.template(data), data.RandomInteger) +} + +func (r MonitorDataCollectionRuleResource) update(data acceptance.TestData) string { + return fmt.Sprintf(` +%[1]s + +resource "azurerm_log_analytics_workspace" "test1" { + name = "acctest-law-%[2]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_monitor_data_collection_rule" "test" { + name = "acctestmdcr-%[2]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + + destinations { + log_analytics { + workspace_resource_id = azurerm_log_analytics_workspace.test1.id + name = "test-destination-log" + } + azure_monitor_metrics { + name = "test-destination-metrics" + } + } + + data_flow { + streams = ["Microsoft-InsightsMetrics"] + destinations = ["test-destination-metrics"] + } + + data_flow { + streams = ["Microsoft-InsightsMetrics", "Microsoft-Syslog", "Microsoft-Perf"] + destinations = ["test-destination-log"] + } + + data_sources { + syslog { + facility_names = ["*"] + log_levels = ["*"] + name = "test-datasource-syslog" + } + performance_counter { + streams = ["Microsoft-Perf", "Microsoft-InsightsMetrics"] + sampling_frequency_in_seconds = 10 + counter_specifiers = ["Processor(*)\\%% Processor Time"] + name = "test-datasource-perfcounter" + } + } + + kind = "Linux" + description = "acc test monitor_data_collection_rule" + tags = { + ENV = "test" + } +} +`, r.template(data), data.RandomInteger) +} + +func (r MonitorDataCollectionRuleResource) complete(data acceptance.TestData) string { + return fmt.Sprintf(` +%[1]s + +resource "azurerm_log_analytics_workspace" "test1" { + name = "acctest-law-%[2]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_log_analytics_solution" "test1" { + solution_name = "WindowsEventForwarding" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + workspace_resource_id = azurerm_log_analytics_workspace.test1.id + workspace_name = azurerm_log_analytics_workspace.test1.name + plan { + publisher = "Microsoft" + product = "OMSGallery/WindowsEventForwarding" + } +} + +resource "azurerm_log_analytics_workspace" "test2" { + name = "acctest-law2-%[2]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_log_analytics_solution" "test2" { + solution_name = "WindowsEventForwarding" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + workspace_resource_id = azurerm_log_analytics_workspace.test1.id + workspace_name = azurerm_log_analytics_workspace.test1.name + plan { + publisher = "Microsoft" + product = "OMSGallery/WindowsEventForwarding" + } +} + +resource "azurerm_monitor_data_collection_rule" "test" { + name = "acctestmdcr-%[2]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + + destinations { + log_analytics { + workspace_resource_id = azurerm_log_analytics_workspace.test1.id + name = "test-destination-log1" + } + + log_analytics { + workspace_resource_id = azurerm_log_analytics_workspace.test2.id + name = "test-destination-log2" + } + + azure_monitor_metrics { + name = "test-destination-metrics" + } + } + + data_flow { + streams = ["Microsoft-InsightsMetrics"] + destinations = ["test-destination-metrics"] + } + + data_flow { + streams = ["Microsoft-InsightsMetrics", "Microsoft-Syslog", "Microsoft-Perf"] + destinations = ["test-destination-log1"] + } + + data_flow { + streams = ["Microsoft-Event", "Microsoft-WindowsEvent"] + destinations = ["test-destination-log1", "test-destination-log2"] + } + + data_sources { + syslog { + facility_names = [ + "auth", + "authpriv", + "cron", + "daemon", + "kern", + ] + log_levels = [ + "Debug", + "Info", + "Notice", + ] + name = "test-datasource-syslog" + } + + performance_counter { + streams = ["Microsoft-Perf", "Microsoft-InsightsMetrics"] + sampling_frequency_in_seconds = 10 + counter_specifiers = [ + "Processor(*)\\%% Processor Time", + "Processor(*)\\%% Idle Time", + "Processor(*)\\%% User Time", + "Processor(*)\\%% Nice Time", + "Processor(*)\\%% Privileged Time", + "Processor(*)\\%% IO Wait Time", + "Processor(*)\\%% Interrupt Time", + "Processor(*)\\%% DPC Time", + ] + name = "test-datasource-perfcounter" + } + + performance_counter { + streams = ["Microsoft-Perf"] + sampling_frequency_in_seconds = 20 + counter_specifiers = [ + "Network(*)\\Total Bytes Transmitted", + "Network(*)\\Total Bytes Received", + "Network(*)\\Total Bytes", + "Network(*)\\Total Packets Transmitted", + "Network(*)\\Total Packets Received", + "Network(*)\\Total Rx Errors", + "Network(*)\\Total Tx Errors", + "Network(*)\\Total Collisions" + ] + name = "test-datasource-perfcounter2" + } + + windows_event_log { + streams = ["Microsoft-WindowsEvent"] + x_path_queries = ["*[System/Level=1]"] + name = "test-datasource-wineventlog" + } + + extension { + streams = ["Microsoft-WindowsEvent"] + input_data_sources = ["test-datasource-wineventlog"] + extension_name = "test-extension-name" + extension_json = jsonencode({ + a = 1 + b = "hello" + }) + name = "test-datasource-extension" + } + } + + description = "acc test monitor_data_collection_rule complete" + tags = { + ENV = "test" + ENV2 = "test2" + } + + depends_on = [ + azurerm_log_analytics_solution.test1, + azurerm_log_analytics_solution.test2, + ] +} + + +`, r.template(data), data.RandomInteger) +} + +func (r MonitorDataCollectionRuleResource) requiresImport(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_monitor_data_collection_rule" "import" { + name = azurerm_monitor_data_collection_rule.test.name + resource_group_name = azurerm_monitor_data_collection_rule.test.resource_group_name + location = azurerm_monitor_data_collection_rule.test.location + destinations { + azure_monitor_metrics { + name = azurerm_monitor_data_collection_rule.test.destinations.0.azure_monitor_metrics.0.name + } + } + data_flow { + streams = azurerm_monitor_data_collection_rule.test.data_flow.0.streams + destinations = azurerm_monitor_data_collection_rule.test.data_flow.0.destinations + } +} +`, r.basic(data)) +} + +func (r MonitorDataCollectionRuleResource) template(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-DataCollectionRule-%[1]d" + location = "%[2]s" +} + +`, data.RandomInteger, data.Locations.Primary) +} diff --git a/internal/services/monitor/monitor_diagnostic_categories_data_source.go b/internal/services/monitor/monitor_diagnostic_categories_data_source.go index e95e3d2bdc80..6bf806fa63f2 100644 --- a/internal/services/monitor/monitor_diagnostic_categories_data_source.go +++ b/internal/services/monitor/monitor_diagnostic_categories_data_source.go @@ -5,15 +5,17 @@ import ( "strings" "time" - "github.com/Azure/azure-sdk-for-go/services/preview/monitor/mgmt/2021-07-01-preview/insights" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" + "github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-05-01-preview/diagnosticsettingscategories" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/features" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" ) func dataSourceMonitorDiagnosticCategories() *pluginsdk.Resource { - return &pluginsdk.Resource{ + resource := &pluginsdk.Resource{ Read: dataSourceMonitorDiagnosticCategoriesRead, Timeouts: &pluginsdk.ResourceTimeout{ @@ -27,7 +29,14 @@ func dataSourceMonitorDiagnosticCategories() *pluginsdk.Resource { ValidateFunc: azure.ValidateResourceID, }, - "logs": { + "log_category_types": { + Type: pluginsdk.TypeSet, + Elem: &pluginsdk.Schema{Type: pluginsdk.TypeString}, + Set: pluginsdk.HashString, + Computed: true, + }, + + "log_category_groups": { Type: pluginsdk.TypeSet, Elem: &pluginsdk.Schema{Type: pluginsdk.TypeString}, Set: pluginsdk.HashString, @@ -42,6 +51,18 @@ func dataSourceMonitorDiagnosticCategories() *pluginsdk.Resource { }, }, } + + if !features.FourPointOhBeta() { + resource.Schema["logs"] = &pluginsdk.Schema{ + Type: pluginsdk.TypeSet, + Elem: &pluginsdk.Schema{Type: pluginsdk.TypeString}, + Set: pluginsdk.HashString, + Computed: true, + Deprecated: "`logs` will be removed in favour of the property `log_category_types` in version 4.0 of the AzureRM Provider.", + } + } + + return resource } func dataSourceMonitorDiagnosticCategoriesRead(d *pluginsdk.ResourceData, meta interface{}) error { @@ -49,50 +70,71 @@ func dataSourceMonitorDiagnosticCategoriesRead(d *pluginsdk.ResourceData, meta i ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - actualResourceId := d.Get("resource_id").(string) + actualResourceId := commonids.NewScopeID(d.Get("resource_id").(string)) // trim off the leading `/` since the CheckExistenceByID / List methods don't expect it - resourceId := strings.TrimPrefix(actualResourceId, "/") + resourceId := strings.TrimPrefix(actualResourceId.Scope, "/") + resourceIdToList, err := commonids.ParseScopeID(resourceId) + if err != nil { + return fmt.Errorf("parsing resource id error: %+v", err) + } // then retrieve the possible Diagnostics Categories for this Resource - categories, err := categoriesClient.List(ctx, resourceId) + categories, err := categoriesClient.DiagnosticSettingsCategoryList(ctx, *resourceIdToList) if err != nil { return fmt.Errorf("retrieving Diagnostics Categories for Resource %q: %+v", actualResourceId, err) } - if categories.Value == nil { + if categories.Model == nil && categories.Model.Value == nil { return fmt.Errorf("retrieving Diagnostics Categories for Resource %q: `categories.Value` was nil", actualResourceId) } - d.SetId(actualResourceId) - val := *categories.Value + d.SetId(actualResourceId.ID()) + val := *categories.Model.Value metrics := make([]string, 0) logs := make([]string, 0) + categoryGroups := make([]string, 0) for _, v := range val { if v.Name == nil { continue } - if category := v.DiagnosticSettingsCategory; category != nil { - switch category.CategoryType { - case insights.CategoryTypeLogs: - logs = append(logs, *v.Name) - case insights.CategoryTypeMetrics: - metrics = append(metrics, *v.Name) - default: - return fmt.Errorf("Unsupported category type %q", string(category.CategoryType)) + if category := v.Properties; category != nil { + if category.CategoryGroups != nil { + for _, item := range *category.CategoryGroups { + categoryGroups = append(categoryGroups, item) + } + } + if category.CategoryType != nil { + switch *category.CategoryType { + case diagnosticsettingscategories.CategoryTypeLogs: + logs = append(logs, *v.Name) + case diagnosticsettingscategories.CategoryTypeMetrics: + metrics = append(metrics, *v.Name) + default: + return fmt.Errorf("Unsupported category type %q", string(*category.CategoryType)) + } } } } - if err := d.Set("logs", logs); err != nil { - return fmt.Errorf("setting `logs`: %+v", err) + if err := d.Set("log_category_types", logs); err != nil { + return fmt.Errorf("setting `log_category_types`: %+v", err) + } + + if !features.FourPointOhBeta() { + if err := d.Set("logs", logs); err != nil { + return fmt.Errorf("setting `log`: %+v", err) + } } if err := d.Set("metrics", metrics); err != nil { return fmt.Errorf("setting `metrics`: %+v", err) } + if err := d.Set("log_category_groups", categoryGroups); err != nil { + return fmt.Errorf("setting `log_category_groups`: %+v", err) + } return nil } diff --git a/internal/services/monitor/monitor_diagnostic_categories_data_source_test.go b/internal/services/monitor/monitor_diagnostic_categories_data_source_test.go index 50a045b45581..c93f9c2a940f 100644 --- a/internal/services/monitor/monitor_diagnostic_categories_data_source_test.go +++ b/internal/services/monitor/monitor_diagnostic_categories_data_source_test.go @@ -20,6 +20,8 @@ func TestAccDataSourceMonitorDiagnosticCategories_appService(t *testing.T) { Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).Key("metrics.#").Exists(), check.That(data.ResourceName).Key("logs.#").Exists(), + check.That(data.ResourceName).Key("log_category_types.#").Exists(), + check.That(data.ResourceName).Key("log_category_groups.#").Exists(), ), }, }) @@ -35,6 +37,8 @@ func TestAccDataSourceMonitorDiagnosticCategories_storageAccount(t *testing.T) { Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).Key("metrics.#").Exists(), check.That(data.ResourceName).Key("logs.#").Exists(), + check.That(data.ResourceName).Key("log_category_types.#").Exists(), + check.That(data.ResourceName).Key("log_category_groups.#").Exists(), ), }, }) diff --git a/internal/services/monitor/monitor_diagnostic_setting_resource.go b/internal/services/monitor/monitor_diagnostic_setting_resource.go index d13c4f2290ea..b7c05c3a67fe 100644 --- a/internal/services/monitor/monitor_diagnostic_setting_resource.go +++ b/internal/services/monitor/monitor_diagnostic_setting_resource.go @@ -1,21 +1,21 @@ package monitor import ( + "bytes" "context" "fmt" "log" "strings" "time" - "github.com/Azure/azure-sdk-for-go/services/preview/monitor/mgmt/2021-07-01-preview/insights" "github.com/hashicorp/go-azure-helpers/lang/response" - authRuleParse "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2017-04-01/authorizationrulesnamespaces" + authRuleParse "github.com/hashicorp/go-azure-sdk/resource-manager/eventhub/2021-11-01/authorizationrulesnamespaces" + "github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-05-01-preview/diagnosticsettings" + "github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" eventhubValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/eventhub/validate" - logAnalyticsParse "github.com/hashicorp/terraform-provider-azurerm/internal/services/loganalytics/parse" - logAnalyticsValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/loganalytics/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/services/monitor/validate" storageParse "github.com/hashicorp/terraform-provider-azurerm/internal/services/storage/parse" storageValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/storage/validate" @@ -76,7 +76,7 @@ func resourceMonitorDiagnosticSetting() *pluginsdk.Resource { "log_analytics_workspace_id": { Type: pluginsdk.TypeString, Optional: true, - ValidateFunc: logAnalyticsValidate.LogAnalyticsWorkspaceID, + ValidateFunc: workspaces.ValidateWorkspaceID, }, "storage_account_id": { @@ -103,7 +103,12 @@ func resourceMonitorDiagnosticSetting() *pluginsdk.Resource { Schema: map[string]*pluginsdk.Schema{ "category": { Type: pluginsdk.TypeString, - Required: true, + Optional: true, + }, + + "category_group": { + Type: pluginsdk.TypeString, + Optional: true, }, "enabled": { @@ -133,6 +138,7 @@ func resourceMonitorDiagnosticSetting() *pluginsdk.Resource { }, }, }, + Set: resourceMonitorDiagnosticLogSettingHash, }, "metric": { @@ -172,6 +178,7 @@ func resourceMonitorDiagnosticSetting() *pluginsdk.Resource { }, }, }, + Set: resourceMonitorDiagnosticMetricsSettingHash, }, }, } @@ -185,17 +192,18 @@ func resourceMonitorDiagnosticSettingCreateUpdate(d *pluginsdk.ResourceData, met name := d.Get("name").(string) actualResourceId := d.Get("target_resource_id").(string) + diagnosticSettingId := diagnosticsettings.NewScopedDiagnosticSettingID(actualResourceId, name) if d.IsNewResource() { - existing, err := client.Get(ctx, actualResourceId, name) + existing, err := client.Get(ctx, diagnosticSettingId) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { - return fmt.Errorf("checking for presence of existing Monitor Diagnostic Setting %q for Resource %q: %s", name, actualResourceId, err) + if !response.WasNotFound(existing.HttpResponse) { + return fmt.Errorf("checking for presence of existing Monitor Diagnostic Setting %q for Resource %q: %s", diagnosticSettingId.Name, diagnosticSettingId.ResourceUri, err) } } - if existing.ID != nil && *existing.ID != "" { - return tf.ImportAsExistsError("azurerm_monitor_diagnostic_setting", *existing.ID) + if existing.Model != nil && existing.Model.Id != nil && *existing.Model.Id != "" { + return tf.ImportAsExistsError("azurerm_monitor_diagnostic_setting", *existing.Model.Id) } } @@ -212,14 +220,14 @@ func resourceMonitorDiagnosticSettingCreateUpdate(d *pluginsdk.ResourceData, met // also if there's none enabled valid := false for _, v := range logs { - if v.Enabled != nil && *v.Enabled { + if v.Enabled { valid = true break } } if !valid { for _, v := range metrics { - if v.Enabled != nil && *v.Enabled { + if v.Enabled { valid = true break } @@ -230,8 +238,8 @@ func resourceMonitorDiagnosticSettingCreateUpdate(d *pluginsdk.ResourceData, met return fmt.Errorf("At least one `log` or `metric` must be enabled") } - properties := insights.DiagnosticSettingsResource{ - DiagnosticSettings: &insights.DiagnosticSettings{ + parameters := diagnosticsettings.DiagnosticSettingsResource{ + Properties: &diagnosticsettings.DiagnosticSettings{ Logs: &logs, Metrics: &metrics, }, @@ -241,26 +249,26 @@ func resourceMonitorDiagnosticSettingCreateUpdate(d *pluginsdk.ResourceData, met eventHubAuthorizationRuleId := d.Get("eventhub_authorization_rule_id").(string) eventHubName := d.Get("eventhub_name").(string) if eventHubAuthorizationRuleId != "" { - properties.DiagnosticSettings.EventHubAuthorizationRuleID = utils.String(eventHubAuthorizationRuleId) - properties.DiagnosticSettings.EventHubName = utils.String(eventHubName) + parameters.Properties.EventHubAuthorizationRuleId = utils.String(eventHubAuthorizationRuleId) + parameters.Properties.EventHubName = utils.String(eventHubName) valid = true } workspaceId := d.Get("log_analytics_workspace_id").(string) if workspaceId != "" { - properties.DiagnosticSettings.WorkspaceID = utils.String(workspaceId) + parameters.Properties.WorkspaceId = utils.String(workspaceId) valid = true } storageAccountId := d.Get("storage_account_id").(string) if storageAccountId != "" { - properties.DiagnosticSettings.StorageAccountID = utils.String(storageAccountId) + parameters.Properties.StorageAccountId = utils.String(storageAccountId) valid = true } if v := d.Get("log_analytics_destination_type").(string); v != "" { if workspaceId != "" { - properties.DiagnosticSettings.LogAnalyticsDestinationType = &v + parameters.Properties.LogAnalyticsDestinationType = &v } else { return fmt.Errorf("`log_analytics_workspace_id` must be set for `log_analytics_destination_type` to be used") } @@ -270,18 +278,16 @@ func resourceMonitorDiagnosticSettingCreateUpdate(d *pluginsdk.ResourceData, met return fmt.Errorf("Either a `eventhub_authorization_rule_id`, `log_analytics_workspace_id` or `storage_account_id` must be set") } - // the Azure SDK prefixes the URI with a `/` such this makes a bad request if we don't trim the `/` - targetResourceId := strings.TrimPrefix(actualResourceId, "/") - if _, err := client.CreateOrUpdate(ctx, targetResourceId, properties, name); err != nil { + if _, err := client.CreateOrUpdate(ctx, diagnosticSettingId, parameters); err != nil { return fmt.Errorf("creating Monitor Diagnostics Setting %q for Resource %q: %+v", name, actualResourceId, err) } - read, err := client.Get(ctx, targetResourceId, name) + read, err := client.Get(ctx, diagnosticSettingId) if err != nil { return err } - if read.ID == nil { - return fmt.Errorf("Cannot read ID for Monitor Diagnostics %q for Resource ID %q", name, actualResourceId) + if read.Model == nil && read.Model.Id == nil { + return fmt.Errorf("Cannot read ID for Monitor Diagnostics %q for Resource ID %q", diagnosticSettingId.Name, diagnosticSettingId.ResourceUri) } d.SetId(fmt.Sprintf("%s|%s", actualResourceId, name)) @@ -299,11 +305,10 @@ func resourceMonitorDiagnosticSettingRead(d *pluginsdk.ResourceData, meta interf return err } - actualResourceId := id.ResourceID - targetResourceId := strings.TrimPrefix(actualResourceId, "/") - resp, err := client.Get(ctx, targetResourceId, id.Name) + actualResourceId := id.ResourceUri + resp, err := client.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { log.Printf("[WARN] Monitor Diagnostics Setting %q was not found for Resource %q - removing from state!", id.Name, actualResourceId) d.SetId("") return nil @@ -313,51 +318,54 @@ func resourceMonitorDiagnosticSettingRead(d *pluginsdk.ResourceData, meta interf } d.Set("name", id.Name) - d.Set("target_resource_id", id.ResourceID) - - d.Set("eventhub_name", resp.EventHubName) - eventhubAuthorizationRuleId := "" - if resp.EventHubAuthorizationRuleID != nil && *resp.EventHubAuthorizationRuleID != "" { - authRuleId := utils.NormalizeNilableString(resp.EventHubAuthorizationRuleID) - parsedId, err := authRuleParse.ParseAuthorizationRuleIDInsensitively(authRuleId) - if err != nil { - return err - } - - eventhubAuthorizationRuleId = parsedId.ID() - } - d.Set("eventhub_authorization_rule_id", eventhubAuthorizationRuleId) + d.Set("target_resource_id", id.ResourceUri) + + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("eventhub_name", props.EventHubName) + eventhubAuthorizationRuleId := "" + if props.EventHubAuthorizationRuleId != nil && *props.EventHubAuthorizationRuleId != "" { + authRuleId := utils.NormalizeNilableString(props.EventHubAuthorizationRuleId) + parsedId, err := authRuleParse.ParseAuthorizationRuleIDInsensitively(authRuleId) + if err != nil { + return err + } + eventhubAuthorizationRuleId = parsedId.ID() + } + d.Set("eventhub_authorization_rule_id", eventhubAuthorizationRuleId) - workspaceId := "" - if resp.WorkspaceID != nil && *resp.WorkspaceID != "" { - parsedId, err := logAnalyticsParse.LogAnalyticsWorkspaceID(*resp.WorkspaceID) - if err != nil { - return err - } + workspaceId := "" + if props.WorkspaceId != nil && *props.WorkspaceId != "" { + parsedId, err := workspaces.ParseWorkspaceID(*props.WorkspaceId) + if err != nil { + return err + } - workspaceId = parsedId.ID() - } - d.Set("log_analytics_workspace_id", workspaceId) + workspaceId = parsedId.ID() + } + d.Set("log_analytics_workspace_id", workspaceId) - storageAccountId := "" - if resp.StorageAccountID != nil && *resp.StorageAccountID != "" { - parsedId, err := storageParse.StorageAccountID(*resp.StorageAccountID) - if err != nil { - return err - } + storageAccountId := "" + if props.StorageAccountId != nil && *props.StorageAccountId != "" { + parsedId, err := storageParse.StorageAccountID(*props.StorageAccountId) + if err != nil { + return err + } - storageAccountId = parsedId.ID() - } - d.Set("storage_account_id", storageAccountId) + storageAccountId = parsedId.ID() + d.Set("storage_account_id", storageAccountId) + } - d.Set("log_analytics_destination_type", resp.LogAnalyticsDestinationType) + d.Set("log_analytics_destination_type", resp.Model.Properties.LogAnalyticsDestinationType) - if err := d.Set("log", flattenMonitorDiagnosticLogs(resp.Logs)); err != nil { - return fmt.Errorf("setting `log`: %+v", err) - } + if err := d.Set("log", flattenMonitorDiagnosticLogs(resp.Model.Properties.Logs)); err != nil { + return fmt.Errorf("setting `log`: %+v", err) + } - if err := d.Set("metric", flattenMonitorDiagnosticMetrics(resp.Metrics)); err != nil { - return fmt.Errorf("setting `metric`: %+v", err) + if err := d.Set("metric", flattenMonitorDiagnosticMetrics(resp.Model.Properties.Metrics)); err != nil { + return fmt.Errorf("setting `metric`: %+v", err) + } + } } return nil @@ -373,37 +381,36 @@ func resourceMonitorDiagnosticSettingDelete(d *pluginsdk.ResourceData, meta inte return err } - targetResourceId := strings.TrimPrefix(id.ResourceID, "/") - resp, err := client.Delete(ctx, targetResourceId, id.Name) + resp, err := client.Delete(ctx, *id) if err != nil { - if !response.WasNotFound(resp.Response) { - return fmt.Errorf("deleting Monitor Diagnostics Setting %q for Resource %q: %+v", id.Name, targetResourceId, err) + if !response.WasNotFound(resp.HttpResponse) { + return fmt.Errorf("deleting Monitor Diagnostics Setting %q for Resource %q: %+v", id.Name, id.ResourceUri, err) } } // API appears to be eventually consistent (identified during tainting this resource) - log.Printf("[DEBUG] Waiting for Monitor Diagnostic Setting %q for Resource %q to disappear", id.Name, id.ResourceID) + log.Printf("[DEBUG] Waiting for Monitor Diagnostic Setting %q for Resource %q to disappear", id.Name, id.ResourceUri) stateConf := &pluginsdk.StateChangeConf{ Pending: []string{"Exists"}, Target: []string{"NotFound"}, - Refresh: monitorDiagnosticSettingDeletedRefreshFunc(ctx, client, targetResourceId, id.Name), + Refresh: monitorDiagnosticSettingDeletedRefreshFunc(ctx, client, *id), MinTimeout: 15 * time.Second, ContinuousTargetOccurence: 5, Timeout: d.Timeout(pluginsdk.TimeoutDelete), } if _, err = stateConf.WaitForStateContext(ctx); err != nil { - return fmt.Errorf("waiting for Monitor Diagnostic Setting %q for Resource %q to become available: %s", id.Name, id.ResourceID, err) + return fmt.Errorf("waiting for Monitor Diagnostic Setting %q for Resource %q to become available: %s", id.Name, id.ResourceUri, err) } return nil } -func monitorDiagnosticSettingDeletedRefreshFunc(ctx context.Context, client *insights.DiagnosticSettingsClient, targetResourceId string, name string) pluginsdk.StateRefreshFunc { +func monitorDiagnosticSettingDeletedRefreshFunc(ctx context.Context, client *diagnosticsettings.DiagnosticSettingsClient, targetResourceId diagnosticsettings.ScopedDiagnosticSettingId) pluginsdk.StateRefreshFunc { return func() (interface{}, string, error) { - res, err := client.Get(ctx, targetResourceId, name) + res, err := client.Get(ctx, targetResourceId) if err != nil { - if utils.ResponseWasNotFound(res.Response) { + if response.WasNotFound(res.HttpResponse) { return "NotFound", "NotFound", nil } return nil, "", fmt.Errorf("issuing read request in monitorDiagnosticSettingDeletedRefreshFunc: %s", err) @@ -413,31 +420,36 @@ func monitorDiagnosticSettingDeletedRefreshFunc(ctx context.Context, client *ins } } -func expandMonitorDiagnosticsSettingsLogs(input []interface{}) []insights.LogSettings { - results := make([]insights.LogSettings, 0) +func expandMonitorDiagnosticsSettingsLogs(input []interface{}) []diagnosticsettings.LogSettings { + results := make([]diagnosticsettings.LogSettings, 0) for _, raw := range input { v := raw.(map[string]interface{}) category := v["category"].(string) + categoryGroup := v["category_group"].(string) enabled := v["enabled"].(bool) policiesRaw := v["retention_policy"].([]interface{}) - var retentionPolicy *insights.RetentionPolicy + var retentionPolicy *diagnosticsettings.RetentionPolicy if len(policiesRaw) != 0 { policyRaw := policiesRaw[0].(map[string]interface{}) retentionDays := policyRaw["days"].(int) retentionEnabled := policyRaw["enabled"].(bool) - retentionPolicy = &insights.RetentionPolicy{ - Days: utils.Int32(int32(retentionDays)), - Enabled: utils.Bool(retentionEnabled), + retentionPolicy = &diagnosticsettings.RetentionPolicy{ + Days: int64(retentionDays), + Enabled: retentionEnabled, } } - output := insights.LogSettings{ - Category: utils.String(category), - Enabled: utils.Bool(enabled), + output := diagnosticsettings.LogSettings{ + Enabled: enabled, RetentionPolicy: retentionPolicy, } + if category != "" { + output.Category = utils.String(category) + } else { + output.CategoryGroup = utils.String(categoryGroup) + } results = append(results, output) } @@ -445,7 +457,7 @@ func expandMonitorDiagnosticsSettingsLogs(input []interface{}) []insights.LogSet return results } -func flattenMonitorDiagnosticLogs(input *[]insights.LogSettings) []interface{} { +func flattenMonitorDiagnosticLogs(input *[]diagnosticsettings.LogSettings) []interface{} { results := make([]interface{}, 0) if input == nil { return results @@ -458,22 +470,20 @@ func flattenMonitorDiagnosticLogs(input *[]insights.LogSettings) []interface{} { output["category"] = *v.Category } - if v.Enabled != nil { - output["enabled"] = *v.Enabled + if v.CategoryGroup != nil { + output["category_group"] = *v.CategoryGroup } + output["enabled"] = v.Enabled + policies := make([]interface{}, 0) if inputPolicy := v.RetentionPolicy; inputPolicy != nil { outputPolicy := make(map[string]interface{}) - if inputPolicy.Days != nil { - outputPolicy["days"] = int(*inputPolicy.Days) - } + outputPolicy["days"] = int(inputPolicy.Days) - if inputPolicy.Enabled != nil { - outputPolicy["enabled"] = *inputPolicy.Enabled - } + outputPolicy["enabled"] = inputPolicy.Enabled policies = append(policies, outputPolicy) } @@ -486,8 +496,8 @@ func flattenMonitorDiagnosticLogs(input *[]insights.LogSettings) []interface{} { return results } -func expandMonitorDiagnosticsSettingsMetrics(input []interface{}) []insights.MetricSettings { - results := make([]insights.MetricSettings, 0) +func expandMonitorDiagnosticsSettingsMetrics(input []interface{}) []diagnosticsettings.MetricSettings { + results := make([]diagnosticsettings.MetricSettings, 0) for _, raw := range input { v := raw.(map[string]interface{}) @@ -496,19 +506,19 @@ func expandMonitorDiagnosticsSettingsMetrics(input []interface{}) []insights.Met enabled := v["enabled"].(bool) policiesRaw := v["retention_policy"].([]interface{}) - var retentionPolicy *insights.RetentionPolicy + var retentionPolicy *diagnosticsettings.RetentionPolicy if len(policiesRaw) > 0 && policiesRaw[0] != nil { policyRaw := policiesRaw[0].(map[string]interface{}) retentionDays := policyRaw["days"].(int) retentionEnabled := policyRaw["enabled"].(bool) - retentionPolicy = &insights.RetentionPolicy{ - Days: utils.Int32(int32(retentionDays)), - Enabled: utils.Bool(retentionEnabled), + retentionPolicy = &diagnosticsettings.RetentionPolicy{ + Days: int64(retentionDays), + Enabled: retentionEnabled, } } - output := insights.MetricSettings{ + output := diagnosticsettings.MetricSettings{ Category: utils.String(category), - Enabled: utils.Bool(enabled), + Enabled: enabled, RetentionPolicy: retentionPolicy, } @@ -518,7 +528,7 @@ func expandMonitorDiagnosticsSettingsMetrics(input []interface{}) []insights.Met return results } -func flattenMonitorDiagnosticMetrics(input *[]insights.MetricSettings) []interface{} { +func flattenMonitorDiagnosticMetrics(input *[]diagnosticsettings.MetricSettings) []interface{} { results := make([]interface{}, 0) if input == nil { return results @@ -531,22 +541,16 @@ func flattenMonitorDiagnosticMetrics(input *[]insights.MetricSettings) []interfa output["category"] = *v.Category } - if v.Enabled != nil { - output["enabled"] = *v.Enabled - } + output["enabled"] = v.Enabled policies := make([]interface{}, 0) if inputPolicy := v.RetentionPolicy; inputPolicy != nil { outputPolicy := make(map[string]interface{}) - if inputPolicy.Days != nil { - outputPolicy["days"] = int(*inputPolicy.Days) - } + outputPolicy["days"] = int(inputPolicy.Days) - if inputPolicy.Enabled != nil { - outputPolicy["enabled"] = *inputPolicy.Enabled - } + outputPolicy["enabled"] = inputPolicy.Enabled policies = append(policies, outputPolicy) } @@ -559,20 +563,60 @@ func flattenMonitorDiagnosticMetrics(input *[]insights.MetricSettings) []interfa return results } -type monitorDiagnosticId struct { - ResourceID string - Name string -} - -func ParseMonitorDiagnosticId(monitorId string) (*monitorDiagnosticId, error) { +func ParseMonitorDiagnosticId(monitorId string) (*diagnosticsettings.ScopedDiagnosticSettingId, error) { v := strings.Split(monitorId, "|") if len(v) != 2 { return nil, fmt.Errorf("Expected the Monitor Diagnostics ID to be in the format `{resourceId}|{name}` but got %d segments", len(v)) } - identifier := monitorDiagnosticId{ - ResourceID: v[0], - Name: v[1], + identifier := diagnosticsettings.ScopedDiagnosticSettingId{ + ResourceUri: v[0], + Name: v[1], } return &identifier, nil } + +func resourceMonitorDiagnosticLogSettingHash(input interface{}) int { + var buf bytes.Buffer + if rawData, ok := input.(map[string]interface{}); ok { + if category, ok := rawData["category"]; ok { + buf.WriteString(fmt.Sprintf("%s-", category.(string))) + } + if categoryGroup, ok := rawData["category_group"]; ok { + buf.WriteString(fmt.Sprintf("%s-", categoryGroup.(string))) + } + if enabled, ok := rawData["enabled"]; ok { + buf.WriteString(fmt.Sprintf("%t-", enabled.(bool))) + } + if policy, ok := rawData["retention_policy"].(map[string]interface{}); ok { + if policyEnabled, ok := policy["enabled"]; ok { + buf.WriteString(fmt.Sprintf("%t-", policyEnabled.(bool))) + } + if days, ok := policy["days"]; ok { + buf.WriteString(fmt.Sprintf("%d-", days.(int))) + } + } + } + return pluginsdk.HashString(buf.String()) +} + +func resourceMonitorDiagnosticMetricsSettingHash(input interface{}) int { + var buf bytes.Buffer + if rawData, ok := input.(map[string]interface{}); ok { + if category, ok := rawData["category"]; ok { + buf.WriteString(fmt.Sprintf("%s-", category.(string))) + } + if enabled, ok := rawData["enabled"]; ok { + buf.WriteString(fmt.Sprintf("%t-", enabled.(bool))) + } + if policy, ok := rawData["retention_policy"].(map[string]interface{}); ok { + if policyEnabled, ok := policy["enabled"]; ok { + buf.WriteString(fmt.Sprintf("%t-", policyEnabled.(bool))) + } + if days, ok := policy["days"]; ok { + buf.WriteString(fmt.Sprintf("%d-", days.(int))) + } + } + } + return pluginsdk.HashString(buf.String()) +} diff --git a/internal/services/monitor/monitor_diagnostic_setting_resource_test.go b/internal/services/monitor/monitor_diagnostic_setting_resource_test.go index b0d910a18aa1..6b815a82b277 100644 --- a/internal/services/monitor/monitor_diagnostic_setting_resource_test.go +++ b/internal/services/monitor/monitor_diagnostic_setting_resource_test.go @@ -3,7 +3,6 @@ package monitor_test import ( "context" "fmt" - "strings" "testing" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" @@ -34,6 +33,24 @@ func TestAccMonitorDiagnosticSetting_eventhub(t *testing.T) { }) } +func TestAccMonitorDiagnosticSetting_CategoryGroup(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_monitor_diagnostic_setting", "test") + r := MonitorDiagnosticSettingResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.categoryGroup(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("eventhub_name").Exists(), + check.That(data.ResourceName).Key("eventhub_authorization_rule_id").Exists(), + check.That(data.ResourceName).Key("log.#").HasValue("2"), + check.That(data.ResourceName).Key("metric.#").HasValue("1"), + ), + }, + data.ImportStep(), + }) +} + func TestAccMonitorDiagnosticSetting_requiresImport(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_monitor_diagnostic_setting", "test") r := MonitorDiagnosticSettingResource{} @@ -123,15 +140,15 @@ func (t MonitorDiagnosticSettingResource) Exists(ctx context.Context, clients *c if err != nil { return nil, err } - actualResourceId := id.ResourceID - targetResourceId := strings.TrimPrefix(actualResourceId, "/") + // actualResourceId := id.ResourceUri + // targetResourceId := strings.TrimPrefix(actualResourceId, "/") - resp, err := clients.Monitor.DiagnosticSettingsClient.Get(ctx, targetResourceId, id.Name) + resp, err := clients.Monitor.DiagnosticSettingsClient.Get(ctx, *id) if err != nil { return nil, fmt.Errorf("reading diagnostic setting (%s): %+v", id, err) } - return utils.Bool(resp.ID != nil), nil + return utils.Bool(resp.Model != nil && resp.Model.Id != nil), nil } func (MonitorDiagnosticSettingResource) eventhub(data acceptance.TestData) string { @@ -218,6 +235,88 @@ resource "azurerm_monitor_diagnostic_setting" "test" { `, data.RandomInteger, data.Locations.Primary, data.RandomIntOfLength(17)) } +func (MonitorDiagnosticSettingResource) categoryGroup(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +data "azurerm_client_config" "current" { +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%[1]d" + location = "%[2]s" +} + +resource "azurerm_eventhub_namespace" "test" { + name = "acctest-EHN-%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku = "Basic" +} + +resource "azurerm_eventhub" "test" { + name = "acctest-EH-%[1]d" + namespace_name = azurerm_eventhub_namespace.test.name + resource_group_name = azurerm_resource_group.test.name + partition_count = 2 + message_retention = 1 +} + +resource "azurerm_eventhub_namespace_authorization_rule" "test" { + name = "example" + namespace_name = azurerm_eventhub_namespace.test.name + resource_group_name = azurerm_resource_group.test.name + listen = true + send = true + manage = true +} + +resource "azurerm_key_vault" "test" { + name = "acctest%[3]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + tenant_id = data.azurerm_client_config.current.tenant_id + sku_name = "standard" +} + +resource "azurerm_monitor_diagnostic_setting" "test" { + name = "acctest-DS-%[1]d" + target_resource_id = azurerm_key_vault.test.id + eventhub_authorization_rule_id = azurerm_eventhub_namespace_authorization_rule.test.id + eventhub_name = azurerm_eventhub.test.name + + log { + category_group = "Audit" + enabled = true + + retention_policy { + days = 0 + enabled = false + } + } + + log { + category_group = "allLogs" + enabled = false + + retention_policy { + days = 0 + enabled = false + } + } + + metric { + category = "AllMetrics" + + retention_policy { + enabled = false + } + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomIntOfLength(17)) +} func (r MonitorDiagnosticSettingResource) requiresImport(data acceptance.TestData) string { return fmt.Sprintf(` %s @@ -436,56 +535,6 @@ resource "azurerm_monitor_diagnostic_setting" "test" { } } - log { - category = "AirflowDagProcessingLogs" - enabled = false - - retention_policy { - days = 0 - enabled = false - } - } - - log { - category = "AirflowSchedulerLogs" - enabled = false - - retention_policy { - days = 0 - enabled = false - } - } - - log { - category = "AirflowTaskLogs" - enabled = false - - retention_policy { - days = 0 - enabled = false - } - } - - log { - category = "AirflowWebLogs" - enabled = false - - retention_policy { - days = 0 - enabled = false - } - } - - log { - category = "AirflowWorkerLogs" - enabled = false - - retention_policy { - days = 0 - enabled = false - } - } - metric { category = "AllMetrics" retention_policy { diff --git a/internal/services/monitor/monitor_private_link_scoped_service_resource.go b/internal/services/monitor/monitor_private_link_scoped_service_resource.go index ad289416f588..2c708e4699a1 100644 --- a/internal/services/monitor/monitor_private_link_scoped_service_resource.go +++ b/internal/services/monitor/monitor_private_link_scoped_service_resource.go @@ -6,11 +6,11 @@ import ( "time" "github.com/Azure/azure-sdk-for-go/services/preview/monitor/mgmt/2021-07-01-preview/insights" + "github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" applicationinsightsvalidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/applicationinsights/validate" - loganalyticsValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/loganalytics/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/services/monitor/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/monitor/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" @@ -62,7 +62,7 @@ func resourceMonitorPrivateLinkScopedService() *pluginsdk.Resource { DiffSuppressFunc: suppress.CaseDifference, ValidateFunc: validation.Any( applicationinsightsvalidate.ComponentID, - loganalyticsValidate.LogAnalyticsWorkspaceID, + workspaces.ValidateWorkspaceID, ), }, }, diff --git a/internal/services/monitor/monitor_scheduled_query_rules_alert_v2_resource.go b/internal/services/monitor/monitor_scheduled_query_rules_alert_v2_resource.go new file mode 100644 index 000000000000..5420002f3da4 --- /dev/null +++ b/internal/services/monitor/monitor_scheduled_query_rules_alert_v2_resource.go @@ -0,0 +1,895 @@ +package monitor + +import ( + "context" + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-08-01/scheduledqueryrules" + "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" + helperValidate "github.com/hashicorp/terraform-provider-azurerm/helpers/validate" + "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" +) + +type ScheduledQueryRulesAlertV2Model struct { + Name string `tfschema:"name"` + ResourceGroupName string `tfschema:"resource_group_name"` + Actions []ScheduledQueryRulesAlertV2ActionsModel `tfschema:"action"` + AutoMitigate bool `tfschema:"auto_mitigation_enabled"` + CheckWorkspaceAlertsStorageConfigured bool `tfschema:"workspace_alerts_storage_enabled"` + Criteria []ScheduledQueryRulesAlertV2CriteriaModel `tfschema:"criteria"` + Description string `tfschema:"description"` + DisplayName string `tfschema:"display_name"` + Enabled bool `tfschema:"enabled"` + EvaluationFrequency string `tfschema:"evaluation_frequency"` + Location string `tfschema:"location"` + MuteActionsDuration string `tfschema:"mute_actions_after_alert_duration"` + OverrideQueryTimeRange string `tfschema:"query_time_range_override"` + Scopes []string `tfschema:"scopes"` + Severity scheduledqueryrules.AlertSeverity `tfschema:"severity"` + SkipQueryValidation bool `tfschema:"skip_query_validation"` + Tags map[string]string `tfschema:"tags"` + TargetResourceTypes []string `tfschema:"target_resource_types"` + WindowSize string `tfschema:"window_duration"` + CreatedWithApiVersion string `tfschema:"created_with_api_version"` + IsLegacyLogAnalyticsRule bool `tfschema:"is_a_legacy_log_analytics_rule"` + IsWorkspaceAlertsStorageConfigured bool `tfschema:"is_workspace_alerts_storage_configured"` +} + +type ScheduledQueryRulesAlertV2ActionsModel struct { + ActionGroups []string `tfschema:"action_groups"` + CustomProperties map[string]string `tfschema:"custom_properties"` +} + +type ScheduledQueryRulesAlertV2CriteriaModel struct { + Dimensions []ScheduledQueryRulesAlertV2DimensionModel `tfschema:"dimension"` + FailingPeriods []ScheduledQueryRulesAlertV2FailingPeriodsModel `tfschema:"failing_periods"` + MetricMeasureColumn string `tfschema:"metric_measure_column"` + Operator scheduledqueryrules.ConditionOperator `tfschema:"operator"` + Query string `tfschema:"query"` + ResourceIdColumn string `tfschema:"resource_id_column"` + Threshold float64 `tfschema:"threshold"` + TimeAggregation scheduledqueryrules.TimeAggregation `tfschema:"time_aggregation_method"` +} + +type ScheduledQueryRulesAlertV2DimensionModel struct { + Name string `tfschema:"name"` + Operator scheduledqueryrules.DimensionOperator `tfschema:"operator"` + Values []string `tfschema:"values"` +} + +type ScheduledQueryRulesAlertV2FailingPeriodsModel struct { + MinFailingPeriodsToAlert int64 `tfschema:"minimum_failing_periods_to_trigger_alert"` + NumberOfEvaluationPeriods int64 `tfschema:"number_of_evaluation_periods"` +} + +type ScheduledQueryRulesAlertV2Resource struct{} + +var _ sdk.ResourceWithUpdate = ScheduledQueryRulesAlertV2Resource{} + +func (r ScheduledQueryRulesAlertV2Resource) ResourceType() string { + return "azurerm_monitor_scheduled_query_rules_alert_v2" +} + +func (r ScheduledQueryRulesAlertV2Resource) ModelObject() interface{} { + return &ScheduledQueryRulesAlertV2Model{} +} + +func (r ScheduledQueryRulesAlertV2Resource) IDValidationFunc() pluginsdk.SchemaValidateFunc { + return scheduledqueryrules.ValidateScheduledQueryRuleID +} + +func (r ScheduledQueryRulesAlertV2Resource) Arguments() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "resource_group_name": commonschema.ResourceGroupName(), + + "location": commonschema.Location(), + + "criteria": { + Type: pluginsdk.TypeList, + Required: true, + MinItems: 1, + Elem: &pluginsdk.Resource{ + + Schema: map[string]*pluginsdk.Schema{ + "query": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "operator": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(scheduledqueryrules.ConditionOperatorEquals), + string(scheduledqueryrules.ConditionOperatorGreaterThan), + string(scheduledqueryrules.ConditionOperatorGreaterThanOrEqual), + string(scheduledqueryrules.ConditionOperatorLessThan), + string(scheduledqueryrules.ConditionOperatorLessThanOrEqual), + }, false), + }, + + "time_aggregation_method": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(scheduledqueryrules.TimeAggregationCount), + string(scheduledqueryrules.TimeAggregationAverage), + string(scheduledqueryrules.TimeAggregationMinimum), + string(scheduledqueryrules.TimeAggregationMaximum), + string(scheduledqueryrules.TimeAggregationTotal), + }, false), + }, + + "threshold": { + Type: pluginsdk.TypeFloat, + Required: true, + }, + + "dimension": { + Type: pluginsdk.TypeList, + Optional: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "operator": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(scheduledqueryrules.DimensionOperatorInclude), + string(scheduledqueryrules.DimensionOperatorExclude), + }, false), + }, + + "values": { + Type: pluginsdk.TypeList, + Required: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, + }, + }, + }, + + "failing_periods": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "minimum_failing_periods_to_trigger_alert": { + Type: pluginsdk.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(1, 6), + }, + + "number_of_evaluation_periods": { + Type: pluginsdk.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(1, 6), + }, + }, + }, + }, + + "metric_measure_column": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "resource_id_column": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, + }, + }, + + "evaluation_frequency": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: helperValidate.ISO8601Duration, + }, + + "scopes": { + Type: pluginsdk.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + ForceNew: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: azure.ValidateResourceID, + }, + }, + + "severity": { + Type: pluginsdk.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(0, 4), + }, + + "window_duration": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: helperValidate.ISO8601Duration, + }, + + "action": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "action_groups": { + Type: pluginsdk.TypeList, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: azure.ValidateResourceID, + }, + }, + + "custom_properties": { + Type: pluginsdk.TypeMap, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + }, + }, + }, + }, + }, + + "auto_mitigation_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: false, + }, + + "workspace_alerts_storage_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: false, + }, + + "description": { + Type: pluginsdk.TypeString, + Optional: true, + }, + + "display_name": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: true, + }, + + "mute_actions_after_alert_duration": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: helperValidate.ISO8601Duration, + }, + + "query_time_range_override": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: helperValidate.ISO8601Duration, + }, + + "skip_query_validation": { + Type: pluginsdk.TypeBool, + Optional: true, + }, + + "tags": commonschema.Tags(), + + "target_resource_types": { + Type: pluginsdk.TypeList, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, + } +} + +func (r ScheduledQueryRulesAlertV2Resource) Attributes() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "created_with_api_version": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "is_a_legacy_log_analytics_rule": { + Type: pluginsdk.TypeBool, + Computed: true, + }, + + "is_workspace_alerts_storage_configured": { + Type: pluginsdk.TypeBool, + Computed: true, + }, + } +} + +func (r ScheduledQueryRulesAlertV2Resource) Create() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + var model ScheduledQueryRulesAlertV2Model + if err := metadata.Decode(&model); err != nil { + return fmt.Errorf("decoding: %+v", err) + } + + client := metadata.Client.Monitor.ScheduledQueryRulesV2Client + subscriptionId := metadata.Client.Account.SubscriptionId + id := scheduledqueryrules.NewScheduledQueryRuleID(subscriptionId, model.ResourceGroupName, model.Name) + existing, err := client.Get(ctx, id) + if err != nil && !response.WasNotFound(existing.HttpResponse) { + return fmt.Errorf("checking for existing %s: %+v", id, err) + } + + if !response.WasNotFound(existing.HttpResponse) { + return metadata.ResourceRequiresImport(r.ResourceType(), id) + } + kind := scheduledqueryrules.KindLogAlert + properties := &scheduledqueryrules.ScheduledQueryRuleResource{ + Kind: &kind, + Location: location.Normalize(model.Location), + Properties: scheduledqueryrules.ScheduledQueryRuleProperties{ + AutoMitigate: &model.AutoMitigate, + CheckWorkspaceAlertsStorageConfigured: &model.CheckWorkspaceAlertsStorageConfigured, + Enabled: &model.Enabled, + Scopes: &model.Scopes, + Severity: &model.Severity, + SkipQueryValidation: &model.SkipQueryValidation, + TargetResourceTypes: &model.TargetResourceTypes, + }, + Tags: &model.Tags, + } + + actionsValue, err := expandScheduledQueryRulesAlertV2ActionsModel(model.Actions) + if err != nil { + return err + } + + properties.Properties.Actions = actionsValue + + criteriaValue, err := expandScheduledQueryRulesAlertV2CriteriaModel(model.Criteria) + if err != nil { + return err + } + + properties.Properties.Criteria = criteriaValue + + if model.Description != "" { + properties.Properties.Description = &model.Description + } + + if model.DisplayName != "" { + properties.Properties.DisplayName = &model.DisplayName + } + + if model.EvaluationFrequency != "" { + properties.Properties.EvaluationFrequency = &model.EvaluationFrequency + } + + if model.MuteActionsDuration != "" { + if model.AutoMitigate { + return fmt.Errorf("auto mitigation must be disabled when mute action duration is set") + } + properties.Properties.MuteActionsDuration = &model.MuteActionsDuration + } + + if model.OverrideQueryTimeRange != "" { + properties.Properties.OverrideQueryTimeRange = &model.OverrideQueryTimeRange + } + + if model.WindowSize != "" { + properties.Properties.WindowSize = &model.WindowSize + } + + if _, err := client.CreateOrUpdate(ctx, id, *properties); err != nil { + return fmt.Errorf("creating %s: %+v", id, err) + } + + metadata.SetID(id) + return nil + }, + } +} + +func (r ScheduledQueryRulesAlertV2Resource) Update() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.Monitor.ScheduledQueryRulesV2Client + + id, err := scheduledqueryrules.ParseScheduledQueryRuleID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + var resourceModel ScheduledQueryRulesAlertV2Model + if err := metadata.Decode(&resourceModel); err != nil { + return fmt.Errorf("decoding: %+v", err) + } + + resp, err := client.Get(ctx, *id) + if err != nil { + return fmt.Errorf("retrieving %s: %+v", *id, err) + } + + model := resp.Model + if model == nil { + return fmt.Errorf("retrieving %s: model was nil", id) + } + + if metadata.ResourceData.HasChange("action") { + actionsValue, err := expandScheduledQueryRulesAlertV2ActionsModel(resourceModel.Actions) + if err != nil { + return err + } + + model.Properties.Actions = actionsValue + } + + if metadata.ResourceData.HasChange("auto_mitigation_enabled") { + model.Properties.AutoMitigate = &resourceModel.AutoMitigate + } + + if metadata.ResourceData.HasChange("workspace_alerts_storage_enabled") { + model.Properties.CheckWorkspaceAlertsStorageConfigured = &resourceModel.CheckWorkspaceAlertsStorageConfigured + } + + if metadata.ResourceData.HasChange("criteria") { + criteriaValue, err := expandScheduledQueryRulesAlertV2CriteriaModel(resourceModel.Criteria) + if err != nil { + return err + } + + model.Properties.Criteria = criteriaValue + } + + if metadata.ResourceData.HasChange("description") { + model.Properties.Description = &resourceModel.Description + } + + if metadata.ResourceData.HasChange("display_name") { + if resourceModel.DisplayName != "" { + model.Properties.DisplayName = &resourceModel.DisplayName + } else { + model.Properties.DisplayName = nil + } + } + + if metadata.ResourceData.HasChange("enabled") { + model.Properties.Enabled = &resourceModel.Enabled + } + + if metadata.ResourceData.HasChange("evaluation_frequency") { + model.Properties.EvaluationFrequency = &resourceModel.EvaluationFrequency + } + + if metadata.ResourceData.HasChange("mute_actions_after_alert_duration") { + if resourceModel.MuteActionsDuration != "" { + if resourceModel.AutoMitigate { + return fmt.Errorf("auto mitigation must be disabled when mute action duration is set") + } + model.Properties.MuteActionsDuration = &resourceModel.MuteActionsDuration + } else { + model.Properties.MuteActionsDuration = nil + } + } + + if metadata.ResourceData.HasChange("query_time_range_override") { + if resourceModel.OverrideQueryTimeRange != "" { + model.Properties.OverrideQueryTimeRange = &resourceModel.OverrideQueryTimeRange + } else { + model.Properties.OverrideQueryTimeRange = nil + } + } + + if metadata.ResourceData.HasChange("severity") { + model.Properties.Severity = &resourceModel.Severity + } + + if metadata.ResourceData.HasChange("skip_query_validation") { + model.Properties.SkipQueryValidation = &resourceModel.SkipQueryValidation + } + + if metadata.ResourceData.HasChange("target_resource_types") { + model.Properties.TargetResourceTypes = &resourceModel.TargetResourceTypes + } + + if metadata.ResourceData.HasChange("window_duration") { + if resourceModel.WindowSize != "" { + model.Properties.WindowSize = &resourceModel.WindowSize + } else { + model.Properties.WindowSize = nil + } + } + + model.SystemData = nil + + if metadata.ResourceData.HasChange("tags") { + model.Tags = &resourceModel.Tags + } + + if _, err := client.CreateOrUpdate(ctx, *id, *model); err != nil { + return fmt.Errorf("updating %s: %+v", *id, err) + } + + return nil + }, + } +} + +func (r ScheduledQueryRulesAlertV2Resource) Read() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 5 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.Monitor.ScheduledQueryRulesV2Client + + id, err := scheduledqueryrules.ParseScheduledQueryRuleID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + resp, err := client.Get(ctx, *id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return metadata.MarkAsGone(id) + } + + return fmt.Errorf("retrieving %s: %+v", *id, err) + } + + model := resp.Model + if model == nil { + return fmt.Errorf("retrieving %s: model was nil", id) + } + + state := ScheduledQueryRulesAlertV2Model{ + Name: id.RuleName, + ResourceGroupName: id.ResourceGroupName, + Location: location.Normalize(model.Location), + } + + properties := &model.Properties + actionsValue, err := flattenScheduledQueryRulesAlertV2ActionsModel(properties.Actions) + if err != nil { + return err + } + + state.Actions = actionsValue + + if properties.AutoMitigate != nil { + state.AutoMitigate = *properties.AutoMitigate + } + + if properties.CheckWorkspaceAlertsStorageConfigured != nil { + state.CheckWorkspaceAlertsStorageConfigured = *properties.CheckWorkspaceAlertsStorageConfigured + } + + if properties.CreatedWithApiVersion != nil { + state.CreatedWithApiVersion = *properties.CreatedWithApiVersion + } + + criteriaValue, err := flattenScheduledQueryRulesAlertV2CriteriaModel(properties.Criteria) + if err != nil { + return err + } + + state.Criteria = criteriaValue + + if properties.Description != nil { + state.Description = *properties.Description + } + + if properties.DisplayName != nil { + state.DisplayName = *properties.DisplayName + } + + if properties.Enabled != nil { + state.Enabled = *properties.Enabled + } + + if properties.EvaluationFrequency != nil { + state.EvaluationFrequency = *properties.EvaluationFrequency + } + + if properties.IsLegacyLogAnalyticsRule != nil { + state.IsLegacyLogAnalyticsRule = *properties.IsLegacyLogAnalyticsRule + } + + if properties.IsWorkspaceAlertsStorageConfigured != nil { + state.IsWorkspaceAlertsStorageConfigured = *properties.IsWorkspaceAlertsStorageConfigured + } + + if properties.MuteActionsDuration != nil { + state.MuteActionsDuration = *properties.MuteActionsDuration + } + + if properties.OverrideQueryTimeRange != nil { + state.OverrideQueryTimeRange = *properties.OverrideQueryTimeRange + } + + if properties.Scopes != nil { + state.Scopes = *properties.Scopes + } + + if properties.Severity != nil { + state.Severity = *properties.Severity + } + + if properties.SkipQueryValidation != nil { + state.SkipQueryValidation = *properties.SkipQueryValidation + } + + if properties.TargetResourceTypes != nil { + state.TargetResourceTypes = *properties.TargetResourceTypes + } + + if properties.WindowSize != nil { + state.WindowSize = *properties.WindowSize + } + if model.Tags != nil { + state.Tags = *model.Tags + } + + return metadata.Encode(&state) + }, + } +} + +func (r ScheduledQueryRulesAlertV2Resource) Delete() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.Monitor.ScheduledQueryRulesV2Client + + id, err := scheduledqueryrules.ParseScheduledQueryRuleID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + if _, err := client.Delete(ctx, *id); err != nil { + return fmt.Errorf("deleting %s: %+v", id, err) + } + + return nil + }, + } +} + +func expandScheduledQueryRulesAlertV2ActionsModel(inputList []ScheduledQueryRulesAlertV2ActionsModel) (*scheduledqueryrules.Actions, error) { + if len(inputList) == 0 { + return nil, nil + } + + input := &inputList[0] + output := scheduledqueryrules.Actions{ + ActionGroups: &input.ActionGroups, + CustomProperties: &input.CustomProperties, + } + + return &output, nil +} + +func expandScheduledQueryRulesAlertV2CriteriaModel(inputList []ScheduledQueryRulesAlertV2CriteriaModel) (*scheduledqueryrules.ScheduledQueryRuleCriteria, error) { + output := scheduledqueryrules.ScheduledQueryRuleCriteria{} + var outputList []scheduledqueryrules.Condition + for _, v := range inputList { + input := v + condition := scheduledqueryrules.Condition{ + Operator: &input.Operator, + Threshold: &input.Threshold, + TimeAggregation: &input.TimeAggregation, + } + + dimensionsValue, err := expandScheduledQueryRulesAlertV2DimensionModel(input.Dimensions) + if err != nil { + return nil, err + } + + condition.Dimensions = dimensionsValue + + failingPeriodsValue, err := expandScheduledQueryRulesAlertV2FailingPeriodsModel(input.FailingPeriods) + if err != nil { + return nil, err + } + + condition.FailingPeriods = failingPeriodsValue + + if input.MetricMeasureColumn != "" { + condition.MetricMeasureColumn = &input.MetricMeasureColumn + } + + if input.Query != "" { + condition.Query = &input.Query + } + + if input.ResourceIdColumn != "" { + condition.ResourceIdColumn = &input.ResourceIdColumn + } + + outputList = append(outputList, condition) + } + output.AllOf = &outputList + return &output, nil +} + +func expandScheduledQueryRulesAlertV2DimensionModel(inputList []ScheduledQueryRulesAlertV2DimensionModel) (*[]scheduledqueryrules.Dimension, error) { + var outputList []scheduledqueryrules.Dimension + for _, v := range inputList { + input := v + output := scheduledqueryrules.Dimension{ + Name: input.Name, + Operator: input.Operator, + Values: input.Values, + } + + outputList = append(outputList, output) + } + + return &outputList, nil +} + +func expandScheduledQueryRulesAlertV2FailingPeriodsModel(inputList []ScheduledQueryRulesAlertV2FailingPeriodsModel) (*scheduledqueryrules.ConditionFailingPeriods, error) { + if len(inputList) == 0 { + return nil, nil + } + + input := &inputList[0] + output := scheduledqueryrules.ConditionFailingPeriods{ + MinFailingPeriodsToAlert: &input.MinFailingPeriodsToAlert, + NumberOfEvaluationPeriods: &input.NumberOfEvaluationPeriods, + } + + return &output, nil +} + +func flattenScheduledQueryRulesAlertV2ActionsModel(input *scheduledqueryrules.Actions) ([]ScheduledQueryRulesAlertV2ActionsModel, error) { + var outputList []ScheduledQueryRulesAlertV2ActionsModel + if input == nil { + return outputList, nil + } + + output := ScheduledQueryRulesAlertV2ActionsModel{} + + if input.ActionGroups != nil { + output.ActionGroups = *input.ActionGroups + } + + if input.CustomProperties != nil { + output.CustomProperties = *input.CustomProperties + } + + return append(outputList, output), nil +} + +func flattenScheduledQueryRulesAlertV2CriteriaModel(input *scheduledqueryrules.ScheduledQueryRuleCriteria) ([]ScheduledQueryRulesAlertV2CriteriaModel, error) { + var outputList []ScheduledQueryRulesAlertV2CriteriaModel + if input == nil { + return outputList, nil + } + + inputList := input.AllOf + if inputList == nil { + return outputList, nil + } + + for _, v := range *inputList { + output := ScheduledQueryRulesAlertV2CriteriaModel{} + + dimensionsValue, err := flattenScheduledQueryRulesAlertV2DimensionModel(v.Dimensions) + if err != nil { + return nil, err + } + + output.Dimensions = dimensionsValue + + failingPeriodsValue, err := flattenScheduledQueryRulesAlertV2FailingPeriodsModel(v.FailingPeriods) + if err != nil { + return nil, err + } + + output.FailingPeriods = failingPeriodsValue + + if v.MetricMeasureColumn != nil { + output.MetricMeasureColumn = *v.MetricMeasureColumn + } + + if v.Operator != nil { + output.Operator = *v.Operator + } + + if v.Query != nil { + output.Query = *v.Query + } + + if v.ResourceIdColumn != nil { + output.ResourceIdColumn = *v.ResourceIdColumn + } + + if v.Threshold != nil { + output.Threshold = *v.Threshold + } + + if v.TimeAggregation != nil { + output.TimeAggregation = *v.TimeAggregation + } + + outputList = append(outputList, output) + } + + return outputList, nil +} + +func flattenScheduledQueryRulesAlertV2DimensionModel(inputList *[]scheduledqueryrules.Dimension) ([]ScheduledQueryRulesAlertV2DimensionModel, error) { + var outputList []ScheduledQueryRulesAlertV2DimensionModel + if inputList == nil { + return outputList, nil + } + + for _, input := range *inputList { + output := ScheduledQueryRulesAlertV2DimensionModel{ + Name: input.Name, + Operator: input.Operator, + Values: input.Values, + } + + outputList = append(outputList, output) + } + + return outputList, nil +} + +func flattenScheduledQueryRulesAlertV2FailingPeriodsModel(input *scheduledqueryrules.ConditionFailingPeriods) ([]ScheduledQueryRulesAlertV2FailingPeriodsModel, error) { + var outputList []ScheduledQueryRulesAlertV2FailingPeriodsModel + if input == nil { + return outputList, nil + } + + output := ScheduledQueryRulesAlertV2FailingPeriodsModel{} + + if input.MinFailingPeriodsToAlert != nil { + output.MinFailingPeriodsToAlert = *input.MinFailingPeriodsToAlert + } + + if input.NumberOfEvaluationPeriods != nil { + output.NumberOfEvaluationPeriods = *input.NumberOfEvaluationPeriods + } + + return append(outputList, output), nil +} diff --git a/internal/services/monitor/monitor_scheduled_query_rules_alert_v2_resource_test.go b/internal/services/monitor/monitor_scheduled_query_rules_alert_v2_resource_test.go new file mode 100644 index 000000000000..4d120a67d6c7 --- /dev/null +++ b/internal/services/monitor/monitor_scheduled_query_rules_alert_v2_resource_test.go @@ -0,0 +1,296 @@ +package monitor_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/insights/2021-08-01/scheduledqueryrules" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type MonitorScheduledQueryRulesAlertV2Resource struct{} + +func TestAccMonitorScheduledQueryRulesAlertV2_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_monitor_scheduled_query_rules_alert_v2", "test") + r := MonitorScheduledQueryRulesAlertV2Resource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccMonitorScheduledQueryRulesAlertV2_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_monitor_scheduled_query_rules_alert_v2", "test") + r := MonitorScheduledQueryRulesAlertV2Resource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func TestAccMonitorScheduledQueryRulesAlertV2_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_monitor_scheduled_query_rules_alert_v2", "test") + r := MonitorScheduledQueryRulesAlertV2Resource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccMonitorScheduledQueryRulesAlertV2_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_monitor_scheduled_query_rules_alert_v2", "test") + r := MonitorScheduledQueryRulesAlertV2Resource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.update(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func (r MonitorScheduledQueryRulesAlertV2Resource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + id, err := scheduledqueryrules.ParseScheduledQueryRuleID(state.ID) + if err != nil { + return nil, err + } + + client := clients.Monitor.ScheduledQueryRulesV2Client + resp, err := client.Get(ctx, *id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return utils.Bool(false), nil + } + return nil, fmt.Errorf("retrieving %s: %+v", id, err) + } + return utils.Bool(resp.Model != nil), nil +} + +func (r MonitorScheduledQueryRulesAlertV2Resource) template(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctest-rg-%d" + location = "%s" +} + +resource "azurerm_application_insights" "test" { + name = "acctest-ai-%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + application_type = "web" +} + +resource "azurerm_monitor_action_group" "test" { + name = "acctest-mag-%[1]d" + resource_group_name = azurerm_resource_group.test.name + short_name = "test mag" +} +`, data.RandomInteger, data.Locations.Primary) +} + +func (r MonitorScheduledQueryRulesAlertV2Resource) basic(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_monitor_scheduled_query_rules_alert_v2" "test" { + name = "acctest-isqr-%d" + resource_group_name = azurerm_resource_group.test.name + location = "%s" + evaluation_frequency = "PT5M" + window_duration = "PT5M" + scopes = [azurerm_application_insights.test.id] + severity = 3 + criteria { + query = <<-QUERY + requests + | summarize CountByCountry=count() by client_CountryOrRegion + QUERY + time_aggregation_method = "Count" + threshold = 5.0 + operator = "GreaterThan" + } +} +`, template, data.RandomInteger, data.Locations.Primary) +} + +func (r MonitorScheduledQueryRulesAlertV2Resource) requiresImport(data acceptance.TestData) string { + config := r.basic(data) + return fmt.Sprintf(` +%s + +resource "azurerm_monitor_scheduled_query_rules_alert_v2" "import" { + name = azurerm_monitor_scheduled_query_rules_alert_v2.test.name + resource_group_name = azurerm_resource_group.test.name + location = "%s" + evaluation_frequency = azurerm_monitor_scheduled_query_rules_alert_v2.test.evaluation_frequency + window_duration = azurerm_monitor_scheduled_query_rules_alert_v2.test.window_duration + scopes = azurerm_monitor_scheduled_query_rules_alert_v2.test.scopes + severity = azurerm_monitor_scheduled_query_rules_alert_v2.test.severity + criteria { + query = azurerm_monitor_scheduled_query_rules_alert_v2.test.criteria.0.query + time_aggregation_method = azurerm_monitor_scheduled_query_rules_alert_v2.test.criteria.0.time_aggregation_method + threshold = azurerm_monitor_scheduled_query_rules_alert_v2.test.criteria.0.threshold + operator = azurerm_monitor_scheduled_query_rules_alert_v2.test.criteria.0.operator + } +} +`, config, data.Locations.Primary) +} + +func (r MonitorScheduledQueryRulesAlertV2Resource) complete(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_monitor_scheduled_query_rules_alert_v2" "test" { + name = "acctest-isqr-%d" + resource_group_name = azurerm_resource_group.test.name + location = "%s" + + evaluation_frequency = "PT5M" + window_duration = "PT5M" + scopes = [azurerm_application_insights.test.id] + severity = 3 + criteria { + query = <<-QUERY + requests + | summarize CountByCountry=count() by client_CountryOrRegion + QUERY + time_aggregation_method = "Count" + threshold = 5.0 + operator = "GreaterThan" + + resource_id_column = "client_CountryOrRegion" + dimension { + name = "client_CountryOrRegion" + operator = "Include" + values = ["*"] + } + failing_periods { + minimum_failing_periods_to_trigger_alert = 1 + number_of_evaluation_periods = 1 + } + } + + auto_mitigation_enabled = false + workspace_alerts_storage_enabled = false + description = "test sqr" + display_name = "acctest-sqr" + enabled = false + mute_actions_after_alert_duration = "PT10M" + query_time_range_override = "PT10M" + skip_query_validation = false + target_resource_types = ["microsoft.insights/components"] + action { + action_groups = [azurerm_monitor_action_group.test.id] + custom_properties = { + key = "value" + } + } + + tags = { + key = "value" + } +} +`, template, data.RandomInteger, data.Locations.Primary) +} + +func (r MonitorScheduledQueryRulesAlertV2Resource) update(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_monitor_scheduled_query_rules_alert_v2" "test" { + name = "acctest-isqr-%d" + resource_group_name = azurerm_resource_group.test.name + location = "%s" + + evaluation_frequency = "PT10M" + window_duration = "PT10M" + scopes = [azurerm_application_insights.test.id] + severity = 4 + criteria { + query = <<-QUERY + requests + | summarize CountByCountry=count() by client_CountryOrRegion + QUERY + time_aggregation_method = "Maximum" + threshold = 17.5 + operator = "LessThan" + + resource_id_column = "client_CountryOrRegion" + metric_measure_column = "CountByCountry" + dimension { + name = "client_CountryOrRegion" + operator = "Exclude" + values = ["123"] + } + failing_periods { + minimum_failing_periods_to_trigger_alert = 1 + number_of_evaluation_periods = 1 + } + } + + auto_mitigation_enabled = true + workspace_alerts_storage_enabled = false + description = "test sqr" + display_name = "acctest-sqr" + enabled = true + query_time_range_override = "PT1H" + skip_query_validation = true + action { + action_groups = [azurerm_monitor_action_group.test.id] + custom_properties = { + key = "value" + key2 = "value2" + } + } + + tags = { + key = "value" + key2 = "value2" + } +} +`, template, data.RandomInteger, data.Locations.Primary) +} diff --git a/internal/services/monitor/registration.go b/internal/services/monitor/registration.go index f908adc25252..bae5889b4feb 100644 --- a/internal/services/monitor/registration.go +++ b/internal/services/monitor/registration.go @@ -7,12 +7,29 @@ import ( type Registration struct{} -var _ sdk.UntypedServiceRegistrationWithAGitHubLabel = Registration{} +var ( + _ sdk.TypedServiceRegistration = Registration{} + _ sdk.UntypedServiceRegistrationWithAGitHubLabel = Registration{} +) func (r Registration) AssociatedGitHubLabel() string { return "service/monitor" } +func (r Registration) DataSources() []sdk.DataSource { + return []sdk.DataSource{ + DataCollectionEndpointDataSource{}, + } +} + +func (r Registration) Resources() []sdk.Resource { + return []sdk.Resource{ + DataCollectionEndpointResource{}, + DataCollectionRuleResource{}, + ScheduledQueryRulesAlertV2Resource{}, + } +} + // Name is the name of this Service func (r Registration) Name() string { return "Monitor" diff --git a/internal/services/msi/client/client.go b/internal/services/msi/client/client.go index 587e7303a216..83207868b8b5 100644 --- a/internal/services/msi/client/client.go +++ b/internal/services/msi/client/client.go @@ -1,16 +1,16 @@ package client import ( - "github.com/hashicorp/go-azure-sdk/resource-manager/managedidentity/2018-11-30/managedidentity" + "github.com/hashicorp/go-azure-sdk/resource-manager/managedidentity/2018-11-30/managedidentities" "github.com/hashicorp/terraform-provider-azurerm/internal/common" ) type Client struct { - UserAssignedIdentitiesClient *managedidentity.ManagedIdentityClient + UserAssignedIdentitiesClient *managedidentities.ManagedIdentitiesClient } func NewClient(o *common.ClientOptions) *Client { - userAssignedIdentitiesClient := managedidentity.NewManagedIdentityClientWithBaseURI(o.ResourceManagerEndpoint) + userAssignedIdentitiesClient := managedidentities.NewManagedIdentitiesClientWithBaseURI(o.ResourceManagerEndpoint) o.ConfigureClient(&userAssignedIdentitiesClient.Client, o.ResourceManagerAuthorizer) return &Client{ diff --git a/internal/services/msi/user_assigned_identity_resource.go b/internal/services/msi/user_assigned_identity_resource.go index 33dd68ee36c0..1b05a86330a2 100644 --- a/internal/services/msi/user_assigned_identity_resource.go +++ b/internal/services/msi/user_assigned_identity_resource.go @@ -10,7 +10,7 @@ import ( "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" - "github.com/hashicorp/go-azure-sdk/resource-manager/managedidentity/2018-11-30/managedidentity" + "github.com/hashicorp/go-azure-sdk/resource-manager/managedidentity/2018-11-30/managedidentities" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/services/msi/migration" @@ -99,7 +99,7 @@ func resourceArmUserAssignedIdentityCreateUpdate(d *pluginsdk.ResourceData, meta } } - identity := managedidentity.Identity{ + identity := managedidentities.Identity{ Name: utils.String(resourceId.ResourceName), Location: location.Normalize(d.Get("location").(string)), Tags: tags.Expand(t), diff --git a/internal/services/mssql/mssql_elasticpool_resource.go b/internal/services/mssql/mssql_elasticpool_resource.go index c1bf7087513a..9d0e298890f2 100644 --- a/internal/services/mssql/mssql_elasticpool_resource.go +++ b/internal/services/mssql/mssql_elasticpool_resource.go @@ -8,6 +8,7 @@ import ( "time" "github.com/Azure/azure-sdk-for-go/services/preview/sql/mgmt/v5.0/sql" + "github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/publicmaintenanceconfigurations" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" @@ -114,6 +115,20 @@ func resourceMsSqlElasticPool() *pluginsdk.Resource { }, }, + "maintenance_configuration_name": { + Type: pluginsdk.TypeString, + Optional: true, + Default: "SQL_Default", + ValidateFunc: validation.StringInSlice([]string{"SQL_Default", "SQL_EastUS_DB_1", "SQL_EastUS2_DB_1", "SQL_SoutheastAsia_DB_1", "SQL_AustraliaEast_DB_1", "SQL_NorthEurope_DB_1", "SQL_SouthCentralUS_DB_1", + "SQL_WestUS2_DB_1", "SQL_UKSouth_DB_1", "SQL_WestEurope_DB_1", "SQL_EastUS_DB_2", "SQL_EastUS2_DB_2", "SQL_WestUS2_DB_2", "SQL_SoutheastAsia_DB_2", "SQL_AustraliaEast_DB_2", "SQL_NorthEurope_DB_2", + "SQL_SouthCentralUS_DB_2", "SQL_UKSouth_DB_2", "SQL_WestEurope_DB_2", "SQL_AustraliaSoutheast_DB_1", "SQL_BrazilSouth_DB_1", "SQL_CanadaCentral_DB_1", "SQL_CanadaEast_DB_1", "SQL_CentralUS_DB_1", + "SQL_EastAsia_DB_1", "SQL_FranceCentral_DB_1", "SQL_GermanyWestCentral_DB_1", "SQL_CentralIndia_DB_1", "SQL_SouthIndia_DB_1", "SQL_JapanEast_DB_1", "SQL_JapanWest_DB_1", "SQL_NorthCentralUS_DB_1", + "SQL_UKWest_DB_1", "SQL_WestUS_DB_1", "SQL_AustraliaSoutheast_DB_2", "SQL_BrazilSouth_DB_2", "SQL_CanadaCentral_DB_2", "SQL_CanadaEast_DB_2", "SQL_CentralUS_DB_2", "SQL_EastAsia_DB_2", + "SQL_FranceCentral_DB_2", "SQL_GermanyWestCentral_DB_2", "SQL_CentralIndia_DB_2", "SQL_SouthIndia_DB_2", "SQL_JapanEast_DB_2", "SQL_JapanWest_DB_2", "SQL_NorthCentralUS_DB_2", "SQL_UKWest_DB_2", + "SQL_WestUS_DB_2", "SQL_WestCentralUS_DB_1", "SQL_FranceSouth_DB_1", "SQL_WestCentralUS_DB_2", "SQL_FranceSouth_DB_2", "SQL_SwitzerlandNorth_DB_1", "SQL_SwitzerlandNorth_DB_2", "SQL_BrazilSoutheast_DB_1", + "SQL_UAENorth_DB_1", "SQL_BrazilSoutheast_DB_2", "SQL_UAENorth_DB_2"}, false), + }, + "per_database_settings": { Type: pluginsdk.TypeList, Required: true, @@ -206,15 +221,17 @@ func resourceMsSqlElasticPoolCreateUpdate(d *pluginsdk.ResourceData, meta interf sku := expandMsSqlElasticPoolSku(d) t := d.Get("tags").(map[string]interface{}) + maintenanceConfigId := publicmaintenanceconfigurations.NewPublicMaintenanceConfigurationID(subscriptionId, d.Get("maintenance_configuration_name").(string)) elasticPool := sql.ElasticPool{ Name: &id.Name, Location: &location, Sku: sku, Tags: tags.Expand(t), ElasticPoolProperties: &sql.ElasticPoolProperties{ - LicenseType: sql.ElasticPoolLicenseType(d.Get("license_type").(string)), - PerDatabaseSettings: expandMsSqlElasticPoolPerDatabaseSettings(d), - ZoneRedundant: utils.Bool(d.Get("zone_redundant").(bool)), + LicenseType: sql.ElasticPoolLicenseType(d.Get("license_type").(string)), + PerDatabaseSettings: expandMsSqlElasticPoolPerDatabaseSettings(d), + ZoneRedundant: utils.Bool(d.Get("zone_redundant").(bool)), + MaintenanceConfigurationID: utils.String(maintenanceConfigId.ID()), }, } @@ -288,6 +305,12 @@ func resourceMsSqlElasticPoolRead(d *pluginsdk.ResourceData, meta interface{}) e if err := d.Set("per_database_settings", flattenMsSqlElasticPoolPerDatabaseSettings(properties.PerDatabaseSettings)); err != nil { return fmt.Errorf("setting `per_database_settings`: %+v", err) } + + maintenanceConfigId, err := publicmaintenanceconfigurations.ParsePublicMaintenanceConfigurationID(*properties.MaintenanceConfigurationID) + if err != nil { + return err + } + d.Set("maintenance_configuration_name", maintenanceConfigId.ResourceName) } return tags.FlattenAndSet(d, resp.Tags) diff --git a/internal/services/mssql/mssql_elasticpool_resource_test.go b/internal/services/mssql/mssql_elasticpool_resource_test.go index 510d768e76d1..bd2fe7069088 100644 --- a/internal/services/mssql/mssql_elasticpool_resource_test.go +++ b/internal/services/mssql/mssql_elasticpool_resource_test.go @@ -342,6 +342,8 @@ resource "azurerm_mssql_elasticpool" "test" { max_size_gb = %.7[6]f zone_redundant = %[9]t + maintenance_configuration_name = "%[4]s" != "Basic" && azurerm_resource_group.test.location == "westeurope" ? "SQL_WestEurope_DB_2" : "SQL_Default" + sku { name = "%[3]s" tier = "%[4]s" diff --git a/internal/services/mssql/mssql_managed_instance_resource.go b/internal/services/mssql/mssql_managed_instance_resource.go index 5f8f1d96c0d2..b818c23bb825 100644 --- a/internal/services/mssql/mssql_managed_instance_resource.go +++ b/internal/services/mssql/mssql_managed_instance_resource.go @@ -11,10 +11,10 @@ import ( "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/identity" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2021-05-01/publicmaintenanceconfigurations" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" - maintenanceParse "github.com/hashicorp/terraform-provider-azurerm/internal/services/maintenance/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/mssql/validate" networkValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/services/sql/parse" @@ -120,7 +120,7 @@ func (r MsSqlManagedInstanceResource) Arguments() map[string]*pluginsdk.Schema { "storage_size_in_gb": { Type: schema.TypeInt, Required: true, - ValidateFunc: validation.IntBetween(32, 8192), + ValidateFunc: validation.IntBetween(32, 16384), }, "subnet_id": { @@ -293,7 +293,7 @@ func (r MsSqlManagedInstanceResource) Create() sdk.ResourceFunc { return fmt.Errorf("expanding `sku_name` for SQL Managed Instance Server %q: %v", id.ID(), err) } - maintenanceConfigId := maintenanceParse.NewPublicMaintenanceConfigurationID(subscriptionId, model.MaintenanceConfigurationName) + maintenanceConfigId := publicmaintenanceconfigurations.NewPublicMaintenanceConfigurationID(subscriptionId, model.MaintenanceConfigurationName) parameters := sql.ManagedInstance{ Sku: sku, @@ -380,7 +380,7 @@ func (r MsSqlManagedInstanceResource) Update() sdk.ResourceFunc { } if metadata.ResourceData.HasChange("maintenance_configuration_name") { - maintenanceConfigId := maintenanceParse.NewPublicMaintenanceConfigurationID(id.SubscriptionId, state.MaintenanceConfigurationName) + maintenanceConfigId := publicmaintenanceconfigurations.NewPublicMaintenanceConfigurationID(id.SubscriptionId, state.MaintenanceConfigurationName) properties.MaintenanceConfigurationID = utils.String(maintenanceConfigId.ID()) } @@ -461,11 +461,11 @@ func (r MsSqlManagedInstanceResource) Read() sdk.ResourceFunc { model.Fqdn = *props.FullyQualifiedDomainName } if props.MaintenanceConfigurationID != nil { - maintenanceConfigId, err := maintenanceParse.PublicMaintenanceConfigurationID(*props.MaintenanceConfigurationID) + maintenanceConfigId, err := publicmaintenanceconfigurations.ParsePublicMaintenanceConfigurationID(*props.MaintenanceConfigurationID) if err != nil { return err } - model.MaintenanceConfigurationName = maintenanceConfigId.Name + model.MaintenanceConfigurationName = maintenanceConfigId.ResourceName } if props.MinimalTLSVersion != nil { model.MinimumTlsVersion = *props.MinimalTLSVersion diff --git a/internal/services/mssql/mssql_server_dns_alias_resource.go b/internal/services/mssql/mssql_server_dns_alias_resource.go index 62a3f8a20f15..d8b9dbd4d4e6 100644 --- a/internal/services/mssql/mssql_server_dns_alias_resource.go +++ b/internal/services/mssql/mssql_server_dns_alias_resource.go @@ -131,9 +131,14 @@ func (m ServerDNSAliasResource) Delete() sdk.ResourceFunc { } metadata.Logger.Infof("deleting %s", id) client := metadata.Client.MSSQL.ServerDNSAliasClient - if _, err = client.Delete(ctx, id.ResourceGroup, id.ServerName, id.DnsAliaseName); err != nil { + future, err := client.Delete(ctx, id.ResourceGroup, id.ServerName, id.DnsAliaseName) + if err != nil { return fmt.Errorf("deleting %s: %v", id, err) } + if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for deletion of %q: %+v", id, err) + } + return nil }, } diff --git a/internal/services/mssql/mssql_server_resource.go b/internal/services/mssql/mssql_server_resource.go index 088b50a53e9e..de679242eae2 100644 --- a/internal/services/mssql/mssql_server_resource.go +++ b/internal/services/mssql/mssql_server_resource.go @@ -149,6 +149,7 @@ func resourceMsSqlServer() *pluginsdk.Resource { "1.0", "1.1", "1.2", + "Disabled", }, false), }, @@ -256,7 +257,7 @@ func resourceMsSqlServerCreate(d *pluginsdk.ResourceData, meta interface{}) erro props.ServerProperties.RestrictOutboundNetworkAccess = sql.ServerNetworkAccessFlagEnabled } - if v := d.Get("minimum_tls_version"); v.(string) != "" { + if v := d.Get("minimum_tls_version"); v.(string) != "Disabled" { props.ServerProperties.MinimalTLSVersion = utils.String(v.(string)) } @@ -346,7 +347,7 @@ func resourceMsSqlServerUpdate(d *pluginsdk.ResourceData, meta interface{}) erro props.ServerProperties.AdministratorLoginPassword = utils.String(adminPassword) } - if v := d.Get("minimum_tls_version"); v.(string) != "" { + if v := d.Get("minimum_tls_version"); v.(string) != "Disabled" { props.ServerProperties.MinimalTLSVersion = utils.String(v.(string)) } @@ -466,7 +467,11 @@ func resourceMsSqlServerRead(d *pluginsdk.ResourceData, meta interface{}) error d.Set("version", props.Version) d.Set("administrator_login", props.AdministratorLogin) d.Set("fully_qualified_domain_name", props.FullyQualifiedDomainName) - d.Set("minimum_tls_version", props.MinimalTLSVersion) + if v := props.MinimalTLSVersion; v == nil { + d.Set("minimum_tls_version", "Disabled") + } else { + d.Set("minimum_tls_version", props.MinimalTLSVersion) + } d.Set("public_network_access_enabled", props.PublicNetworkAccess == sql.ServerNetworkAccessFlagEnabled) d.Set("outbound_network_restriction_enabled", props.RestrictOutboundNetworkAccess == sql.ServerNetworkAccessFlagEnabled) primaryUserAssignedIdentityID := "" @@ -681,7 +686,7 @@ func flattenSqlServerRestorableDatabases(resp sql.RestorableDroppedDatabaseListR func msSqlMinimumTLSVersionDiff(ctx context.Context, d *pluginsdk.ResourceDiff, _ interface{}) (err error) { old, new := d.GetChange("minimum_tls_version") - if old != "" && new == "" { + if old != "" && old != "Disabled" && new == "Disabled" { err = fmt.Errorf("`minimum_tls_version` cannot be removed once set, please set a valid value for this property") } return diff --git a/internal/services/mssql/mssql_server_resource_test.go b/internal/services/mssql/mssql_server_resource_test.go index 6a4de734a52c..e998e03b7f38 100644 --- a/internal/services/mssql/mssql_server_resource_test.go +++ b/internal/services/mssql/mssql_server_resource_test.go @@ -45,6 +45,21 @@ func TestAccMsSqlServer_complete(t *testing.T) { }) } +func TestAccMsSqlServer_minimumTLSVersionDisabled(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_mssql_server", "test") + r := MsSqlServerResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basicWithMinimumTLSVersionDisabled(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("administrator_login_password"), + }) +} + func TestAccMsSqlServer_requiresImport(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_mssql_server", "test") r := MsSqlServerResource{} @@ -255,6 +270,33 @@ resource "azurerm_mssql_server" "test" { `, data.RandomInteger, data.Locations.Primary) } +func (MsSqlServerResource) basicWithMinimumTLSVersionDisabled(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-mssql-%[1]d" + location = "%[2]s" +} + +resource "azurerm_mssql_server" "test" { + name = "acctestsqlserver%[1]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + version = "12.0" + administrator_login = "missadministrator" + administrator_login_password = "thisIsKat11" + minimum_tls_version = "Disabled" + + identity { + type = "SystemAssigned" + } +} +`, data.RandomInteger, data.Locations.Primary) +} + func (MsSqlServerResource) basicWithMinimumTLSVersion(data acceptance.TestData) string { return fmt.Sprintf(` provider "azurerm" { diff --git a/internal/services/mssql/mssql_virtual_machine_resource.go b/internal/services/mssql/mssql_virtual_machine_resource.go index a87ba5565bcb..19c25b180b14 100644 --- a/internal/services/mssql/mssql_virtual_machine_resource.go +++ b/internal/services/mssql/mssql_virtual_machine_resource.go @@ -409,6 +409,29 @@ func resourceMsSqlVirtualMachineCreateUpdate(d *pluginsdk.ResourceData, meta int } } + // Wait for the auto patching settings to take effect + // See: https://github.com/Azure/azure-rest-api-specs/issues/12818 + if autoPatching := d.Get("auto_patching"); (d.IsNewResource() && len(autoPatching.([]interface{})) > 0) || (!d.IsNewResource() && d.HasChange("auto_patching")) { + log.Printf("[DEBUG] Waiting for SQL Virtual Machine %q AutoPatchingSettings to take effect", d.Id()) + stateConf := &pluginsdk.StateChangeConf{ + Pending: []string{"Retry", "Pending"}, + Target: []string{"Updated"}, + Refresh: resourceMsSqlVirtualMachineAutoPatchingSettingsRefreshFunc(ctx, client, d), + MinTimeout: 1 * time.Minute, + ContinuousTargetOccurence: 2, + } + + if d.IsNewResource() { + stateConf.Timeout = d.Timeout(pluginsdk.TimeoutCreate) + } else { + stateConf.Timeout = d.Timeout(pluginsdk.TimeoutUpdate) + } + + if _, err := stateConf.WaitForStateContext(ctx); err != nil { + return fmt.Errorf("waiting for SQL Virtual Machine %q AutoPatchingSettings to take effect: %+v", d.Id(), err) + } + } + return resourceMsSqlVirtualMachineRead(d, meta) } @@ -688,6 +711,48 @@ func flattenSqlVirtualMachineAutoBackup(autoBackup *sqlvirtualmachines.AutoBacku } } +func resourceMsSqlVirtualMachineAutoPatchingSettingsRefreshFunc(ctx context.Context, client *sqlvirtualmachines.SqlVirtualMachinesClient, d *pluginsdk.ResourceData) pluginsdk.StateRefreshFunc { + return func() (interface{}, string, error) { + id, err := sqlvirtualmachines.ParseSqlVirtualMachineID(d.Id()) + if err != nil { + return nil, "Error", err + } + + resp, err := client.Get(ctx, *id, sqlvirtualmachines.GetOperationOptions{Expand: utils.String("*")}) + if err != nil { + return nil, "Retry", err + } + + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + autoPatchingSettings := flattenSqlVirtualMachineAutoPatching(props.AutoPatchingSettings) + + if len(autoPatchingSettings) == 0 { + if v, ok := d.GetOk("auto_patching"); !ok || len(v.([]interface{})) == 0 { + return resp, "Updated", nil + } + return resp, "Pending", nil + } + + if v, ok := d.GetOk("auto_patching"); !ok || len(v.([]interface{})) == 0 { + return resp, "Pending", nil + } + + for prop, val := range autoPatchingSettings[0].(map[string]interface{}) { + v := d.Get(fmt.Sprintf("auto_patching.0.%s", prop)) + if v != val { + return resp, "Pending", nil + } + } + + return resp, "Updated", nil + } + } + + return resp, "Retry", nil + } +} + func expandSqlVirtualMachineAutoPatchingSettings(input []interface{}) *sqlvirtualmachines.AutoPatchingSettings { if len(input) == 0 { return nil @@ -709,14 +774,14 @@ func flattenSqlVirtualMachineAutoPatching(autoPatching *sqlvirtualmachines.AutoP return []interface{}{} } - var startHour int64 + var startHour int if autoPatching.MaintenanceWindowStartingHour != nil { - startHour = *autoPatching.MaintenanceWindowStartingHour + startHour = int(*autoPatching.MaintenanceWindowStartingHour) } - var duration int64 + var duration int if autoPatching.MaintenanceWindowDuration != nil { - duration = *autoPatching.MaintenanceWindowDuration + duration = int(*autoPatching.MaintenanceWindowDuration) } var dayOfWeek string diff --git a/internal/services/netapp/netapp_snapshot_resource.go b/internal/services/netapp/netapp_snapshot_resource.go index 8ae77671d270..1e0e016b620f 100644 --- a/internal/services/netapp/netapp_snapshot_resource.go +++ b/internal/services/netapp/netapp_snapshot_resource.go @@ -146,7 +146,7 @@ func resourceNetAppSnapshotDelete(d *pluginsdk.ResourceData, meta interface{}) e return err } - if _, err = client.Delete(ctx, *id); err != nil { + if err = client.DeleteThenPoll(ctx, *id); err != nil { return fmt.Errorf("deleting %s: %+v", id, err) } diff --git a/internal/services/netapp/netapp_volume_resource.go b/internal/services/netapp/netapp_volume_resource.go index 1dbe6bec3111..9bba80e9535c 100644 --- a/internal/services/netapp/netapp_volume_resource.go +++ b/internal/services/netapp/netapp_volume_resource.go @@ -1084,8 +1084,8 @@ func flattenNetAppVolumeMountIPAddresses(input *[]volumes.MountTargetProperties) } for _, item := range *input { - if item.IpAddress != nil { - results = append(results, item.IpAddress) + if item.IPAddress != nil { + results = append(results, item.IPAddress) } } diff --git a/internal/services/network/application_gateway_resource.go b/internal/services/network/application_gateway_resource.go index 47ab875139f9..4ddbe76d7648 100644 --- a/internal/services/network/application_gateway_resource.go +++ b/internal/services/network/application_gateway_resource.go @@ -325,6 +325,7 @@ func resourceApplicationGateway() *pluginsdk.Resource { "private_ip_address": { Type: pluginsdk.TypeString, Optional: true, + Computed: true, }, "public_ip_address_id": { @@ -409,6 +410,24 @@ func resourceApplicationGateway() *pluginsdk.Resource { }, }, + "global": { + Type: pluginsdk.TypeList, + MaxItems: 1, + Optional: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "request_buffering_enabled": { + Type: pluginsdk.TypeBool, + Required: true, + }, + "response_buffering_enabled": { + Type: pluginsdk.TypeBool, + Required: true, + }, + }, + }, + }, + //lintignore:S016,S023 "http_listener": { Type: pluginsdk.TypeSet, @@ -966,7 +985,7 @@ func resourceApplicationGateway() *pluginsdk.Resource { Schema: map[string]*pluginsdk.Schema{ "body": { Type: pluginsdk.TypeString, - Required: true, + Optional: true, }, "status_code": { @@ -1092,6 +1111,17 @@ func resourceApplicationGateway() *pluginsdk.Resource { Type: pluginsdk.TypeString, Optional: true, }, + + "components": { + Type: pluginsdk.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice([]string{ + "path_only", + "query_string_only", + }, false), + }, + "reroute": { Type: pluginsdk.TypeBool, Optional: true, @@ -1561,6 +1591,11 @@ func resourceApplicationGatewayCreate(d *pluginsdk.ResourceData, meta interface{ gatewayIPConfigurations, stopApplicationGateway := expandApplicationGatewayIPConfigurations(d) + globalConfiguration, err := expandApplicationGatewayGlobalConfiguration(d.Get("global").([]interface{})) + if err != nil { + return fmt.Errorf("expanding `global`: %+v", err) + } + httpListeners, err := expandApplicationGatewayHTTPListeners(d, id.ID()) if err != nil { return fmt.Errorf("fail to expand `http_listener`: %+v", err) @@ -1585,6 +1620,7 @@ func resourceApplicationGatewayCreate(d *pluginsdk.ResourceData, meta interface{ FrontendIPConfigurations: expandApplicationGatewayFrontendIPConfigurations(d, id.ID()), FrontendPorts: expandApplicationGatewayFrontendPorts(d), GatewayIPConfigurations: gatewayIPConfigurations, + GlobalConfiguration: globalConfiguration, HTTPListeners: httpListeners, PrivateLinkConfigurations: expandApplicationGatewayPrivateLinkConfigurations(d), Probes: expandApplicationGatewayProbes(d), @@ -1793,6 +1829,15 @@ func resourceApplicationGatewayUpdate(d *pluginsdk.ResourceData, meta interface{ applicationGateway.ApplicationGatewayPropertiesFormat.GatewayIPConfigurations = gatewayIPConfigurations } + if d.HasChange("global") { + globalConfiguration, err := expandApplicationGatewayGlobalConfiguration(d.Get("global").([]interface{})) + if err != nil { + return fmt.Errorf("expanding `global`: %+v", err) + } + + applicationGateway.ApplicationGatewayPropertiesFormat.GlobalConfiguration = globalConfiguration + } + if d.HasChange("http_listener") { httpListeners, err := expandApplicationGatewayHTTPListeners(d, id.ID()) if err != nil { @@ -2052,6 +2097,10 @@ func resourceApplicationGatewayRead(d *pluginsdk.ResourceData, meta interface{}) return fmt.Errorf("setting `gateway_ip_configuration`: %+v", setErr) } + if setErr := d.Set("global", flattenApplicationGatewayGlobalConfiguration(props.GlobalConfiguration)); setErr != nil { + return fmt.Errorf("setting `global`: %+v", setErr) + } + if setErr := d.Set("private_endpoint_connection", flattenApplicationGatewayPrivateEndpoints(props.PrivateEndpointConnections)); setErr != nil { return fmt.Errorf("setting `private_endpoint_connection`: %+v", setErr) } @@ -2966,6 +3015,36 @@ func flattenApplicationGatewayIPConfigurations(input *[]network.ApplicationGatew return results } +func expandApplicationGatewayGlobalConfiguration(input []interface{}) (*network.ApplicationGatewayGlobalConfiguration, error) { + if len(input) == 0 { + return nil, nil + } + + v := input[0].(map[string]interface{}) + return &network.ApplicationGatewayGlobalConfiguration{ + EnableRequestBuffering: utils.Bool(v["request_buffering_enabled"].(bool)), + EnableResponseBuffering: utils.Bool(v["response_buffering_enabled"].(bool)), + }, nil +} + +func flattenApplicationGatewayGlobalConfiguration(input *network.ApplicationGatewayGlobalConfiguration) []interface{} { + if input == nil { + return nil + } + + output := make(map[string]interface{}) + + if input.EnableRequestBuffering != nil { + output["request_buffering_enabled"] = *input.EnableRequestBuffering + } + + if input.EnableResponseBuffering != nil { + output["response_buffering_enabled"] = *input.EnableResponseBuffering + } + + return []interface{}{output} +} + func expandApplicationGatewayFrontendPorts(d *pluginsdk.ResourceData) *[]network.ApplicationGatewayFrontendPort { vs := d.Get("frontend_port").(*pluginsdk.Set).List() results := make([]network.ApplicationGatewayFrontendPort, 0) @@ -3599,10 +3678,14 @@ func expandApplicationGatewayRewriteRuleSets(d *pluginsdk.ResourceData) (*[]netw if c["path"] == nil && c["query_string"] == nil { return nil, fmt.Errorf("At least one of `path` or `query_string` must be set") } - if c["path"] != nil { + components := "" + if c["components"] != nil { + components = c["components"].(string) + } + if c["path"] != nil && components != "query_string_only" { urlConfiguration.ModifiedPath = utils.String(c["path"].(string)) } - if c["query_string"] != nil { + if c["query_string"] != nil && components != "path_only" { urlConfiguration.ModifiedQueryString = utils.String(c["query_string"].(string)) } if c["reroute"] != nil { @@ -3733,20 +3816,36 @@ func flattenApplicationGatewayRewriteRuleSets(input *[]network.ApplicationGatewa if actionSet.URLConfiguration != nil { config := *actionSet.URLConfiguration - urlConfig := map[string]interface{}{} - + components := "" + path := "" if config.ModifiedPath != nil { - urlConfig["path"] = *config.ModifiedPath + path = *config.ModifiedPath } + queryString := "" if config.ModifiedQueryString != nil { - urlConfig["query_string"] = *config.ModifiedQueryString + queryString = *config.ModifiedQueryString + } + + if path != queryString { + if path != "" && queryString == "" { + components = "path_only" + } else if queryString != "" && path == "" { + components = "query_string_only" + } } + reroute := false if config.Reroute != nil { - urlConfig["reroute"] = *config.Reroute + reroute = *config.Reroute } - urlConfigs = append(urlConfigs, urlConfig) + + urlConfigs = append(urlConfigs, map[string]interface{}{ + "components": components, + "query_string": queryString, + "path": path, + "reroute": reroute, + }) } } ruleOutput["request_header_configuration"] = requestConfigs diff --git a/internal/services/network/application_gateway_resource_test.go b/internal/services/network/application_gateway_resource_test.go index 68f1e833d7fd..2945740a1695 100644 --- a/internal/services/network/application_gateway_resource_test.go +++ b/internal/services/network/application_gateway_resource_test.go @@ -89,6 +89,36 @@ func TestAccApplicationGateway_autoscaleConfigurationNoMaxCapacity(t *testing.T) }) } +func TestAccApplicationGateway_globalConfiguration(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_application_gateway", "test") + r := ApplicationGatewayResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.createGlobalConfiguration(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("sku.0.name").HasValue("Standard_v2"), + check.That(data.ResourceName).Key("sku.0.tier").HasValue("Standard_v2"), + check.That(data.ResourceName).Key("global.0.request_buffering_enabled").HasValue("true"), + check.That(data.ResourceName).Key("global.0.response_buffering_enabled").HasValue("true"), + ), + }, + data.ImportStep(), + { + Config: r.updateGlobalConfiguration(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("sku.0.name").HasValue("Standard_v2"), + check.That(data.ResourceName).Key("sku.0.tier").HasValue("Standard_v2"), + check.That(data.ResourceName).Key("global.0.request_buffering_enabled").HasValue("false"), + check.That(data.ResourceName).Key("global.0.response_buffering_enabled").HasValue("false"), + ), + }, + data.ImportStep(), + }) +} + func TestAccApplicationGateway_zones(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_application_gateway", "test") r := ApplicationGatewayResource{} @@ -406,6 +436,11 @@ func TestAccApplicationGateway_rewriteRuleSets_rewriteUrl(t *testing.T) { Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), check.That(data.ResourceName).Key("rewrite_rule_set.0.name").Exists(), + check.That(data.ResourceName).Key("rewrite_rule_set.#").HasValue("2"), + check.That(data.ResourceName).Key("rewrite_rule_set.0.rewrite_rule.0.url.0.components").HasValue(""), + check.That(data.ResourceName).Key("rewrite_rule_set.1.rewrite_rule.#").HasValue("2"), + check.That(data.ResourceName).Key("rewrite_rule_set.1.rewrite_rule.0.url.0.components").HasValue("path_only"), + check.That(data.ResourceName).Key("rewrite_rule_set.1.rewrite_rule.1.url.0.components").HasValue("query_string_only"), ), }, data.ImportStep(), @@ -1380,6 +1415,174 @@ resource "azurerm_application_gateway" "test" { `, r.template(data), data.RandomInteger, data.RandomInteger) } +func (r ApplicationGatewayResource) createGlobalConfiguration(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +# since these variables are re-used - a locals block makes this more maintainable +locals { + backend_address_pool_name = "${azurerm_virtual_network.test.name}-beap" + frontend_port_name = "${azurerm_virtual_network.test.name}-feport" + frontend_ip_configuration_name = "${azurerm_virtual_network.test.name}-feip" + http_setting_name = "${azurerm_virtual_network.test.name}-be-htst" + listener_name = "${azurerm_virtual_network.test.name}-httplstn" + request_routing_rule_name = "${azurerm_virtual_network.test.name}-rqrt" +} + +resource "azurerm_public_ip" "test_standard" { + name = "acctest-pubip-standard-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + allocation_method = "Static" + sku = "Standard" +} + +resource "azurerm_application_gateway" "test" { + name = "acctestag-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + + sku { + name = "Standard_v2" + tier = "Standard_v2" + capacity = 2 + } + + gateway_ip_configuration { + name = "my-gateway-ip-configuration" + subnet_id = azurerm_subnet.test.id + } + + frontend_port { + name = local.frontend_port_name + port = 80 + } + + frontend_ip_configuration { + name = local.frontend_ip_configuration_name + public_ip_address_id = azurerm_public_ip.test_standard.id + } + + backend_address_pool { + name = local.backend_address_pool_name + } + + backend_http_settings { + name = local.http_setting_name + cookie_based_affinity = "Disabled" + port = 80 + protocol = "Http" + request_timeout = 1 + } + + global { + request_buffering_enabled = true + response_buffering_enabled = true + } + + http_listener { + name = local.listener_name + frontend_ip_configuration_name = local.frontend_ip_configuration_name + frontend_port_name = local.frontend_port_name + protocol = "Http" + } + + request_routing_rule { + name = local.request_routing_rule_name + rule_type = "Basic" + http_listener_name = local.listener_name + backend_address_pool_name = local.backend_address_pool_name + backend_http_settings_name = local.http_setting_name + priority = 10 + } +} +`, r.template(data), data.RandomInteger, data.RandomInteger) +} + +func (r ApplicationGatewayResource) updateGlobalConfiguration(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +# since these variables are re-used - a locals block makes this more maintainable +locals { + backend_address_pool_name = "${azurerm_virtual_network.test.name}-beap" + frontend_port_name = "${azurerm_virtual_network.test.name}-feport" + frontend_ip_configuration_name = "${azurerm_virtual_network.test.name}-feip" + http_setting_name = "${azurerm_virtual_network.test.name}-be-htst" + listener_name = "${azurerm_virtual_network.test.name}-httplstn" + request_routing_rule_name = "${azurerm_virtual_network.test.name}-rqrt" +} + +resource "azurerm_public_ip" "test_standard" { + name = "acctest-pubip-standard-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + allocation_method = "Static" + sku = "Standard" +} + +resource "azurerm_application_gateway" "test" { + name = "acctestag-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + + sku { + name = "Standard_v2" + tier = "Standard_v2" + capacity = 2 + } + + gateway_ip_configuration { + name = "my-gateway-ip-configuration" + subnet_id = azurerm_subnet.test.id + } + + frontend_port { + name = local.frontend_port_name + port = 80 + } + + frontend_ip_configuration { + name = local.frontend_ip_configuration_name + public_ip_address_id = azurerm_public_ip.test_standard.id + } + + backend_address_pool { + name = local.backend_address_pool_name + } + + backend_http_settings { + name = local.http_setting_name + cookie_based_affinity = "Disabled" + port = 80 + protocol = "Http" + request_timeout = 1 + } + + global { + request_buffering_enabled = false + response_buffering_enabled = false + } + + http_listener { + name = local.listener_name + frontend_ip_configuration_name = local.frontend_ip_configuration_name + frontend_port_name = local.frontend_port_name + protocol = "Http" + } + + request_routing_rule { + name = local.request_routing_rule_name + rule_type = "Basic" + http_listener_name = local.listener_name + backend_address_pool_name = local.backend_address_pool_name + backend_http_settings_name = local.http_setting_name + priority = 10 + } +} +`, r.template(data), data.RandomInteger, data.RandomInteger) +} + func (r ApplicationGatewayResource) UserDefinedIdentity(data acceptance.TestData) string { return fmt.Sprintf(` %s @@ -6056,6 +6259,40 @@ resource "azurerm_application_gateway" "test" { } } + rewrite_rule_set { + name = "${local.rewrite_rule_set_name}_1" + + rewrite_rule { + name = "${local.rewrite_rule_name}_1" + rule_sequence = 1 + + condition { + variable = "var_uri_path" + pattern = ".*article/(.*)/(.*)" + } + + url { + path = "/article.aspx" + components = "path_only" + } + } + + rewrite_rule { + name = "${local.rewrite_rule_name}_2" + rule_sequence = 2 + + condition { + variable = "var_uri_path" + pattern = ".*article2/(.*)/(.*)" + } + + url { + query_string = "id={var_uri_path_1}&title={var_uri_path_2}" + components = "query_string_only" + } + } + } + redirect_configuration { name = local.redirect_configuration_name redirect_type = "Temporary" diff --git a/internal/services/network/express_route_circuit_peering_resource.go b/internal/services/network/express_route_circuit_peering_resource.go index 250c9b10e0e9..e29705151b27 100644 --- a/internal/services/network/express_route_circuit_peering_resource.go +++ b/internal/services/network/express_route_circuit_peering_resource.go @@ -58,12 +58,24 @@ func resourceExpressRouteCircuitPeering() *pluginsdk.Resource { "primary_peer_address_prefix": { Type: pluginsdk.TypeString, - Required: true, + Optional: true, + RequiredWith: []string{ + "secondary_peer_address_prefix", + }, }, "secondary_peer_address_prefix": { Type: pluginsdk.TypeString, - Required: true, + Optional: true, + RequiredWith: []string{ + "primary_peer_address_prefix", + }, + }, + + "ipv4_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: true, }, "vlan_id": { @@ -119,7 +131,7 @@ func resourceExpressRouteCircuitPeering() *pluginsdk.Resource { Schema: map[string]*pluginsdk.Schema{ "microsoft_peering": { Type: pluginsdk.TypeList, - Required: true, + Optional: true, MaxItems: 1, Elem: &pluginsdk.Resource{ Schema: map[string]*pluginsdk.Schema{ @@ -159,6 +171,12 @@ func resourceExpressRouteCircuitPeering() *pluginsdk.Resource { Required: true, }, + "enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: true, + }, + "route_filter_id": { Type: pluginsdk.TypeString, Optional: true, @@ -188,6 +206,11 @@ func resourceExpressRouteCircuitPeering() *pluginsdk.Resource { Optional: true, ValidateFunc: azure.ValidateResourceID, }, + + "gateway_manager_etag": { + Type: pluginsdk.TypeString, + Computed: true, + }, }, } } @@ -228,20 +251,38 @@ func resourceExpressRouteCircuitPeeringCreateUpdate(d *pluginsdk.ResourceData, m parameters := network.ExpressRouteCircuitPeering{ ExpressRouteCircuitPeeringPropertiesFormat: &network.ExpressRouteCircuitPeeringPropertiesFormat{ - PeeringType: network.ExpressRoutePeeringType(id.PeeringName), - SharedKey: utils.String(sharedKey), - PrimaryPeerAddressPrefix: utils.String(primaryPeerAddressPrefix), - SecondaryPeerAddressPrefix: utils.String(secondaryPeerAddressPrefix), - AzureASN: utils.Int32(int32(azureASN)), - PeerASN: utils.Int64(int64(peerASN)), - VlanID: utils.Int32(int32(vlanId)), + PeeringType: network.ExpressRoutePeeringType(id.PeeringName), + SharedKey: utils.String(sharedKey), + AzureASN: utils.Int32(int32(azureASN)), + PeerASN: utils.Int64(int64(peerASN)), + VlanID: utils.Int32(int32(vlanId)), + GatewayManagerEtag: utils.String(d.Get("gateway_manager_etag").(string)), }, } + ipv4Enabled := d.Get("ipv4_enabled").(bool) + if ipv4Enabled { + parameters.ExpressRouteCircuitPeeringPropertiesFormat.State = network.ExpressRoutePeeringStateEnabled + } else { + parameters.ExpressRouteCircuitPeeringPropertiesFormat.State = network.ExpressRoutePeeringStateDisabled + } + + if !strings.EqualFold(primaryPeerAddressPrefix, "") { + parameters.PrimaryPeerAddressPrefix = utils.String(primaryPeerAddressPrefix) + } + + if !strings.EqualFold(secondaryPeerAddressPrefix, "") { + parameters.SecondaryPeerAddressPrefix = utils.String(secondaryPeerAddressPrefix) + } + if strings.EqualFold(id.PeeringName, string(network.ExpressRoutePeeringTypeMicrosoftPeering)) { peerings := d.Get("microsoft_peering_config").([]interface{}) - if len(peerings) == 0 { - return fmt.Errorf("`microsoft_peering_config` must be specified when `peering_type` is set to `MicrosoftPeering`") + if len(peerings) == 0 && primaryPeerAddressPrefix != "" { + return fmt.Errorf("`microsoft_peering_config` must be specified when config for Ipv4 and `peering_type` is set to `MicrosoftPeering`") + } + + if len(peerings) != 0 && (primaryPeerAddressPrefix == "" || secondaryPeerAddressPrefix == "") { + return fmt.Errorf("`primary_peer_address_prefix, secondary_peer_address_prefix` must be specified when config for Ipv4") } peeringConfig := expandExpressRouteCircuitPeeringMicrosoftConfig(peerings) @@ -252,23 +293,20 @@ func resourceExpressRouteCircuitPeeringCreateUpdate(d *pluginsdk.ResourceData, m ID: utils.String(route_filter_id), } } + } else if route_filter_id != "" { + return fmt.Errorf("`route_filter_id` may only be specified when `peering_type` is set to `MicrosoftPeering`") + } - ipv6Peering := d.Get("ipv6").([]interface{}) - ipv6PeeringConfig, err := expandExpressRouteCircuitIpv6PeeringConfig(ipv6Peering) - if err != nil { - return err - } - parameters.ExpressRouteCircuitPeeringPropertiesFormat.Ipv6PeeringConfig = ipv6PeeringConfig - } else { - if route_filter_id != "" { - return fmt.Errorf("`route_filter_id` may only be specified when `peering_type` is set to `MicrosoftPeering`") - } + ipv6Peering := d.Get("ipv6").([]interface{}) + if len(ipv6Peering) != 0 && id.PeeringName == string(network.ExpressRoutePeeringTypeAzurePublicPeering) { + return fmt.Errorf("`ipv6` may only be specified when `peering_type` is `MicrosoftPeering` or `AzurePrivatePeering`") + } - ipv6Peering := d.Get("ipv6").([]interface{}) - if len(ipv6Peering) != 0 { - return fmt.Errorf("`ipv6` may only be specified when `peering_type` is set to `MicrosoftPeering`") - } + ipv6PeeringConfig, err := expandExpressRouteCircuitIpv6PeeringConfig(ipv6Peering) + if err != nil { + return err } + parameters.ExpressRouteCircuitPeeringPropertiesFormat.Ipv6PeeringConfig = ipv6PeeringConfig future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.ExpressRouteCircuitName, id.PeeringName, parameters) if err != nil { @@ -315,6 +353,8 @@ func resourceExpressRouteCircuitPeeringRead(d *pluginsdk.ResourceData, meta inte d.Set("primary_peer_address_prefix", props.PrimaryPeerAddressPrefix) d.Set("secondary_peer_address_prefix", props.SecondaryPeerAddressPrefix) d.Set("vlan_id", props.VlanID) + d.Set("gateway_manager_etag", props.GatewayManagerEtag) + d.Set("ipv4_enabled", props.State == network.ExpressRoutePeeringStateEnabled) routeFilterId := "" if props.RouteFilter != nil && props.RouteFilter.ID != nil { @@ -388,10 +428,24 @@ func expandExpressRouteCircuitIpv6PeeringConfig(input []interface{}) (*network.I v := input[0].(map[string]interface{}) peeringConfig := network.Ipv6ExpressRouteCircuitPeeringConfig{ - PrimaryPeerAddressPrefix: utils.String(v["primary_peer_address_prefix"].(string)), - SecondaryPeerAddressPrefix: utils.String(v["secondary_peer_address_prefix"].(string)), - MicrosoftPeeringConfig: expandExpressRouteCircuitPeeringMicrosoftConfig(v["microsoft_peering"].([]interface{})), + MicrosoftPeeringConfig: expandExpressRouteCircuitPeeringMicrosoftConfig(v["microsoft_peering"].([]interface{})), + State: network.ExpressRouteCircuitPeeringStateEnabled, } + + primaryPeerAddressPrefix := v["primary_peer_address_prefix"].(string) + secondaryPeerAddressPrefix := v["secondary_peer_address_prefix"].(string) + if !strings.EqualFold(primaryPeerAddressPrefix, "") { + peeringConfig.PrimaryPeerAddressPrefix = utils.String(primaryPeerAddressPrefix) + } + if !strings.EqualFold(secondaryPeerAddressPrefix, "") { + peeringConfig.SecondaryPeerAddressPrefix = utils.String(secondaryPeerAddressPrefix) + } + + ipv6Enabled := v["enabled"].(bool) + if !ipv6Enabled { + peeringConfig.State = network.ExpressRouteCircuitPeeringStateDisabled + } + routeFilterId := v["route_filter_id"].(string) if routeFilterId != "" { if _, err := parse.RouteFilterID(routeFilterId); err != nil { @@ -448,6 +502,7 @@ func flattenExpressRouteCircuitIpv6PeeringConfig(input *network.Ipv6ExpressRoute "primary_peer_address_prefix": primaryPeerAddressPrefix, "secondary_peer_address_prefix": secondaryPeerAddressPrefix, "route_filter_id": routeFilterId, + "enabled": input.State == network.ExpressRouteCircuitPeeringStateEnabled, }, } } diff --git a/internal/services/network/network_connection_monitor_resource.go b/internal/services/network/network_connection_monitor_resource.go index 7e6ae97a5d91..e0f5e2fd80e0 100644 --- a/internal/services/network/network_connection_monitor_resource.go +++ b/internal/services/network/network_connection_monitor_resource.go @@ -6,12 +6,12 @@ import ( "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2021-08-01/network" "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/helpers/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" computeValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/compute/validate" - logAnalyticsValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/loganalytics/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/parse" networkValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tags" @@ -167,7 +167,7 @@ func resourceNetworkConnectionMonitorSchema() map[string]*pluginsdk.Schema { Computed: true, ValidateFunc: validation.Any( computeValidate.VirtualMachineID, - logAnalyticsValidate.LogAnalyticsWorkspaceID, + workspaces.ValidateWorkspaceID, networkValidate.SubnetID, networkValidate.VirtualNetworkID, ), @@ -422,7 +422,7 @@ func resourceNetworkConnectionMonitorSchema() map[string]*pluginsdk.Schema { ConfigMode: pluginsdk.SchemaConfigModeAttr, Elem: &pluginsdk.Schema{ Type: pluginsdk.TypeString, - ValidateFunc: logAnalyticsValidate.LogAnalyticsWorkspaceID, + ValidateFunc: workspaces.ValidateWorkspaceID, }, }, diff --git a/internal/services/network/parse/virtual_machine_scale_set_public_ip_address.go b/internal/services/network/parse/virtual_machine_scale_set_public_ip_address.go new file mode 100644 index 000000000000..9b4765ffbed5 --- /dev/null +++ b/internal/services/network/parse/virtual_machine_scale_set_public_ip_address.go @@ -0,0 +1,93 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + "strings" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +type VirtualMachineScaleSetPublicIPAddressId struct { + SubscriptionId string + ResourceGroup string + VirtualMachineScaleSetName string + VirtualMachineName string + NetworkInterfaceName string + IpConfigurationName string + PublicIPAddressName string +} + +func NewVirtualMachineScaleSetPublicIPAddressID(subscriptionId, resourceGroup, virtualMachineScaleSetName, virtualMachineName, networkInterfaceName, ipConfigurationName, publicIPAddressName string) VirtualMachineScaleSetPublicIPAddressId { + return VirtualMachineScaleSetPublicIPAddressId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + VirtualMachineScaleSetName: virtualMachineScaleSetName, + VirtualMachineName: virtualMachineName, + NetworkInterfaceName: networkInterfaceName, + IpConfigurationName: ipConfigurationName, + PublicIPAddressName: publicIPAddressName, + } +} + +func (id VirtualMachineScaleSetPublicIPAddressId) String() string { + segments := []string{ + fmt.Sprintf("Public I P Address Name %q", id.PublicIPAddressName), + fmt.Sprintf("Ip Configuration Name %q", id.IpConfigurationName), + fmt.Sprintf("Network Interface Name %q", id.NetworkInterfaceName), + fmt.Sprintf("Virtual Machine Name %q", id.VirtualMachineName), + fmt.Sprintf("Virtual Machine Scale Set Name %q", id.VirtualMachineScaleSetName), + fmt.Sprintf("Resource Group %q", id.ResourceGroup), + } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "Virtual Machine Scale Set Public I P Address", segmentsStr) +} + +func (id VirtualMachineScaleSetPublicIPAddressId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/virtualMachineScaleSets/%s/virtualMachines/%s/networkInterfaces/%s/ipConfigurations/%s/publicIPAddresses/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.VirtualMachineScaleSetName, id.VirtualMachineName, id.NetworkInterfaceName, id.IpConfigurationName, id.PublicIPAddressName) +} + +// VirtualMachineScaleSetPublicIPAddressID parses a VirtualMachineScaleSetPublicIPAddress ID into an VirtualMachineScaleSetPublicIPAddressId struct +func VirtualMachineScaleSetPublicIPAddressID(input string) (*VirtualMachineScaleSetPublicIPAddressId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := VirtualMachineScaleSetPublicIPAddressId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + if resourceId.VirtualMachineScaleSetName, err = id.PopSegment("virtualMachineScaleSets"); err != nil { + return nil, err + } + if resourceId.VirtualMachineName, err = id.PopSegment("virtualMachines"); err != nil { + return nil, err + } + if resourceId.NetworkInterfaceName, err = id.PopSegment("networkInterfaces"); err != nil { + return nil, err + } + if resourceId.IpConfigurationName, err = id.PopSegment("ipConfigurations"); err != nil { + return nil, err + } + if resourceId.PublicIPAddressName, err = id.PopSegment("publicIPAddresses"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} diff --git a/internal/services/network/parse/virtual_machine_scale_set_public_ip_address_test.go b/internal/services/network/parse/virtual_machine_scale_set_public_ip_address_test.go new file mode 100644 index 000000000000..0a75f5252697 --- /dev/null +++ b/internal/services/network/parse/virtual_machine_scale_set_public_ip_address_test.go @@ -0,0 +1,176 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "testing" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +var _ resourceids.Id = VirtualMachineScaleSetPublicIPAddressId{} + +func TestVirtualMachineScaleSetPublicIPAddressIDFormatter(t *testing.T) { + actual := NewVirtualMachineScaleSetPublicIPAddressID("12345678-1234-9876-4563-123456789012", "resGroup1", "scaleSet1", "virtualMachine1", "networkInterface1", "ipConfiguration1", "publicIpAddress1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/virtualMachineScaleSets/scaleSet1/virtualMachines/virtualMachine1/networkInterfaces/networkInterface1/ipConfigurations/ipConfiguration1/publicIPAddresses/publicIpAddress1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestVirtualMachineScaleSetPublicIPAddressID(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *VirtualMachineScaleSetPublicIPAddressId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing VirtualMachineScaleSetName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/", + Error: true, + }, + + { + // missing value for VirtualMachineScaleSetName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/virtualMachineScaleSets/", + Error: true, + }, + + { + // missing VirtualMachineName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/virtualMachineScaleSets/scaleSet1/", + Error: true, + }, + + { + // missing value for VirtualMachineName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/virtualMachineScaleSets/scaleSet1/virtualMachines/", + Error: true, + }, + + { + // missing NetworkInterfaceName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/virtualMachineScaleSets/scaleSet1/virtualMachines/virtualMachine1/", + Error: true, + }, + + { + // missing value for NetworkInterfaceName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/virtualMachineScaleSets/scaleSet1/virtualMachines/virtualMachine1/networkInterfaces/", + Error: true, + }, + + { + // missing IpConfigurationName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/virtualMachineScaleSets/scaleSet1/virtualMachines/virtualMachine1/networkInterfaces/networkInterface1/", + Error: true, + }, + + { + // missing value for IpConfigurationName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/virtualMachineScaleSets/scaleSet1/virtualMachines/virtualMachine1/networkInterfaces/networkInterface1/ipConfigurations/", + Error: true, + }, + + { + // missing PublicIPAddressName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/virtualMachineScaleSets/scaleSet1/virtualMachines/virtualMachine1/networkInterfaces/networkInterface1/ipConfigurations/ipConfiguration1/", + Error: true, + }, + + { + // missing value for PublicIPAddressName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/virtualMachineScaleSets/scaleSet1/virtualMachines/virtualMachine1/networkInterfaces/networkInterface1/ipConfigurations/ipConfiguration1/publicIPAddresses/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/virtualMachineScaleSets/scaleSet1/virtualMachines/virtualMachine1/networkInterfaces/networkInterface1/ipConfigurations/ipConfiguration1/publicIPAddresses/publicIpAddress1", + Expected: &VirtualMachineScaleSetPublicIPAddressId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + VirtualMachineScaleSetName: "scaleSet1", + VirtualMachineName: "virtualMachine1", + NetworkInterfaceName: "networkInterface1", + IpConfigurationName: "ipConfiguration1", + PublicIPAddressName: "publicIpAddress1", + }, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.COMPUTE/VIRTUALMACHINESCALESETS/SCALESET1/VIRTUALMACHINES/VIRTUALMACHINE1/NETWORKINTERFACES/NETWORKINTERFACE1/IPCONFIGURATIONS/IPCONFIGURATION1/PUBLICIPADDRESSES/PUBLICIPADDRESS1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := VirtualMachineScaleSetPublicIPAddressID(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.VirtualMachineScaleSetName != v.Expected.VirtualMachineScaleSetName { + t.Fatalf("Expected %q but got %q for VirtualMachineScaleSetName", v.Expected.VirtualMachineScaleSetName, actual.VirtualMachineScaleSetName) + } + if actual.VirtualMachineName != v.Expected.VirtualMachineName { + t.Fatalf("Expected %q but got %q for VirtualMachineName", v.Expected.VirtualMachineName, actual.VirtualMachineName) + } + if actual.NetworkInterfaceName != v.Expected.NetworkInterfaceName { + t.Fatalf("Expected %q but got %q for NetworkInterfaceName", v.Expected.NetworkInterfaceName, actual.NetworkInterfaceName) + } + if actual.IpConfigurationName != v.Expected.IpConfigurationName { + t.Fatalf("Expected %q but got %q for IpConfigurationName", v.Expected.IpConfigurationName, actual.IpConfigurationName) + } + if actual.PublicIPAddressName != v.Expected.PublicIPAddressName { + t.Fatalf("Expected %q but got %q for PublicIPAddressName", v.Expected.PublicIPAddressName, actual.PublicIPAddressName) + } + } +} diff --git a/internal/services/network/private_endpoint_resource.go b/internal/services/network/private_endpoint_resource.go index ff406428168d..fbfe33c0a231 100644 --- a/internal/services/network/private_endpoint_resource.go +++ b/internal/services/network/private_endpoint_resource.go @@ -11,18 +11,19 @@ import ( "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2021-08-01/network" "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + mariaDB "github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers" "github.com/hashicorp/go-azure-sdk/resource-manager/privatedns/2018-09-01/privatezones" "github.com/hashicorp/go-azure-sdk/resource-manager/signalr/2022-02-01/signalr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/locks" cosmosParse "github.com/hashicorp/terraform-provider-azurerm/internal/services/cosmos/parse" - mariaDBParse "github.com/hashicorp/terraform-provider-azurerm/internal/services/mariadb/parse" mysqlParse "github.com/hashicorp/terraform-provider-azurerm/internal/services/mysql/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/validate" - postgresqlParse "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" @@ -164,6 +165,34 @@ func resourcePrivateEndpoint() *pluginsdk.Resource { }, }, + "ip_configuration": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.PrivateLinkName, + }, + "private_ip_address": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + "subresource_name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, + }, + }, + "custom_dns_configs": { Type: pluginsdk.TypeList, Computed: true, @@ -268,6 +297,7 @@ func resourcePrivateEndpointCreate(d *pluginsdk.ResourceData, meta interface{}) location := azure.NormalizeLocation(d.Get("location").(string)) privateDnsZoneGroup := d.Get("private_dns_zone_group").([]interface{}) privateServiceConnections := d.Get("private_service_connection").([]interface{}) + ipConfigurations := d.Get("ip_configuration").([]interface{}) subnetId := d.Get("subnet_id").(string) parameters := network.PrivateEndpoint{ @@ -278,10 +308,20 @@ func resourcePrivateEndpointCreate(d *pluginsdk.ResourceData, meta interface{}) Subnet: &network.Subnet{ ID: utils.String(subnetId), }, + IPConfigurations: expandPrivateEndpointIPConfigurations(ipConfigurations), }, Tags: tags.Expand(d.Get("tags").(map[string]interface{})), } + err = validatePrivateLinkServiceId(*parameters.PrivateEndpointProperties.PrivateLinkServiceConnections) + if err != nil { + return err + } + err = validatePrivateLinkServiceId(*parameters.PrivateEndpointProperties.ManualPrivateLinkServiceConnections) + if err != nil { + return err + } + cosmosDbResIds := getCosmosDbResIdInPrivateServiceConnections(parameters.PrivateEndpointProperties) for _, cosmosDbResId := range cosmosDbResIds { log.Printf("[DEBUG] Add Lock For Private Endpoint %q, lock name: %q", id.Name, cosmosDbResId) @@ -289,17 +329,45 @@ func resourcePrivateEndpointCreate(d *pluginsdk.ResourceData, meta interface{}) //goland:noinspection GoDeferInLoop defer locks.UnlockByName(cosmosDbResId, "azurerm_private_endpoint") } + locks.ByName(subnetId, "azurerm_private_endpoint") + defer locks.UnlockByName(subnetId, "azurerm_private_endpoint") - future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.Name, parameters) - if err != nil { - if strings.EqualFold(err.Error(), "is missing required parameter 'group Id'") { - return fmt.Errorf("creating Private Endpoint %q (Resource Group %q) due to missing 'group Id', ensure that the 'subresource_names' type is populated: %+v", id.Name, id.ResourceGroup, err) - } else { - return fmt.Errorf("creating Private Endpoint %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + err = pluginsdk.Retry(d.Timeout(pluginsdk.TimeoutCreate), func() *resource.RetryError { + future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.Name, parameters) + if err != nil { + switch { + case strings.EqualFold(err.Error(), "is missing required parameter 'group Id'"): + { + return &resource.RetryError{ + Err: fmt.Errorf("creating Private Endpoint %q (Resource Group %q) due to missing 'group Id', ensure that the 'subresource_names' type is populated: %+v", id.Name, id.ResourceGroup, err), + Retryable: false, + } + } + case strings.Contains(err.Error(), "PrivateLinkServiceId Invalid private link service id"): + { + return &resource.RetryError{ + Err: fmt.Errorf("creating Private Endpoint %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err), + Retryable: true, + } + } + default: + return &resource.RetryError{ + Err: fmt.Errorf("creating Private Endpoint %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err), + Retryable: false, + } + } } - } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for creation of Private Endpoint %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return &resource.RetryError{ + Err: fmt.Errorf("waiting for creation of Private Endpoint %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err), + Retryable: false, + } + } + return nil + }) + if err != nil { + return err } d.SetId(id.ID()) @@ -317,6 +385,20 @@ func resourcePrivateEndpointCreate(d *pluginsdk.ResourceData, meta interface{}) return resourcePrivateEndpointRead(d, meta) } +func validatePrivateLinkServiceId(endpoints []network.PrivateLinkServiceConnection) error { + for _, connection := range endpoints { + _, errors := azure.ValidateResourceID(*connection.PrivateLinkServiceID, "PrivateLinkServiceID") + if len(errors) == 0 { + continue + } + _, errors = validate.PrivateConnectionResourceAlias(*connection.PrivateLinkServiceID, "PrivateLinkServiceID") + if len(errors) != 0 { + return fmt.Errorf("PrivateLinkServiceId Invalid: %q", *connection.PrivateLinkServiceID) + } + } + return nil +} + func getCosmosDbResIdInPrivateServiceConnections(p *network.PrivateEndpointProperties) []string { var ids []string exists := make(map[string]struct{}) @@ -364,6 +446,7 @@ func resourcePrivateEndpointUpdate(d *pluginsdk.ResourceData, meta interface{}) location := azure.NormalizeLocation(d.Get("location").(string)) privateDnsZoneGroup := d.Get("private_dns_zone_group").([]interface{}) privateServiceConnections := d.Get("private_service_connection").([]interface{}) + ipConfigurations := d.Get("ip_configuration").([]interface{}) subnetId := d.Get("subnet_id").(string) // TODO: in future it'd be nice to support conditional updates here, but one problem at a time @@ -375,20 +458,58 @@ func resourcePrivateEndpointUpdate(d *pluginsdk.ResourceData, meta interface{}) Subnet: &network.Subnet{ ID: utils.String(subnetId), }, + IPConfigurations: expandPrivateEndpointIPConfigurations(ipConfigurations), }, Tags: tags.Expand(d.Get("tags").(map[string]interface{})), } - future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.Name, parameters) + err = validatePrivateLinkServiceId(*parameters.PrivateEndpointProperties.PrivateLinkServiceConnections) if err != nil { - if strings.EqualFold(err.Error(), "is missing required parameter 'group Id'") { - return fmt.Errorf("updating Private Endpoint %q (Resource Group %q) due to missing 'group Id', ensure that the 'subresource_names' type is populated: %+v", id.Name, id.ResourceGroup, err) - } else { - return fmt.Errorf("updating Private Endpoint %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) - } + return err } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for update of Private Endpoint %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + err = validatePrivateLinkServiceId(*parameters.PrivateEndpointProperties.ManualPrivateLinkServiceConnections) + if err != nil { + return err + } + + locks.ByName(subnetId, "azurerm_private_endpoint") + defer locks.UnlockByName(subnetId, "azurerm_private_endpoint") + + err = pluginsdk.Retry(d.Timeout(pluginsdk.TimeoutCreate), func() *resource.RetryError { + future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.Name, parameters) + if err != nil { + switch { + case strings.EqualFold(err.Error(), "is missing required parameter 'group Id'"): + { + return &resource.RetryError{ + Err: fmt.Errorf("updating Private Endpoint %q (Resource Group %q) due to missing 'group Id', ensure that the 'subresource_names' type is populated: %+v", id.Name, id.ResourceGroup, err), + Retryable: false, + } + } + case strings.Contains(err.Error(), "PrivateLinkServiceId Invalid private link service id"): + { + return &resource.RetryError{ + Err: fmt.Errorf("creating Private Endpoint %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err), + Retryable: true, + } + } + default: + return &resource.RetryError{ + Err: fmt.Errorf("updating Private Endpoint %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err), + } + } + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return &resource.RetryError{ + Err: fmt.Errorf("waiting for update of Private Endpoint %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err), + Retryable: false, + } + } + return nil + }) + if err != nil { + return err } // 1 Private Endpoint can have 1 Private DNS Zone Group - so to update we need to Delete & Recreate @@ -495,6 +616,11 @@ func resourcePrivateEndpointRead(d *pluginsdk.ResourceData, meta interface{}) er return fmt.Errorf("setting `private_service_connection`: %+v", err) } + flattenedipconfiguration := flattenPrivateEndpointIPConfigurations(props.IPConfigurations) + if err := d.Set("ip_configuration", flattenedipconfiguration); err != nil { + return fmt.Errorf("setting `ip_configuration`: %+v", err) + } + subnetId := "" if props.Subnet != nil && props.Subnet.ID != nil { subnetId = *props.Subnet.ID @@ -547,6 +673,7 @@ func resourcePrivateEndpointDelete(d *pluginsdk.ResourceData, meta interface{}) } log.Printf("[DEBUG] Deleted the Private DNS Zone Group associated with Private Endpoint %q / Resource Group %q.", id.Name, id.ResourceGroup) + subnetId := d.Get("subnet_id").(string) privateServiceConnections := d.Get("private_service_connection").([]interface{}) parameters := network.PrivateEndpoint{ PrivateEndpointProperties: &network.PrivateEndpointProperties{ @@ -560,6 +687,8 @@ func resourcePrivateEndpointDelete(d *pluginsdk.ResourceData, meta interface{}) //goland:noinspection GoDeferInLoop defer locks.UnlockByName(cosmosDbResId, "azurerm_private_endpoint") } + locks.ByName(subnetId, "azurerm_private_endpoint") + defer locks.UnlockByName(subnetId, "azurerm_private_endpoint") log.Printf("[DEBUG] Deleting the Private Endpoint %q / Resource Group %q..", id.Name, id.ResourceGroup) future, err := client.Delete(ctx, id.ResourceGroup, id.Name) @@ -611,6 +740,45 @@ func expandPrivateLinkEndpointServiceConnection(input []interface{}, parseManual return &results } +func expandPrivateEndpointIPConfigurations(input []interface{}) *[]network.PrivateEndpointIPConfiguration { + results := make([]network.PrivateEndpointIPConfiguration, 0) + + for _, item := range input { + v := item.(map[string]interface{}) + privateIPAddress := v["private_ip_address"].(string) + subResourceName := v["subresource_name"].(string) + name := v["name"].(string) + result := network.PrivateEndpointIPConfiguration{ + Name: utils.String(name), + PrivateEndpointIPConfigurationProperties: &network.PrivateEndpointIPConfigurationProperties{ + PrivateIPAddress: utils.String(privateIPAddress), + GroupID: utils.String(subResourceName), + MemberName: utils.String(subResourceName), + }, + } + results = append(results, result) + } + + return &results +} + +func flattenPrivateEndpointIPConfigurations(ipConfigurations *[]network.PrivateEndpointIPConfiguration) []interface{} { + results := make([]interface{}, 0) + if ipConfigurations == nil { + return results + } + + for _, item := range *ipConfigurations { + results = append(results, map[string]interface{}{ + "name": item.Name, + "private_ip_address": item.PrivateIPAddress, + "subresource_name": item.GroupID, + }) + } + + return results +} + func flattenCustomDnsConfigs(customDnsConfigs *[]network.CustomDNSConfigPropertiesFormat) []interface{} { results := make([]interface{}, 0) if customDnsConfigs == nil { @@ -663,7 +831,7 @@ func flattenPrivateLinkEndpointServiceConnection(serviceConnections *[]network.P // There is a bug from service, the PE created from portal could be with the connection id for postgresql server "Microsoft.DBForPostgreSQL" instead of "Microsoft.DBforPostgreSQL" // and for Mysql and MariaDB if strings.Contains(strings.ToLower(privateConnectionId), "microsoft.dbforpostgresql") { - if serverId, err := postgresqlParse.ServerID(privateConnectionId); err == nil { + if serverId, err := servers.ParseServerID(privateConnectionId); err == nil { privateConnectionId = serverId.ID() } } @@ -673,7 +841,7 @@ func flattenPrivateLinkEndpointServiceConnection(serviceConnections *[]network.P } } if strings.Contains(strings.ToLower(privateConnectionId), "microsoft.dbformariadb") { - if serverId, err := mariaDBParse.ServerID(privateConnectionId); err == nil { + if serverId, err := mariaDB.ParseServerID(privateConnectionId); err == nil { privateConnectionId = serverId.ID() } } @@ -725,7 +893,7 @@ func flattenPrivateLinkEndpointServiceConnection(serviceConnections *[]network.P // There is a bug from service, the PE created from portal could be with the connection id for postgresql server "Microsoft.DBForPostgreSQL" instead of "Microsoft.DBforPostgreSQL" // and for Mysql and MariaDB if strings.Contains(strings.ToLower(privateConnectionId), "microsoft.dbforpostgresql") { - if serverId, err := postgresqlParse.ServerID(privateConnectionId); err == nil { + if serverId, err := servers.ParseServerID(privateConnectionId); err == nil { privateConnectionId = serverId.ID() } } @@ -735,7 +903,7 @@ func flattenPrivateLinkEndpointServiceConnection(serviceConnections *[]network.P } } if strings.Contains(strings.ToLower(privateConnectionId), "microsoft.dbformariadb") { - if serverId, err := mariaDBParse.ServerID(privateConnectionId); err == nil { + if serverId, err := mariaDB.ParseServerID(privateConnectionId); err == nil { privateConnectionId = serverId.ID() } } diff --git a/internal/services/network/private_endpoint_resource_test.go b/internal/services/network/private_endpoint_resource_test.go index 56bd2a674ce1..e32e8b8fdbc0 100644 --- a/internal/services/network/private_endpoint_resource_test.go +++ b/internal/services/network/private_endpoint_resource_test.go @@ -215,7 +215,7 @@ func TestAccPrivateEndpoint_privateConnectionAlias(t *testing.T) { data.ResourceTest(t, r, []acceptance.TestStep{ { - Config: r.privateConnectionAlias(data), + Config: r.privateConnectionAlias(data, false), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), check.That(data.ResourceName).Key("subnet_id").Exists(), @@ -228,6 +228,22 @@ func TestAccPrivateEndpoint_privateConnectionAlias(t *testing.T) { }) } +func TestAccPrivateEndpoint_updateToPrivateConnectionAlias(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_private_endpoint", "test") + r := PrivateEndpointResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.privateConnectionAlias(data, false), + }, + data.ImportStep(), + { + Config: r.privateConnectionAlias(data, true), + }, + data.ImportStep(), + }) +} + func (t PrivateEndpointResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { id, err := parse.PrivateEndpointID(state.ID) if err != nil { @@ -242,6 +258,25 @@ func (t PrivateEndpointResource) Exists(ctx context.Context, clients *clients.Cl return utils.Bool(resp.ID != nil), nil } +func TestAccPrivateEndpoint_multipleInstances(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_private_endpoint", "test") + r := PrivateEndpointResource{} + + instanceCount := 5 + var checks []pluginsdk.TestCheckFunc + for i := 0; i < instanceCount; i++ { + checks = append(checks, check.That(fmt.Sprintf("%s.%d", data.ResourceName, i)).ExistsInAzure(r)) + } + + config := r.multipleInstances(data, instanceCount) + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: config, + Check: acceptance.ComposeTestCheckFunc(checks...), + }, + }) +} + func (PrivateEndpointResource) template(data acceptance.TestData, seviceCfg string) string { return fmt.Sprintf(` provider "azurerm" { @@ -251,7 +286,7 @@ provider "azurerm" { data "azurerm_subscription" "current" {} resource "azurerm_resource_group" "test" { - name = "acctestRG-privatelink-%d" + name = "zjhe-acctestRG-privatelink-%d" location = "%s" } @@ -416,7 +451,7 @@ provider "azurerm" { } resource "azurerm_resource_group" "test" { - name = "acctestRG-privatelink-%d" + name = "zjhe-acctestRG-privatelink-%d" location = "%s" } @@ -496,7 +531,7 @@ provider "azurerm" { } resource "azurerm_resource_group" "test" { - name = "acctestRG-privatelink-%d" + name = "zjhe-acctestRG-privatelink-%d" location = "%s" } @@ -571,7 +606,7 @@ provider "azurerm" { } resource "azurerm_resource_group" "test" { - name = "acctestRG-privatelink-%d" + name = "zjhe-acctestRG-privatelink-%d" location = "%s" } @@ -656,7 +691,7 @@ provider "azurerm" { } resource "azurerm_resource_group" "test" { - name = "acctestRG-privatelink-%d" + name = "zjhe-acctestRG-privatelink-%d" location = "%s" } @@ -729,7 +764,15 @@ resource "azurerm_private_endpoint" "test" { `, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger) } -func (r PrivateEndpointResource) privateConnectionAlias(data acceptance.TestData) string { +func (r PrivateEndpointResource) privateConnectionAlias(data acceptance.TestData, withTags bool) string { + tags := ` + tags = { + env = "TEST" + } +` + if !withTags { + tags = "" + } return fmt.Sprintf(` %s @@ -745,6 +788,27 @@ resource "azurerm_private_endpoint" "test" { private_connection_resource_alias = azurerm_private_link_service.test.alias request_message = "test" } +%s } -`, r.template(data, r.serviceAutoApprove(data)), data.RandomInteger) +`, r.template(data, r.serviceAutoApprove(data)), data.RandomInteger, tags) +} + +func (r PrivateEndpointResource) multipleInstances(data acceptance.TestData, count int) string { + return fmt.Sprintf(` +%s + +resource "azurerm_private_endpoint" "test" { + count = %d + name = "acctest-privatelink-%d-${count.index}" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + subnet_id = azurerm_subnet.endpoint.id + + private_service_connection { + name = azurerm_private_link_service.test.name + is_manual_connection = false + private_connection_resource_id = azurerm_private_link_service.test.id + } +} +`, r.template(data, r.serviceAutoApprove(data)), count, data.RandomInteger) } diff --git a/internal/services/network/registration.go b/internal/services/network/registration.go index 9980984609b9..87082130a4a8 100644 --- a/internal/services/network/registration.go +++ b/internal/services/network/registration.go @@ -93,6 +93,8 @@ func (r Registration) SupportedResources() map[string]*pluginsdk.Resource { "azurerm_route_filter": resourceRouteFilter(), "azurerm_route_table": resourceRouteTable(), "azurerm_route": resourceRoute(), + "azurerm_route_server": resourceRouteServer(), + "azurerm_route_server_bgp_connection": resourceRouteServerBgpConnection(), "azurerm_virtual_hub_security_partner_provider": resourceVirtualHubSecurityPartnerProvider(), "azurerm_subnet_service_endpoint_storage_policy": resourceSubnetServiceEndpointStoragePolicy(), "azurerm_subnet_network_security_group_association": resourceSubnetNetworkSecurityGroupAssociation(), diff --git a/internal/services/network/resourceids.go b/internal/services/network/resourceids.go index bcd1ae1ebdd9..793ef0434518 100644 --- a/internal/services/network/resourceids.go +++ b/internal/services/network/resourceids.go @@ -105,3 +105,6 @@ package network // Load balancer //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=InboundNatRule -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/loadBalancers/loadBalancer1/inboundNatRules/natrule1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=LoadBalancerBackendAddressPool -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/loadBalancers/loadBalancer1/backendAddressPools/backendAddressPool1 + +// Virtual Machine Scale Set +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=VirtualMachineScaleSetPublicIPAddress -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/virtualMachineScaleSets/scaleSet1/virtualMachines/virtualMachine1/networkInterfaces/networkInterface1/ipConfigurations/ipConfiguration1/publicIPAddresses/publicIpAddress1 diff --git a/internal/services/network/route_server_bgp_connection_resource.go b/internal/services/network/route_server_bgp_connection_resource.go new file mode 100644 index 000000000000..e88667a5b8d7 --- /dev/null +++ b/internal/services/network/route_server_bgp_connection_resource.go @@ -0,0 +1,170 @@ +package network + +import ( + "fmt" + "log" + "time" + + "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2021-08-01/network" + "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/locks" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/validate" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +func resourceRouteServerBgpConnection() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Create: resourceRouteServerBgpConnectionCreate, + Read: resourceRouteServerBgpConnectionRead, + Delete: resourceRouteServerBgpConnectionDelete, + + Timeouts: &pluginsdk.ResourceTimeout{ + Create: pluginsdk.DefaultTimeout(30 * time.Minute), + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + Delete: pluginsdk.DefaultTimeout(30 * time.Minute), + }, + + Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { + _, err := parse.BgpConnectionID(id) + return err + }), + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "route_server_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.VirtualHubID, + }, + + "peer_asn": { + Type: pluginsdk.TypeInt, + Required: true, + ForceNew: true, + ValidateFunc: validation.IntAtLeast(0), + }, + + "peer_ip": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.IsIPv4Address, + }, + }, + } +} + +func resourceRouteServerBgpConnectionCreate(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Network.VirtualHubBgpConnectionClient + ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) + defer cancel() + + routerServerId, err := parse.VirtualHubID(d.Get("route_server_id").(string)) + if err != nil { + return err + } + + locks.ByName(routerServerId.Name, "azurerm_route_server") + defer locks.UnlockByName(routerServerId.Name, "azurerm_route_server") + + id := parse.NewBgpConnectionID(routerServerId.SubscriptionId, routerServerId.ResourceGroup, routerServerId.Name, d.Get("name").(string)) + + if d.IsNewResource() { + existing, err := client.Get(ctx, id.ResourceGroup, id.VirtualHubName, id.Name) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("checking for presence of existing %s: %+v", id, err) + } + } + + if !utils.ResponseWasNotFound(existing.Response) { + return tf.ImportAsExistsError("azurerm_route_server_bgp_connection", id.ID()) + } + } + parameters := network.BgpConnection{ + Name: utils.String(d.Get("name").(string)), + BgpConnectionProperties: &network.BgpConnectionProperties{ + PeerAsn: utils.Int64(int64(d.Get("peer_asn").(int))), + PeerIP: utils.String(d.Get("peer_ip").(string)), + }, + } + + future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.VirtualHubName, id.Name, parameters) + if err != nil { + return fmt.Errorf("creating/updating %s: %+v", id, err) + } + + if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting on creation/update future for %s: %+v", id, err) + } + + d.SetId(id.ID()) + return resourceRouteServerBgpConnectionRead(d, meta) +} + +func resourceRouteServerBgpConnectionRead(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Network.VirtualHubBgpConnectionClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.BgpConnectionID(d.Id()) + if err != nil { + return err + } + + resp, err := client.Get(ctx, id.ResourceGroup, id.VirtualHubName, id.Name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[INFO] BGP Connection %s does not exists", id) + d.SetId("") + return nil + } + + return fmt.Errorf("retrieving Route Server BGP Connection %s: %+v", id, err) + } + + d.Set("name", id.Name) + d.Set("route_server_id", parse.NewVirtualHubID(id.SubscriptionId, id.ResourceGroup, id.VirtualHubName).ID()) + + if props := resp.BgpConnectionProperties; props != nil { + if props.PeerAsn != nil { + d.Set("peer_asn", props.PeerAsn) + } + if props.PeerIP != nil { + d.Set("peer_ip", props.PeerIP) + } + } + return nil +} + +func resourceRouteServerBgpConnectionDelete(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Network.VirtualHubBgpConnectionClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.BgpConnectionID(d.Id()) + if err != nil { + return err + } + + future, err := client.Delete(ctx, id.ResourceGroup, id.VirtualHubName, id.Name) + if err != nil { + return fmt.Errorf("deleting BGP Connection %s: %+v", id, err) + } + if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting on deletion future for BGP Connection %s: %+v", id, err) + } + return nil +} diff --git a/internal/services/network/route_server_bgp_connection_resource_test.go b/internal/services/network/route_server_bgp_connection_resource_test.go new file mode 100644 index 000000000000..d65b0343378f --- /dev/null +++ b/internal/services/network/route_server_bgp_connection_resource_test.go @@ -0,0 +1,83 @@ +package network_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type RouteServerBGPConnectionResource struct{} + +func TestAccRouteServerBgpConnection_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_route_server_bgp_connection", "test") + r := RouteServerBGPConnectionResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r)), + }, + data.ImportStep(), + }) +} + +func TestAccRouteServerBgpConnection_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_route_server_bgp_connection", "test") + r := RouteServerBGPConnectionResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r)), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func (r RouteServerBGPConnectionResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + id, err := parse.BgpConnectionID(state.ID) + if err != nil { + return nil, err + } + + resp, err := clients.Network.VirtualHubBgpConnectionClient.Get(ctx, id.ResourceGroup, id.VirtualHubName, id.Name) + if err != nil { + return nil, fmt.Errorf("reading route server bgp connection %s: %+v", id, err) + } + return utils.Bool(resp.ID != nil), nil +} + +func (r RouteServerBGPConnectionResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_route_server_bgp_connection" "test" { + name = "acctest-rs-bgp-%d" + route_server_id = azurerm_route_server.test.id + peer_asn = 65501 + peer_ip = "169.254.21.5" + +} +`, RouteServerResource{}.basic(data), data.RandomInteger) +} + +func (r RouteServerBGPConnectionResource) requiresImport(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_route_server_bgp_connection" "import" { + name = azurerm_route_server_bgp_connection.test.name + route_server_id = azurerm_route_server_bgp_connection.test.route_server_id + peer_asn = azurerm_route_server_bgp_connection.test.peer_asn + peer_ip = azurerm_route_server_bgp_connection.test.peer_ip +} +`, r.basic(data)) +} diff --git a/internal/services/network/route_server_resource.go b/internal/services/network/route_server_resource.go new file mode 100644 index 000000000000..01dd1855cb87 --- /dev/null +++ b/internal/services/network/route_server_resource.go @@ -0,0 +1,343 @@ +package network + +import ( + "context" + "fmt" + "log" + "strconv" + "time" + + "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2021-08-01/network" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" + "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/locks" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/validate" + "github.com/hashicorp/terraform-provider-azurerm/internal/tags" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +func resourceRouteServer() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Create: resourceRouteServerCreateUpdate, + Read: resourceRouteServerRead, + Update: resourceRouteServerCreateUpdate, + Delete: resourceRouteServerDelete, + Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { + _, err := parse.VirtualHubID(id) + return err + }), + + Timeouts: &pluginsdk.ResourceTimeout{ + Create: pluginsdk.DefaultTimeout(60 * time.Minute), + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + Update: pluginsdk.DefaultTimeout(60 * time.Minute), + Delete: pluginsdk.DefaultTimeout(60 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.RouteServerName(), + }, + + "resource_group_name": commonschema.ResourceGroupName(), + + "location": commonschema.Location(), + + "sku": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{"Standard"}, false), + }, + + "public_ip_address_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.PublicIpAddressID, + }, + + "subnet_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.SubnetID, + }, + + "branch_to_branch_traffic_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: false, + }, + + "virtual_router_ips": { + Type: pluginsdk.TypeSet, + Computed: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + }, + }, + + "routing_state": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "virtual_router_asn": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "tags": commonschema.Tags(), + }, + } +} + +func resourceRouteServerCreateUpdate(d *pluginsdk.ResourceData, meta interface{}) error { + serverClient := meta.(*clients.Client).Network.VirtualHubClient + ipClient := meta.(*clients.Client).Network.VirtualHubIPClient + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + + id := parse.NewVirtualHubID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) + + locks.ByName(id.Name, "azurerm_route_server") + defer locks.UnlockByName(id.Name, "azurerm_route_server") + + if d.IsNewResource() { + existing, err := serverClient.Get(ctx, id.ResourceGroup, id.Name) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("checking for present of existing Route Server %q (Resource Group Name %q): %+v", id.Name, id.ResourceGroup, err) + } + } + if !utils.ResponseWasNotFound(existing.Response) { + return tf.ImportAsExistsError("azurerm_route_server", id.ID()) + } + } + + location := location.Normalize(d.Get("location").(string)) + t := tags.Expand(d.Get("tags").(map[string]interface{})) + + parameters := network.VirtualHub{ + Location: utils.String(location), + VirtualHubProperties: &network.VirtualHubProperties{ + Sku: utils.String(d.Get("sku").(string)), + AllowBranchToBranchTraffic: utils.Bool(d.Get("branch_to_branch_traffic_enabled").(bool)), + }, + Tags: t, + } + + if _, err := serverClient.CreateOrUpdate(ctx, id.ResourceGroup, id.Name, parameters); err != nil { + return fmt.Errorf("creating Route Server %q (Resource Group Name %q): %+v", id.Name, id.ResourceGroup, err) + } + + timeout, _ := ctx.Deadline() + stateConf := &pluginsdk.StateChangeConf{ + Pending: []string{"Provisioning", "Updating"}, + Target: []string{"Succeeded", "Provisioned"}, + Refresh: routeServerCreateRefreshFunc(ctx, serverClient, id), + PollInterval: 15 * time.Second, + ContinuousTargetOccurence: 5, + Timeout: time.Until(timeout), + } + _, err := stateConf.WaitForStateContext(ctx) + if err != nil { + return fmt.Errorf("waiting for creation/update of Route Server %q (Resource Group Name %q): %+v", id.Name, id.ResourceGroup, err) + } + + ipConfigName := "ipConfig1" + ipConfigs := network.HubIPConfiguration{ + Name: utils.String(ipConfigName), + HubIPConfigurationPropertiesFormat: &network.HubIPConfigurationPropertiesFormat{ + PublicIPAddress: &network.PublicIPAddress{ + ID: utils.String(d.Get("public_ip_address_id").(string)), + }, + Subnet: &network.Subnet{ + ID: utils.String(d.Get("subnet_id").(string)), + }, + }, + } + + future, err := ipClient.CreateOrUpdate(ctx, id.ResourceGroup, id.Name, ipConfigName, ipConfigs) + if err != nil { + return fmt.Errorf("creating/updating IP Configuration %q of Route Server %q (Resource Group Name %q): %+v", ipConfigName, id.Name, id.ResourceGroup, err) + } + + if err = future.WaitForCompletionRef(ctx, ipClient.Client); err != nil { + return fmt.Errorf("waiting on creation/update for IP Configuration %q of Route Server %q (Resource Group Name %q): %+v", ipConfigName, id.Name, id.ResourceGroup, err) + } + d.SetId(id.ID()) + + return resourceRouteServerRead(d, meta) +} + +func resourceRouteServerRead(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Network.VirtualHubClient + ipClient := meta.(*clients.Client).Network.VirtualHubIPClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.VirtualHubID(d.Id()) + if err != nil { + return err + } + + routeServer, err := client.Get(ctx, id.ResourceGroup, id.Name) + if err != nil { + if utils.ResponseWasNotFound(routeServer.Response) { + log.Printf("[INFO] Route Server %s does not exists - removing from state", d.Id()) + d.SetId("") + return nil + } + return fmt.Errorf("reading Route Server %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + } + + d.Set("name", id.Name) + d.Set("resource_group_name", id.ResourceGroup) + if location := routeServer.Location; location != nil { + d.Set("location", azure.NormalizeLocation(*location)) + } + if props := routeServer.VirtualHubProperties; props != nil { + d.Set("sku", props.Sku) + var virtualRouterIps *[]string + if props.VirtualRouterIps != nil { + virtualRouterIps = props.VirtualRouterIps + } + d.Set("virtual_router_ips", virtualRouterIps) + if props.AllowBranchToBranchTraffic != nil { + d.Set("branch_to_branch_traffic_enabled", props.AllowBranchToBranchTraffic) + } + if props.VirtualRouterAsn != nil { + d.Set("virtual_router_asn", props.VirtualRouterAsn) + } + d.Set("routing_state", string(props.RoutingState)) + } + + ipConfig, err := ipClient.List(ctx, id.ResourceGroup, id.Name) + if err != nil { + return fmt.Errorf("retrieving IP Config for Router Server %q (Resource Group Name %q): %+v", id.Name, id.ResourceGroup, err) + } + + for _, setting := range ipConfig.Values() { + if ipProps := setting.HubIPConfigurationPropertiesFormat; ipProps != nil { + if ipProps.PublicIPAddress != nil { + d.Set("public_ip_address_id", ipProps.PublicIPAddress.ID) + } + if ipProps.Subnet != nil { + d.Set("subnet_id", ipProps.Subnet.ID) + } + } + } + return tags.FlattenAndSet(d, routeServer.Tags) +} + +func resourceRouteServerDelete(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Network.VirtualHubClient + ipClient := meta.(*clients.Client).Network.VirtualHubIPClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + routeServerId, err := parse.VirtualHubID(d.Id()) + if err != nil { + return err + } + + ipConfig, err := ipClient.List(ctx, routeServerId.ResourceGroup, routeServerId.Name) + if err != nil { + return fmt.Errorf("retrieving IP Config for Router Server %q (Resource Group Name %q): %+v", routeServerId.Name, routeServerId.ResourceGroup, err) + } + var ipName string + for _, setting := range ipConfig.Values() { + if setting.Name != nil { + ipName = *setting.Name + } + } + ipConfigId := parse.NewVirtualHubIpConfigurationID(routeServerId.SubscriptionId, routeServerId.ResourceGroup, routeServerId.Name, ipName) + + if ipConfig.Values() != nil { + if err := deleteRouteServerIpConfiguration(ctx, ipClient, ipConfigId); err != nil { + return err + } + } + + future, err := client.Delete(ctx, routeServerId.ResourceGroup, routeServerId.Name) + if err != nil { + return fmt.Errorf("deleting Route Server %q (Resource Group Name %q): %+v", routeServerId.Name, routeServerId.ResourceGroup, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + if !response.WasNotFound(future.Response()) { + return fmt.Errorf("waiting for Route Server %q (Resource Group Name %q): %+v", routeServerId.Name, routeServerId.ResourceGroup, err) + } + } + + return nil +} + +func deleteRouteServerIpConfiguration(ctx context.Context, client *network.VirtualHubIPConfigurationClient, id parse.VirtualHubIpConfigurationId) error { + future, err := client.Delete(ctx, id.ResourceGroup, id.VirtualHubName, id.IpConfigurationName) + if err != nil { + return fmt.Errorf("deleting Router Server IP Config %s for Route Server %q (Resource Group Name %q): %+v", id.IpConfigurationName, id.VirtualHubName, id.ResourceGroup, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + if !response.WasNotFound(future.Response()) { + return fmt.Errorf("waiting for deletion of Route Server IP Config %s: %+v", id.IpConfigurationName, err) + } + } + timeout, _ := ctx.Deadline() + stateConf := &pluginsdk.StateChangeConf{ + Pending: []string{"200"}, + Target: []string{"404"}, + Refresh: ipConfigStateRefreshFunc(ctx, client, id), + Timeout: time.Until(timeout), + } + + if _, err := stateConf.WaitForStateContext(ctx); err != nil { + return fmt.Errorf("waiting for Router Server IP Config %s for Route Server %q (Resource Group Name %q): %+v", id.IpConfigurationName, id.VirtualHubName, id.ResourceGroup, err) + } + return nil +} + +func routeServerCreateRefreshFunc(ctx context.Context, client *network.VirtualHubsClient, id parse.VirtualHubId) pluginsdk.StateRefreshFunc { + return func() (interface{}, string, error) { + res, err := client.Get(ctx, id.ResourceGroup, id.Name) + if err != nil { + if utils.ResponseWasNotFound(res.Response) { + return nil, "", fmt.Errorf("Route Server %q (Resource Group Name %q) does not exists", id.Name, id.ResourceGroup) + } + return nil, "", fmt.Errorf("retrieving Route Server %q (Resource Group Name %q) error", id.Name, id.ResourceGroup) + } + + if res.VirtualHubProperties != nil { + return res, string(res.VirtualHubProperties.ProvisioningState), nil + } + return nil, "", fmt.Errorf("unable to read the provisioning state of this Route Server %q (Resource Group Name %q)", id.Name, id.ResourceGroup) + } +} + +func ipConfigStateRefreshFunc(ctx context.Context, client *network.VirtualHubIPConfigurationClient, id parse.VirtualHubIpConfigurationId) pluginsdk.StateRefreshFunc { + return func() (interface{}, string, error) { + res, err := client.Get(ctx, id.ResourceGroup, id.VirtualHubName, id.IpConfigurationName) + if err != nil { + if utils.ResponseWasNotFound(res.Response) { + return res, strconv.Itoa(res.StatusCode), nil + } + return nil, "", fmt.Errorf("polling for the status of route server ip config %s: %+v", id, err) + } + return res, strconv.Itoa(res.StatusCode), nil + } +} diff --git a/internal/services/network/route_server_resource_test.go b/internal/services/network/route_server_resource_test.go new file mode 100644 index 000000000000..2ac78d7597e3 --- /dev/null +++ b/internal/services/network/route_server_resource_test.go @@ -0,0 +1,183 @@ +package network_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type RouteServerResource struct{} + +func TestAccRouteServer_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_route_server", "test") + r := RouteServerResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r)), + }, + data.ImportStep(), + }) +} + +func TestAccRouteServer_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_route_server", "test") + r := RouteServerResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r)), + }, + { + Config: r.requiresImport(data), + ExpectError: acceptance.RequiresImportError("azurerm_route_server"), + }, + }) +} + +func TestAccRouteServer_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_route_server", "test") + r := RouteServerResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r)), + }, + data.ImportStep(), + }) +} + +func TestAccRouteServer_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_route_server", "test") + r := RouteServerResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r)), + }, + data.ImportStep(), + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r)), + }, + data.ImportStep(), + }) +} +func (r RouteServerResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + routeServerId, err := parse.VirtualHubID(state.ID) + if err != nil { + return nil, err + } + + resp, err := clients.Network.VirtualHubClient.Get(ctx, routeServerId.ResourceGroup, routeServerId.Name) + if err != nil { + return nil, fmt.Errorf("reading Route Server %s: %+v", routeServerId, err) + } + + ipConfig, err := clients.Network.VirtualHubIPClient.List(ctx, routeServerId.ResourceGroup, routeServerId.Name) + if err != nil { + return nil, fmt.Errorf("retrieving Ip Config for Route Server %s: %+v", routeServerId, err) + } + if ipConfig.Values() == nil { + return nil, fmt.Errorf("no IP Config is set for the Route Server %s: %+v", routeServerId, err) + } + + return utils.Bool(resp.ID != nil), nil +} + +func (r RouteServerResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_route_server" "test" { + name = "acctestrs-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + sku = "Standard" + public_ip_address_id = azurerm_public_ip.test.id + subnet_id = azurerm_subnet.test.id +} +`, r.template(data), data.RandomInteger) +} + +func (r RouteServerResource) requiresImport(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_route_server" "import" { + name = azurerm_route_server.test.name + resource_group_name = azurerm_route_server.test.resource_group_name + location = azurerm_route_server.test.location + sku = azurerm_route_server.test.sku + public_ip_address_id = azurerm_route_server.test.public_ip_address_id + subnet_id = azurerm_route_server.test.subnet_id +} +`, r.basic(data)) +} + +func (r RouteServerResource) complete(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_route_server" "test" { + name = "acctestrs-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + sku = "Standard" + public_ip_address_id = azurerm_public_ip.test.id + subnet_id = azurerm_subnet.test.id + branch_to_branch_traffic_enabled = true +} +`, r.template(data), data.RandomInteger) +} + +func (r RouteServerResource) template(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_virtual_network" "test" { + name = "acctestvn-%d" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_subnet" "test" { + name = "RouteServerSubnet" + virtual_network_name = azurerm_virtual_network.test.name + resource_group_name = azurerm_resource_group.test.name + address_prefixes = ["10.0.0.0/24"] +} + +resource "azurerm_public_ip" "test" { + name = "acctestpip-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + allocation_method = "Static" + sku = "Standard" +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} diff --git a/internal/services/network/subnet_data_source.go b/internal/services/network/subnet_data_source.go index 09fc30a119bc..41dfe63549d3 100644 --- a/internal/services/network/subnet_data_source.go +++ b/internal/services/network/subnet_data_source.go @@ -6,6 +6,7 @@ import ( "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/features" "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" @@ -14,7 +15,7 @@ import ( ) func dataSourceSubnet() *pluginsdk.Resource { - return &pluginsdk.Resource{ + resource := &pluginsdk.Resource{ Read: dataSourceSubnetRead, Timeouts: &pluginsdk.ResourceTimeout{ @@ -64,18 +65,31 @@ func dataSourceSubnet() *pluginsdk.Resource { Type: pluginsdk.TypeString, }, }, - - "enforce_private_link_endpoint_network_policies": { + "private_endpoint_network_policies_enabled": { Type: pluginsdk.TypeBool, Computed: true, }, - "enforce_private_link_service_network_policies": { + "private_link_service_network_policies_enabled": { Type: pluginsdk.TypeBool, Computed: true, }, }, } + + if !features.FourPointOhBeta() { + resource.Schema["enforce_private_link_endpoint_network_policies"] = &pluginsdk.Schema{ + Type: pluginsdk.TypeBool, + Computed: true, + } + + resource.Schema["enforce_private_link_service_network_policies"] = &pluginsdk.Schema{ + Type: pluginsdk.TypeBool, + Computed: true, + } + } + + return resource } func dataSourceSubnetRead(d *pluginsdk.ResourceData, meta interface{}) error { @@ -88,7 +102,7 @@ func dataSourceSubnetRead(d *pluginsdk.ResourceData, meta interface{}) error { resp, err := client.Get(ctx, id.ResourceGroup, id.VirtualNetworkName, id.Name, "") if err != nil { if utils.ResponseWasNotFound(resp.Response) { - return fmt.Errorf("Error: %s was not found", id) + return fmt.Errorf("%s was not found", id) } return fmt.Errorf("retrieving %s: %+v", id, err) } @@ -110,8 +124,13 @@ func dataSourceSubnetRead(d *pluginsdk.ResourceData, meta interface{}) error { d.Set("address_prefixes", utils.FlattenStringSlice(props.AddressPrefixes)) } - d.Set("enforce_private_link_endpoint_network_policies", flattenSubnetPrivateLinkNetworkPolicy(string(props.PrivateEndpointNetworkPolicies))) - d.Set("enforce_private_link_service_network_policies", flattenSubnetPrivateLinkNetworkPolicy(string(props.PrivateLinkServiceNetworkPolicies))) + if !features.FourPointOhBeta() { + d.Set("enforce_private_link_endpoint_network_policies", flattenEnforceSubnetNetworkPolicy(string(props.PrivateEndpointNetworkPolicies))) + d.Set("enforce_private_link_service_network_policies", flattenEnforceSubnetNetworkPolicy(string(props.PrivateLinkServiceNetworkPolicies))) + } + + d.Set("private_endpoint_network_policies_enabled", flattenSubnetNetworkPolicy(string(props.PrivateEndpointNetworkPolicies))) + d.Set("private_link_service_network_policies_enabled", flattenSubnetNetworkPolicy(string(props.PrivateLinkServiceNetworkPolicies))) networkSecurityGroupId := "" if props.NetworkSecurityGroup != nil && props.NetworkSecurityGroup.ID != nil { diff --git a/internal/services/network/subnet_resource.go b/internal/services/network/subnet_resource.go index 4b59b47d7608..634857b0f371 100644 --- a/internal/services/network/subnet_resource.go +++ b/internal/services/network/subnet_resource.go @@ -12,6 +12,7 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/features" "github.com/hashicorp/terraform-provider-azurerm/internal/locks" "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/validate" @@ -24,7 +25,7 @@ import ( var SubnetResourceName = "azurerm_subnet" func resourceSubnet() *pluginsdk.Resource { - return &pluginsdk.Resource{ + resource := &pluginsdk.Resource{ Create: resourceSubnetCreate, Read: resourceSubnetRead, Update: resourceSubnetUpdate, @@ -131,6 +132,9 @@ func resourceSubnet() *pluginsdk.Resource { "Microsoft.Synapse/workspaces", "Microsoft.Web/hostingEnvironments", "Microsoft.Web/serverFarms", + "Microsoft.Orbital/orbitalGateways", + "NGINX.NGINXPLUS/nginxDeployments", + "PaloAltoNetworks.Cloudngfw/firewalls", }, false), }, @@ -157,19 +161,67 @@ func resourceSubnet() *pluginsdk.Resource { }, }, - "enforce_private_link_endpoint_network_policies": { - Type: pluginsdk.TypeBool, + "private_endpoint_network_policies_enabled": { + Type: pluginsdk.TypeBool, + Computed: func() bool { + return !features.FourPointOh() + }(), Optional: true, - Default: false, + Default: func() interface{} { + if !features.FourPointOh() { + return nil + } + return !features.FourPointOh() + }(), + ConflictsWith: func() []string { + if !features.FourPointOh() { + return []string{"enforce_private_link_endpoint_network_policies"} + } + return []string{} + }(), }, - "enforce_private_link_service_network_policies": { - Type: pluginsdk.TypeBool, + "private_link_service_network_policies_enabled": { + Type: pluginsdk.TypeBool, + Computed: func() bool { + return !features.FourPointOh() + }(), Optional: true, - Default: false, + Default: func() interface{} { + if !features.FourPointOh() { + return nil + } + return features.FourPointOh() + }(), + ConflictsWith: func() []string { + if !features.FourPointOh() { + return []string{"enforce_private_link_service_network_policies"} + } + return []string{} + }(), }, }, } + + if !features.FourPointOhBeta() { + resource.Schema["enforce_private_link_endpoint_network_policies"] = &pluginsdk.Schema{ + Type: pluginsdk.TypeBool, + Computed: true, + Optional: true, + Deprecated: "`enforce_private_link_endpoint_network_policies` will be removed in favour of the property `private_endpoint_network_policies_enabled` in version 4.0 of the AzureRM Provider", + ConflictsWith: []string{"private_endpoint_network_policies_enabled"}, + } + + resource.Schema["enforce_private_link_service_network_policies"] = &pluginsdk.Schema{ + Type: pluginsdk.TypeBool, + Computed: true, + Optional: true, + Deprecated: "`enforce_private_link_service_network_policies` will be removed in favour of the property `private_link_service_network_policies_enabled` in version 4.0 of the AzureRM Provider", + ConflictsWith: []string{"private_link_service_network_policies_enabled"}, + } + } + + return resource } // TODO: refactor the create/flatten functions @@ -212,10 +264,72 @@ func resourceSubnetCreate(d *pluginsdk.ResourceData, meta interface{}) error { // To enable private endpoints you must disable the network policies for the subnet because // Network policies like network security groups are not supported by private endpoints. - privateEndpointNetworkPolicies := d.Get("enforce_private_link_endpoint_network_policies").(bool) - privateLinkServiceNetworkPolicies := d.Get("enforce_private_link_service_network_policies").(bool) - properties.PrivateEndpointNetworkPolicies = network.VirtualNetworkPrivateEndpointNetworkPolicies(expandSubnetPrivateLinkNetworkPolicy(privateEndpointNetworkPolicies)) - properties.PrivateLinkServiceNetworkPolicies = network.VirtualNetworkPrivateLinkServiceNetworkPolicies(expandSubnetPrivateLinkNetworkPolicy(privateLinkServiceNetworkPolicies)) + var privateEndpointNetworkPolicies network.VirtualNetworkPrivateEndpointNetworkPolicies + var privateLinkServiceNetworkPolicies network.VirtualNetworkPrivateLinkServiceNetworkPolicies + + if features.FourPointOhBeta() { + privateEndpointNetworkPoliciesRaw := d.Get("private_endpoint_network_policies_enabled").(bool) + privateLinkServiceNetworkPoliciesRaw := d.Get("private_link_service_network_policies_enabled").(bool) + + privateEndpointNetworkPolicies = network.VirtualNetworkPrivateEndpointNetworkPolicies(expandSubnetNetworkPolicy(privateEndpointNetworkPoliciesRaw)) + privateLinkServiceNetworkPolicies = network.VirtualNetworkPrivateLinkServiceNetworkPolicies(expandSubnetNetworkPolicy(privateLinkServiceNetworkPoliciesRaw)) + } else { + var enforceOk bool + var enforceServiceOk bool + var enableOk bool + var enableServiceOk bool + var enforcePrivateEndpointNetworkPoliciesRaw bool + var enforcePrivateLinkServiceNetworkPoliciesRaw bool + var privateEndpointNetworkPoliciesRaw bool + var privateLinkServiceNetworkPoliciesRaw bool + + // Set the legacy default value since they are now computed optional + privateEndpointNetworkPolicies = network.VirtualNetworkPrivateEndpointNetworkPoliciesEnabled + privateLinkServiceNetworkPolicies = network.VirtualNetworkPrivateLinkServiceNetworkPoliciesEnabled + + // This is the only way I was able to figure out if the fields are actually in the config or not, + // which is needed here because these are all now optional computed fields... + if !pluginsdk.IsExplicitlyNullInConfig(d, "enforce_private_link_endpoint_network_policies") { + enforceOk = true + enforcePrivateEndpointNetworkPoliciesRaw = d.Get("enforce_private_link_endpoint_network_policies").(bool) + } + + if !pluginsdk.IsExplicitlyNullInConfig(d, "enforce_private_link_service_network_policies") { + enforceServiceOk = true + enforcePrivateLinkServiceNetworkPoliciesRaw = d.Get("enforce_private_link_service_network_policies").(bool) + } + + if !pluginsdk.IsExplicitlyNullInConfig(d, "private_endpoint_network_policies_enabled") { + enableOk = true + privateEndpointNetworkPoliciesRaw = d.Get("private_endpoint_network_policies_enabled").(bool) + } + + if !pluginsdk.IsExplicitlyNullInConfig(d, "private_link_service_network_policies_enabled") { + enableServiceOk = true + privateLinkServiceNetworkPoliciesRaw = d.Get("private_link_service_network_policies_enabled").(bool) + } + + // Only one of these values can be set since they conflict with each other + // if neither of them are set use the default values + if enforceOk || enableOk { + if enforceOk { + privateEndpointNetworkPolicies = network.VirtualNetworkPrivateEndpointNetworkPolicies(expandEnforceSubnetNetworkPolicy(enforcePrivateEndpointNetworkPoliciesRaw)) + } else if enableOk { + privateEndpointNetworkPolicies = network.VirtualNetworkPrivateEndpointNetworkPolicies(expandSubnetNetworkPolicy(privateEndpointNetworkPoliciesRaw)) + } + } + + if enforceServiceOk || enableServiceOk { + if enforceServiceOk { + privateLinkServiceNetworkPolicies = network.VirtualNetworkPrivateLinkServiceNetworkPolicies(expandEnforceSubnetNetworkPolicy(enforcePrivateLinkServiceNetworkPoliciesRaw)) + } else if enableServiceOk { + privateLinkServiceNetworkPolicies = network.VirtualNetworkPrivateLinkServiceNetworkPolicies(expandSubnetNetworkPolicy(privateLinkServiceNetworkPoliciesRaw)) + } + } + } + + properties.PrivateEndpointNetworkPolicies = privateEndpointNetworkPolicies + properties.PrivateLinkServiceNetworkPolicies = privateLinkServiceNetworkPolicies serviceEndpointPoliciesRaw := d.Get("service_endpoint_policy_ids").(*pluginsdk.Set).List() properties.ServiceEndpointPolicies = expandSubnetServiceEndpointPolicies(serviceEndpointPoliciesRaw) @@ -321,14 +435,50 @@ func resourceSubnetUpdate(d *pluginsdk.ResourceData, meta interface{}) error { props.Delegations = expandSubnetDelegation(delegationsRaw) } - if d.HasChange("enforce_private_link_endpoint_network_policies") { - v := d.Get("enforce_private_link_endpoint_network_policies").(bool) - props.PrivateEndpointNetworkPolicies = network.VirtualNetworkPrivateEndpointNetworkPolicies(expandSubnetPrivateLinkNetworkPolicy(v)) - } + if features.FourPointOhBeta() { + if d.HasChange("private_endpoint_network_policies_enabled") { + v := d.Get("private_endpoint_network_policies_enabled").(bool) + props.PrivateEndpointNetworkPolicies = network.VirtualNetworkPrivateEndpointNetworkPolicies(expandSubnetNetworkPolicy(v)) + } + + if d.HasChange("private_link_service_network_policies_enabled") { + v := d.Get("private_link_service_network_policies_enabled").(bool) + props.PrivateLinkServiceNetworkPolicies = network.VirtualNetworkPrivateLinkServiceNetworkPolicies(expandSubnetNetworkPolicy(v)) + } + } else { + // This is the best case we can do in this state since they are computed optional fields now + // If you remove the fields from the config they will just persist as they are, if you change + // one it will update it to the value that was changed and in the read the other value will be + // updated as well to reflect the new value so it is safe to toggle between which field you want + // to use to define this behavior... + var privateEndpointNetworkPolicies network.VirtualNetworkPrivateEndpointNetworkPolicies + var privateLinkServiceNetworkPolicies network.VirtualNetworkPrivateLinkServiceNetworkPolicies + + if d.HasChange("enforce_private_link_endpoint_network_policies") || d.HasChange("private_endpoint_network_policies_enabled") { + enforcePrivateEndpointNetworkPoliciesRaw := d.Get("enforce_private_link_endpoint_network_policies").(bool) + privateEndpointNetworkPoliciesRaw := d.Get("private_endpoint_network_policies_enabled").(bool) + + if d.HasChange("enforce_private_link_endpoint_network_policies") { + privateEndpointNetworkPolicies = network.VirtualNetworkPrivateEndpointNetworkPolicies(expandEnforceSubnetNetworkPolicy(enforcePrivateEndpointNetworkPoliciesRaw)) + } else if d.HasChange("private_endpoint_network_policies_enabled") { + privateEndpointNetworkPolicies = network.VirtualNetworkPrivateEndpointNetworkPolicies(expandSubnetNetworkPolicy(privateEndpointNetworkPoliciesRaw)) + } + + props.PrivateEndpointNetworkPolicies = privateEndpointNetworkPolicies + } - if d.HasChange("enforce_private_link_service_network_policies") { - v := d.Get("enforce_private_link_service_network_policies").(bool) - props.PrivateLinkServiceNetworkPolicies = network.VirtualNetworkPrivateLinkServiceNetworkPolicies(expandSubnetPrivateLinkNetworkPolicy(v)) + if d.HasChange("enforce_private_link_service_network_policies") || d.HasChange("private_link_service_network_policies_enabled") { + enforcePrivateLinkServiceNetworkPoliciesRaw := d.Get("enforce_private_link_service_network_policies").(bool) + privateLinkServiceNetworkPoliciesRaw := d.Get("private_link_service_network_policies_enabled").(bool) + + if d.HasChange("enforce_private_link_service_network_policies") { + privateLinkServiceNetworkPolicies = network.VirtualNetworkPrivateLinkServiceNetworkPolicies(expandEnforceSubnetNetworkPolicy(enforcePrivateLinkServiceNetworkPoliciesRaw)) + } else if d.HasChange("private_link_service_network_policies_enabled") { + privateLinkServiceNetworkPolicies = network.VirtualNetworkPrivateLinkServiceNetworkPolicies(expandSubnetNetworkPolicy(privateLinkServiceNetworkPoliciesRaw)) + } + + props.PrivateLinkServiceNetworkPolicies = privateLinkServiceNetworkPolicies + } } if d.HasChange("service_endpoints") { @@ -376,6 +526,7 @@ func resourceSubnetUpdate(d *pluginsdk.ResourceData, meta interface{}) error { MinTimeout: 1 * time.Minute, Timeout: time.Until(timeout), } + if _, err = vnetStateConf.WaitForStateContext(ctx); err != nil { return fmt.Errorf("waiting for provisioning state of virtual network for %s: %+v", id, err) } @@ -422,8 +573,13 @@ func resourceSubnetRead(d *pluginsdk.ResourceData, meta interface{}) error { return fmt.Errorf("flattening `delegation`: %+v", err) } - d.Set("enforce_private_link_endpoint_network_policies", flattenSubnetPrivateLinkNetworkPolicy(string(props.PrivateEndpointNetworkPolicies))) - d.Set("enforce_private_link_service_network_policies", flattenSubnetPrivateLinkNetworkPolicy(string(props.PrivateLinkServiceNetworkPolicies))) + if !features.FourPointOhBeta() { + d.Set("enforce_private_link_endpoint_network_policies", flattenEnforceSubnetNetworkPolicy(string(props.PrivateEndpointNetworkPolicies))) + d.Set("enforce_private_link_service_network_policies", flattenEnforceSubnetNetworkPolicy(string(props.PrivateLinkServiceNetworkPolicies))) + } + + d.Set("private_endpoint_network_policies_enabled", flattenSubnetNetworkPolicy(string(props.PrivateEndpointNetworkPolicies))) + d.Set("private_link_service_network_policies_enabled", flattenSubnetNetworkPolicy(string(props.PrivateLinkServiceNetworkPolicies))) serviceEndpoints := flattenSubnetServiceEndpoints(props.ServiceEndpoints) if err := d.Set("service_endpoints", serviceEndpoints); err != nil { @@ -566,24 +722,36 @@ func flattenSubnetDelegation(delegations *[]network.Delegation) []interface{} { return retDeles } -// TODO: confirm this logic below - -func expandSubnetPrivateLinkNetworkPolicy(enabled bool) string { +// TODO 4.0: Remove expandEnforceSubnetPrivateLinkNetworkPolicy function +func expandEnforceSubnetNetworkPolicy(enabled bool) string { // This is strange logic, but to get the schema to make sense for the end user // I exposed it with the same name that the Azure CLI does to be consistent // between the tool sets, which means true == Disabled. if enabled { - return "Disabled" + return string(network.VirtualNetworkPrivateEndpointNetworkPoliciesDisabled) + } + + return string(network.VirtualNetworkPrivateEndpointNetworkPoliciesEnabled) +} + +func expandSubnetNetworkPolicy(enabled bool) string { + if enabled { + return string(network.VirtualNetworkPrivateEndpointNetworkPoliciesEnabled) } - return "Enabled" + return string(network.VirtualNetworkPrivateEndpointNetworkPoliciesDisabled) } -func flattenSubnetPrivateLinkNetworkPolicy(input string) bool { +// TODO 4.0: Remove flattenEnforceSubnetPrivateLinkNetworkPolicy function +func flattenEnforceSubnetNetworkPolicy(input string) bool { // This is strange logic, but to get the schema to make sense for the end user // I exposed it with the same name that the Azure CLI does to be consistent // between the tool sets, which means true == Disabled. - return strings.EqualFold(input, "Disabled") + return strings.EqualFold(input, string(network.VirtualNetworkPrivateEndpointNetworkPoliciesDisabled)) +} + +func flattenSubnetNetworkPolicy(input string) bool { + return strings.EqualFold(input, string(network.VirtualNetworkPrivateEndpointNetworkPoliciesEnabled)) } func expandSubnetServiceEndpointPolicies(input []interface{}) *[]network.ServiceEndpointPolicy { diff --git a/internal/services/network/subnet_resource_test.go b/internal/services/network/subnet_resource_test.go index 234ca72420fa..14e6a773dec1 100644 --- a/internal/services/network/subnet_resource_test.go +++ b/internal/services/network/subnet_resource_test.go @@ -8,6 +8,7 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/features" "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" @@ -155,27 +156,27 @@ func TestAccSubnet_delegation(t *testing.T) { }) } -func TestAccSubnet_enforcePrivateLinkEndpointNetworkPolicies(t *testing.T) { +func TestAccSubnet_enablePrivateEndpointNetworkPolicies(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_subnet", "test") r := SubnetResource{} data.ResourceTest(t, r, []acceptance.TestStep{ { - Config: r.enforcePrivateLinkEndpointNetworkPolicies(data, true), + Config: r.enablePrivateEndpointNetworkPolicies(data, true), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), ), }, data.ImportStep(), { - Config: r.enforcePrivateLinkEndpointNetworkPolicies(data, false), + Config: r.enablePrivateEndpointNetworkPolicies(data, false), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), ), }, data.ImportStep(), { - Config: r.enforcePrivateLinkEndpointNetworkPolicies(data, true), + Config: r.enablePrivateEndpointNetworkPolicies(data, true), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), ), @@ -184,27 +185,27 @@ func TestAccSubnet_enforcePrivateLinkEndpointNetworkPolicies(t *testing.T) { }) } -func TestAccSubnet_enforcePrivateLinkServiceNetworkPolicies(t *testing.T) { +func TestAccSubnet_enablePrivateLinkServiceNetworkPolicies(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_subnet", "test") r := SubnetResource{} data.ResourceTest(t, r, []acceptance.TestStep{ { - Config: r.enforcePrivateLinkServiceNetworkPolicies(data, true), + Config: r.enablePrivateLinkServiceNetworkPolicies(data, true), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), ), }, data.ImportStep(), { - Config: r.enforcePrivateLinkServiceNetworkPolicies(data, false), + Config: r.enablePrivateLinkServiceNetworkPolicies(data, false), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), ), }, data.ImportStep(), { - Config: r.enforcePrivateLinkServiceNetworkPolicies(data, true), + Config: r.enablePrivateLinkServiceNetworkPolicies(data, true), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), ), @@ -213,6 +214,188 @@ func TestAccSubnet_enforcePrivateLinkServiceNetworkPolicies(t *testing.T) { }) } +// TODO 4.0: Remove test +func TestAccSubnet_enforcePrivateLinkEndpointNetworkPolicies(t *testing.T) { + if !features.FourPointOhBeta() { + data := acceptance.BuildTestData(t, "azurerm_subnet", "test") + r := SubnetResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.enforcePrivateLinkEndpointNetworkPolicies(data, true), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.enforcePrivateLinkEndpointNetworkPolicies(data, false), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.enforcePrivateLinkEndpointNetworkPolicies(data, true), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) + } else { + t.Skip("@WodansSon: skipping due to deprecation of the 'enforce_private_link_endpoint_network_policies' field in 4.0") + } +} + +// TODO 4.0: Remove test +func TestAccSubnet_enforcePrivateLinkServiceNetworkPolicies(t *testing.T) { + if !features.FourPointOhBeta() { + data := acceptance.BuildTestData(t, "azurerm_subnet", "test") + r := SubnetResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.enforcePrivateLinkServiceNetworkPolicies(data, true), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.enforcePrivateLinkServiceNetworkPolicies(data, false), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.enforcePrivateLinkServiceNetworkPolicies(data, true), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) + } else { + t.Skip("@WodansSon: skipping due to deprecation of the 'enforce_private_link_service_network_policies' field in 4.0") + } +} + +// TODO 4.0: Remove test +func TestAccSubnet_PrivateLinkPoliciesToggleWithEnforceFirst(t *testing.T) { + if !features.FourPointOhBeta() { + data := acceptance.BuildTestData(t, "azurerm_subnet", "test") + r := SubnetResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.enforcePrivateLinkEndpointNetworkPolicies(data, true), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("enforce_private_link_endpoint_network_policies").HasValue("true"), + check.That(data.ResourceName).Key("enforce_private_link_service_network_policies").HasValue("false"), + check.That(data.ResourceName).Key("private_endpoint_network_policies_enabled").HasValue("false"), + check.That(data.ResourceName).Key("private_link_service_network_policies_enabled").HasValue("true"), + ), + }, + data.ImportStep(), + { + Config: r.enablePrivateEndpointNetworkPolicies(data, true), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("enforce_private_link_endpoint_network_policies").HasValue("false"), + check.That(data.ResourceName).Key("enforce_private_link_service_network_policies").HasValue("false"), + check.That(data.ResourceName).Key("private_endpoint_network_policies_enabled").HasValue("true"), + check.That(data.ResourceName).Key("private_link_service_network_policies_enabled").HasValue("true"), + ), + }, + data.ImportStep(), + { + Config: r.enforcePrivateLinkServiceNetworkPolicies(data, true), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("enforce_private_link_endpoint_network_policies").HasValue("false"), + check.That(data.ResourceName).Key("enforce_private_link_service_network_policies").HasValue("true"), + check.That(data.ResourceName).Key("private_endpoint_network_policies_enabled").HasValue("true"), + check.That(data.ResourceName).Key("private_link_service_network_policies_enabled").HasValue("false"), + ), + }, + data.ImportStep(), + { + Config: r.enablePrivateLinkServiceNetworkPolicies(data, true), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("enforce_private_link_endpoint_network_policies").HasValue("false"), + check.That(data.ResourceName).Key("enforce_private_link_service_network_policies").HasValue("false"), + check.That(data.ResourceName).Key("private_endpoint_network_policies_enabled").HasValue("true"), + check.That(data.ResourceName).Key("private_link_service_network_policies_enabled").HasValue("true"), + ), + }, + data.ImportStep(), + }) + } else { + t.Skip("@WodansSon: skipping due to deprecation of the 'enforce_private_link_endpoint_network_policies' and 'enforce_private_link_service_network_policies' fields in 4.0") + } +} + +// TODO 4.0: Remove test +func TestAccSubnet_PrivateLinkPoliciesToggleWithEnabledFirst(t *testing.T) { + if !features.FourPointOhBeta() { + data := acceptance.BuildTestData(t, "azurerm_subnet", "test") + r := SubnetResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.enablePrivateEndpointNetworkPolicies(data, false), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("enforce_private_link_endpoint_network_policies").HasValue("true"), + check.That(data.ResourceName).Key("enforce_private_link_service_network_policies").HasValue("false"), + check.That(data.ResourceName).Key("private_endpoint_network_policies_enabled").HasValue("false"), + check.That(data.ResourceName).Key("private_link_service_network_policies_enabled").HasValue("true"), + ), + }, + data.ImportStep(), + { + Config: r.enforcePrivateLinkEndpointNetworkPolicies(data, false), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("enforce_private_link_endpoint_network_policies").HasValue("false"), + check.That(data.ResourceName).Key("enforce_private_link_service_network_policies").HasValue("false"), + check.That(data.ResourceName).Key("private_endpoint_network_policies_enabled").HasValue("true"), + check.That(data.ResourceName).Key("private_link_service_network_policies_enabled").HasValue("true"), + ), + }, + data.ImportStep(), + { + Config: r.enablePrivateLinkServiceNetworkPolicies(data, false), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("enforce_private_link_endpoint_network_policies").HasValue("false"), + check.That(data.ResourceName).Key("enforce_private_link_service_network_policies").HasValue("true"), + check.That(data.ResourceName).Key("private_endpoint_network_policies_enabled").HasValue("true"), + check.That(data.ResourceName).Key("private_link_service_network_policies_enabled").HasValue("false"), + ), + }, + data.ImportStep(), + { + Config: r.enforcePrivateLinkServiceNetworkPolicies(data, false), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("enforce_private_link_endpoint_network_policies").HasValue("false"), + check.That(data.ResourceName).Key("enforce_private_link_service_network_policies").HasValue("false"), + check.That(data.ResourceName).Key("private_endpoint_network_policies_enabled").HasValue("true"), + check.That(data.ResourceName).Key("private_link_service_network_policies_enabled").HasValue("true"), + ), + }, + data.ImportStep(), + }) + } else { + t.Skip("@WodansSon: skipping due to deprecation of the 'enforce_private_link_endpoint_network_policies' and 'enforce_private_link_service_network_policies' fields in 4.0") + } +} + func TestAccSubnet_serviceEndpoints(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_subnet", "test") r := SubnetResource{} @@ -300,6 +483,64 @@ func TestAccSubnet_updateAddressPrefix(t *testing.T) { }) } +func TestAccSubnet_privateLinkEndpointNetworkPoliciesValidateDefaultValues(t *testing.T) { + if features.FourPointOhBeta() { + data := acceptance.BuildTestData(t, "azurerm_subnet", "test") + r := SubnetResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.privateLinkEndpointNetworkPoliciesDefaults(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("private_endpoint_network_policies_enabled").HasValue("false"), + check.That(data.ResourceName).Key("private_link_service_network_policies_enabled").HasValue("true"), + ), + }, + data.ImportStep(), + }) + } else { + data := acceptance.BuildTestData(t, "azurerm_subnet", "test") + r := SubnetResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.privateLinkEndpointNetworkPoliciesDefaults(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("enforce_private_link_endpoint_network_policies").HasValue("false"), + check.That(data.ResourceName).Key("enforce_private_link_service_network_policies").HasValue("false"), + check.That(data.ResourceName).Key("private_endpoint_network_policies_enabled").HasValue("true"), + check.That(data.ResourceName).Key("private_link_service_network_policies_enabled").HasValue("true"), + ), + }, + data.ImportStep(), + }) + } +} + +func TestAccSubnet_updateServiceDelegation(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_subnet", "test") + r := SubnetResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.updateServiceDelegation(data, "NGINX.NGINXPLUS/nginxDeployments"), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.updateServiceDelegation(data, "PaloAltoNetworks.Cloudngfw/firewalls"), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func (t SubnetResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { id, err := parse.SubnetID(state.ID) if err != nil { @@ -481,6 +722,37 @@ resource "azurerm_subnet" "test" { `, r.template(data)) } +func (r SubnetResource) enablePrivateEndpointNetworkPolicies(data acceptance.TestData, enabled bool) string { + return fmt.Sprintf(` +%s + +resource "azurerm_subnet" "test" { + name = "internal" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.2.0/24"] + + private_endpoint_network_policies_enabled = %t +} +`, r.template(data), enabled) +} + +func (r SubnetResource) enablePrivateLinkServiceNetworkPolicies(data acceptance.TestData, enabled bool) string { + return fmt.Sprintf(` +%s + +resource "azurerm_subnet" "test" { + name = "internal" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.2.0/24"] + + private_link_service_network_policies_enabled = %t +} +`, r.template(data), enabled) +} + +// TODO 4.0: Remove test func (r SubnetResource) enforcePrivateLinkEndpointNetworkPolicies(data acceptance.TestData, enabled bool) string { return fmt.Sprintf(` %s @@ -496,6 +768,7 @@ resource "azurerm_subnet" "test" { `, r.template(data), enabled) } +// TODO 4.0: Remove test func (r SubnetResource) enforcePrivateLinkServiceNetworkPolicies(data acceptance.TestData, enabled bool) string { return fmt.Sprintf(` %s @@ -511,6 +784,19 @@ resource "azurerm_subnet" "test" { `, r.template(data), enabled) } +func (r SubnetResource) privateLinkEndpointNetworkPoliciesDefaults(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_subnet" "test" { + name = "internal" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.2.0/24"] +} +`, r.template(data)) +} + func (SubnetResource) basic_addressPrefixes(data acceptance.TestData) string { return fmt.Sprintf(` resource "azurerm_resource_group" "test" { @@ -663,6 +949,31 @@ resource "azurerm_subnet" "test" { `, r.template(data)) } +func (r SubnetResource) updateServiceDelegation(data acceptance.TestData, serviceName string) string { + return fmt.Sprintf(` +%s + +resource "azurerm_subnet" "test" { + name = "internal" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.2.0/24"] + + delegation { + name = "first" + + service_delegation { + name = "%s" + + actions = [ + "Microsoft.Network/virtualNetworks/subnets/join/action", + ] + } + } +} +`, r.template(data), serviceName) +} + func (SubnetResource) template(data acceptance.TestData) string { return fmt.Sprintf(` provider "azurerm" { diff --git a/internal/services/network/validate/route_server_name.go b/internal/services/network/validate/route_server_name.go new file mode 100644 index 000000000000..6a26e46ebcc6 --- /dev/null +++ b/internal/services/network/validate/route_server_name.go @@ -0,0 +1,19 @@ +package validate + +import ( + "regexp" + + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" +) + +func RouteServerName() pluginsdk.SchemaValidateFunc { + return validation.All( + validation.StringIsNotEmpty, + validation.StringLenBetween(1, 80), + validation.StringMatch( + regexp.MustCompile(`^[A-Za-z\d][A-Za-z\d.\-_]*[A-Za-z\d_]$`), + "The name must begin with a letter or number, end with a letter, number or underscore, and may contain only letters, numbers, underscores, periods, or hyphens.", + ), + ) +} diff --git a/internal/services/network/validate/virtual_machine_scale_set_public_ip_address_id.go b/internal/services/network/validate/virtual_machine_scale_set_public_ip_address_id.go new file mode 100644 index 000000000000..58a4f394a115 --- /dev/null +++ b/internal/services/network/validate/virtual_machine_scale_set_public_ip_address_id.go @@ -0,0 +1,23 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + + "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/parse" +) + +func VirtualMachineScaleSetPublicIPAddressID(input interface{}, key string) (warnings []string, errors []error) { + v, ok := input.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected %q to be a string", key)) + return + } + + if _, err := parse.VirtualMachineScaleSetPublicIPAddressID(v); err != nil { + errors = append(errors, err) + } + + return +} diff --git a/internal/services/network/validate/virtual_machine_scale_set_public_ip_address_id_test.go b/internal/services/network/validate/virtual_machine_scale_set_public_ip_address_id_test.go new file mode 100644 index 000000000000..047140c8e474 --- /dev/null +++ b/internal/services/network/validate/virtual_machine_scale_set_public_ip_address_id_test.go @@ -0,0 +1,124 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import "testing" + +func TestVirtualMachineScaleSetPublicIPAddressID(t *testing.T) { + cases := []struct { + Input string + Valid bool + }{ + + { + // empty + Input: "", + Valid: false, + }, + + { + // missing SubscriptionId + Input: "/", + Valid: false, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Valid: false, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Valid: false, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Valid: false, + }, + + { + // missing VirtualMachineScaleSetName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/", + Valid: false, + }, + + { + // missing value for VirtualMachineScaleSetName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/virtualMachineScaleSets/", + Valid: false, + }, + + { + // missing VirtualMachineName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/virtualMachineScaleSets/scaleSet1/", + Valid: false, + }, + + { + // missing value for VirtualMachineName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/virtualMachineScaleSets/scaleSet1/virtualMachines/", + Valid: false, + }, + + { + // missing NetworkInterfaceName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/virtualMachineScaleSets/scaleSet1/virtualMachines/virtualMachine1/", + Valid: false, + }, + + { + // missing value for NetworkInterfaceName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/virtualMachineScaleSets/scaleSet1/virtualMachines/virtualMachine1/networkInterfaces/", + Valid: false, + }, + + { + // missing IpConfigurationName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/virtualMachineScaleSets/scaleSet1/virtualMachines/virtualMachine1/networkInterfaces/networkInterface1/", + Valid: false, + }, + + { + // missing value for IpConfigurationName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/virtualMachineScaleSets/scaleSet1/virtualMachines/virtualMachine1/networkInterfaces/networkInterface1/ipConfigurations/", + Valid: false, + }, + + { + // missing PublicIPAddressName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/virtualMachineScaleSets/scaleSet1/virtualMachines/virtualMachine1/networkInterfaces/networkInterface1/ipConfigurations/ipConfiguration1/", + Valid: false, + }, + + { + // missing value for PublicIPAddressName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/virtualMachineScaleSets/scaleSet1/virtualMachines/virtualMachine1/networkInterfaces/networkInterface1/ipConfigurations/ipConfiguration1/publicIPAddresses/", + Valid: false, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/virtualMachineScaleSets/scaleSet1/virtualMachines/virtualMachine1/networkInterfaces/networkInterface1/ipConfigurations/ipConfiguration1/publicIPAddresses/publicIpAddress1", + Valid: true, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.COMPUTE/VIRTUALMACHINESCALESETS/SCALESET1/VIRTUALMACHINES/VIRTUALMACHINE1/NETWORKINTERFACES/NETWORKINTERFACE1/IPCONFIGURATIONS/IPCONFIGURATION1/PUBLICIPADDRESSES/PUBLICIPADDRESS1", + Valid: false, + }, + } + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.Input) + _, errors := VirtualMachineScaleSetPublicIPAddressID(tc.Input, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} diff --git a/internal/services/network/validate/web_application_firewall_policy.go b/internal/services/network/validate/web_application_firewall_policy.go index 56dfd253ab35..6606ca2d9623 100644 --- a/internal/services/network/validate/web_application_firewall_policy.go +++ b/internal/services/network/validate/web_application_firewall_policy.go @@ -44,3 +44,11 @@ var ValidateWebApplicationFirewallPolicyRuleSetType = validation.StringInSlice([ "OWASP", "Microsoft_BotManagerRuleSet", }, false) + +var ValidateWebApplicationFirewallPolicyExclusionRuleSetVersion = validation.StringInSlice([]string{ + "3.2", +}, false) + +var ValidateWebApplicationFirewallPolicyExclusionRuleSetType = validation.StringInSlice([]string{ + "OWASP", +}, false) diff --git a/internal/services/network/web_application_firewall_policy_resource.go b/internal/services/network/web_application_firewall_policy_resource.go index 610c741618ae..3ca900514a61 100644 --- a/internal/services/network/web_application_firewall_policy_resource.go +++ b/internal/services/network/web_application_firewall_policy_resource.go @@ -195,6 +195,47 @@ func resourceWebApplicationFirewallPolicy() *pluginsdk.Resource { string(network.OwaspCrsExclusionEntrySelectorMatchOperatorStartsWith), }, false), }, + "excluded_rule_set": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "type": { + Type: pluginsdk.TypeString, + Optional: true, + Default: "OWASP", + ValidateFunc: validate.ValidateWebApplicationFirewallPolicyExclusionRuleSetType, + }, + "version": { + Type: pluginsdk.TypeString, + Optional: true, + Default: "3.2", + ValidateFunc: validate.ValidateWebApplicationFirewallPolicyExclusionRuleSetVersion, + }, + "rule_group": { + Type: pluginsdk.TypeList, + Optional: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "rule_group_name": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validate.ValidateWebApplicationFirewallPolicyRuleGroupName, + }, + "excluded_rules": { + Type: pluginsdk.TypeList, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + }, + }, + }, + }, + }, + }, + }, + }, }, }, }, @@ -475,6 +516,62 @@ func expandWebApplicationFirewallPolicyManagedRulesDefinition(input []interface{ } } +func expandWebApplicationFirewallPolicyExclusionManagedRules(input []interface{}) *[]network.ExclusionManagedRule { + results := make([]network.ExclusionManagedRule, 0) + for _, item := range input { + ruleID := item.(string) + + result := network.ExclusionManagedRule{ + RuleID: utils.String(ruleID), + } + + results = append(results, result) + } + return &results +} + +func expandWebApplicationFirewallPolicyExclusionManagedRuleGroup(input []interface{}) *[]network.ExclusionManagedRuleGroup { + results := make([]network.ExclusionManagedRuleGroup, 0) + for _, item := range input { + v := item.(map[string]interface{}) + + ruleGroupName := v["rule_group_name"].(string) + + result := network.ExclusionManagedRuleGroup{ + RuleGroupName: utils.String(ruleGroupName), + } + + if excludedRules := v["excluded_rules"].([]interface{}); len(excludedRules) > 0 { + result.Rules = expandWebApplicationFirewallPolicyExclusionManagedRules(excludedRules) + } + + results = append(results, result) + } + return &results +} + +func expandWebApplicationFirewallPolicyExclusionManagedRuleSet(input []interface{}) *[]network.ExclusionManagedRuleSet { + results := make([]network.ExclusionManagedRuleSet, 0) + for _, item := range input { + v := item.(map[string]interface{}) + + ruleSetType := v["type"].(string) + ruleSetVersion := v["version"].(string) + ruleGroups := make([]interface{}, 0) + if value, exists := v["rule_group"]; exists { + ruleGroups = value.([]interface{}) + } + result := network.ExclusionManagedRuleSet{ + RuleSetType: utils.String(ruleSetType), + RuleSetVersion: utils.String(ruleSetVersion), + RuleGroups: expandWebApplicationFirewallPolicyExclusionManagedRuleGroup(ruleGroups), + } + + results = append(results, result) + } + return &results +} + func expandWebApplicationFirewallPolicyExclusions(input []interface{}) *[]network.OwaspCrsExclusionEntry { results := make([]network.OwaspCrsExclusionEntry, 0) for _, item := range input { @@ -483,11 +580,13 @@ func expandWebApplicationFirewallPolicyExclusions(input []interface{}) *[]networ matchVariable := v["match_variable"].(string) selectorMatchOperator := v["selector_match_operator"].(string) selector := v["selector"].(string) + exclusionManagedRuleSets := v["excluded_rule_set"].([]interface{}) result := network.OwaspCrsExclusionEntry{ - MatchVariable: network.OwaspCrsExclusionEntryMatchVariable(matchVariable), - SelectorMatchOperator: network.OwaspCrsExclusionEntrySelectorMatchOperator(selectorMatchOperator), - Selector: utils.String(selector), + MatchVariable: network.OwaspCrsExclusionEntryMatchVariable(matchVariable), + SelectorMatchOperator: network.OwaspCrsExclusionEntrySelectorMatchOperator(selectorMatchOperator), + Selector: utils.String(selector), + ExclusionManagedRuleSets: expandWebApplicationFirewallPolicyExclusionManagedRuleSet(exclusionManagedRuleSets), } results = append(results, result) @@ -653,6 +752,57 @@ func flattenWebApplicationFirewallPolicyManagedRulesDefinition(input *network.Ma return results } +func flattenWebApplicationFirewallPolicyExclusionManagedRules(input *[]network.ExclusionManagedRule) []string { + results := make([]string, 0) + if input == nil || len(*input) == 0 { + return results + } + + for _, item := range *input { + if item.RuleID != nil { + v := *item.RuleID + results = append(results, v) + } + } + + return results +} + +func flattenWebApplicationFirewallPolicyExclusionManagedRuleGroups(input *[]network.ExclusionManagedRuleGroup) []interface{} { + results := make([]interface{}, 0) + if input == nil { + return results + } + + for _, item := range *input { + v := make(map[string]interface{}) + + v["rule_group_name"] = item.RuleGroupName + v["excluded_rules"] = flattenWebApplicationFirewallPolicyExclusionManagedRules(item.Rules) + + results = append(results, v) + } + return results +} + +func flattenWebApplicationFirewallPolicyExclusionManagedRuleSets(input *[]network.ExclusionManagedRuleSet) []interface{} { + results := make([]interface{}, 0) + if input == nil { + return results + } + + for _, item := range *input { + v := make(map[string]interface{}) + + v["type"] = item.RuleSetType + v["version"] = item.RuleSetVersion + v["rule_group"] = flattenWebApplicationFirewallPolicyExclusionManagedRuleGroups(item.RuleGroups) + + results = append(results, v) + } + return results +} + func flattenWebApplicationFirewallPolicyExclusions(input *[]network.OwaspCrsExclusionEntry) []interface{} { results := make([]interface{}, 0) if input == nil { @@ -668,7 +818,9 @@ func flattenWebApplicationFirewallPolicyExclusions(input *[]network.OwaspCrsExcl if selector != nil { v["selector"] = *selector } + v["selector_match_operator"] = string(item.SelectorMatchOperator) + v["excluded_rule_set"] = flattenWebApplicationFirewallPolicyExclusionManagedRuleSets(item.ExclusionManagedRuleSets) results = append(results, v) } diff --git a/internal/services/network/web_application_firewall_policy_resource_test.go b/internal/services/network/web_application_firewall_policy_resource_test.go index 18b52b5aa307..b917bbe5f461 100644 --- a/internal/services/network/web_application_firewall_policy_resource_test.go +++ b/internal/services/network/web_application_firewall_policy_resource_test.go @@ -216,6 +216,28 @@ func TestAccWebApplicationFirewallPolicy_knownCVEs(t *testing.T) { }) } +func TestAccWebApplicationFirewallPolicy_excludedRules(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_web_application_firewall_policy", "test") + r := WebApplicationFirewallResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.excludedRules(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.updateExcludedRules(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func (t WebApplicationFirewallResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { id, err := parse.ApplicationGatewayWebApplicationFirewallPolicyID(state.ID) if err != nil { @@ -512,3 +534,225 @@ resource "azurerm_web_application_firewall_policy" "test" { } `, data.RandomInteger, data.Locations.Primary, data.RandomInteger) } + +func (WebApplicationFirewallResource) excludedRules(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_web_application_firewall_policy" "test" { + name = "acctestwafpolicy-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + + tags = { + env = "test" + } + + custom_rules { + name = "Rule1" + priority = 1 + rule_type = "MatchRule" + + match_conditions { + match_variables { + variable_name = "RemoteAddr" + } + + operator = "IPMatch" + negation_condition = false + match_values = ["192.168.1.0/24", "10.0.0.0/24"] + } + + action = "Block" + } + + custom_rules { + name = "Rule2" + priority = 2 + rule_type = "MatchRule" + + match_conditions { + match_variables { + variable_name = "RemoteAddr" + } + + operator = "IPMatch" + negation_condition = false + match_values = ["192.168.1.0/24"] + } + + match_conditions { + match_variables { + variable_name = "RequestHeaders" + selector = "UserAgent" + } + + operator = "Contains" + negation_condition = false + match_values = ["windows"] + transforms = ["Lowercase"] + } + + action = "Block" + } + + managed_rules { + exclusion { + match_variable = "RequestHeaderNames" + selector = "x-shared-secret" + selector_match_operator = "Equals" + + excluded_rule_set { + rule_group { + rule_group_name = "REQUEST-920-PROTOCOL-ENFORCEMENT" + excluded_rules = [ + "920100", + "920120", + ] + } + } + } + + managed_rule_set { + type = "OWASP" + version = "3.2" + + rule_group_override { + rule_group_name = "REQUEST-920-PROTOCOL-ENFORCEMENT" + disabled_rules = [ + "920300", + "920440", + ] + } + } + } + + policy_settings { + enabled = true + mode = "Prevention" + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger) +} + +func (WebApplicationFirewallResource) updateExcludedRules(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_web_application_firewall_policy" "test" { + name = "acctestwafpolicy-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + + tags = { + env = "test" + } + + custom_rules { + name = "Rule1" + priority = 1 + rule_type = "MatchRule" + + match_conditions { + match_variables { + variable_name = "RemoteAddr" + } + + operator = "IPMatch" + negation_condition = false + match_values = ["192.168.1.0/24", "10.0.0.0/24"] + } + + action = "Block" + } + + custom_rules { + name = "Rule2" + priority = 2 + rule_type = "MatchRule" + + match_conditions { + match_variables { + variable_name = "RemoteAddr" + } + + operator = "IPMatch" + negation_condition = false + match_values = ["192.168.1.0/24"] + } + + match_conditions { + match_variables { + variable_name = "RequestHeaders" + selector = "UserAgent" + } + + operator = "Contains" + negation_condition = false + match_values = ["windows"] + transforms = ["Lowercase"] + } + + action = "Block" + } + + managed_rules { + exclusion { + match_variable = "RequestHeaderNames" + selector = "x-shared-secret" + selector_match_operator = "Equals" + + excluded_rule_set { + rule_group { + rule_group_name = "REQUEST-913-SCANNER-DETECTION" + excluded_rules = [ + "913100", + "913101", + ] + } + + rule_group { + rule_group_name = "REQUEST-920-PROTOCOL-ENFORCEMENT" + excluded_rules = [ + "920100", + "920120", + ] + } + } + } + + managed_rule_set { + type = "OWASP" + version = "3.2" + + rule_group_override { + rule_group_name = "REQUEST-920-PROTOCOL-ENFORCEMENT" + disabled_rules = [ + "920300", + "920440", + ] + } + } + } + + policy_settings { + enabled = true + mode = "Prevention" + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger) +} diff --git a/internal/services/policy/client/client.go b/internal/services/policy/client/client.go index e4656fcb0212..2d57570ae7f3 100644 --- a/internal/services/policy/client/client.go +++ b/internal/services/policy/client/client.go @@ -4,7 +4,7 @@ import ( "github.com/Azure/azure-sdk-for-go/services/guestconfiguration/mgmt/2020-06-25/guestconfiguration" "github.com/Azure/azure-sdk-for-go/services/preview/resources/mgmt/2021-06-01-preview/policy" policyPreview "github.com/Azure/azure-sdk-for-go/services/preview/resources/mgmt/2021-06-01-preview/policy" - "github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights" + "github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations" "github.com/hashicorp/terraform-provider-azurerm/internal/common" ) @@ -13,7 +13,7 @@ type Client struct { DefinitionsClient *policy.DefinitionsClient ExemptionsClient *policyPreview.ExemptionsClient SetDefinitionsClient *policy.SetDefinitionsClient - PolicyInsightsClient *policyinsights.PolicyInsightsClient + RemediationsClient *remediations.RemediationsClient GuestConfigurationAssignmentsClient *guestconfiguration.AssignmentsClient } @@ -30,8 +30,8 @@ func NewClient(o *common.ClientOptions) *Client { setDefinitionsClient := policy.NewSetDefinitionsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&setDefinitionsClient.Client, o.ResourceManagerAuthorizer) - policyInsightsClient := policyinsights.NewPolicyInsightsClientWithBaseURI(o.ResourceManagerEndpoint) - o.ConfigureClient(&policyInsightsClient.Client, o.ResourceManagerAuthorizer) + remediationsClient := remediations.NewRemediationsClientWithBaseURI(o.ResourceManagerEndpoint) + o.ConfigureClient(&remediationsClient.Client, o.ResourceManagerAuthorizer) guestConfigurationAssignmentsClient := guestconfiguration.NewAssignmentsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&guestConfigurationAssignmentsClient.Client, o.ResourceManagerAuthorizer) @@ -41,7 +41,7 @@ func NewClient(o *common.ClientOptions) *Client { DefinitionsClient: &definitionsClient, ExemptionsClient: &exemptionsClient, SetDefinitionsClient: &setDefinitionsClient, - PolicyInsightsClient: &policyInsightsClient, + RemediationsClient: &remediationsClient, GuestConfigurationAssignmentsClient: &guestConfigurationAssignmentsClient, } } diff --git a/internal/services/policy/remediation_management_group.go b/internal/services/policy/remediation_management_group.go index 7221236fbcdc..63a4d34ba0d8 100644 --- a/internal/services/policy/remediation_management_group.go +++ b/internal/services/policy/remediation_management_group.go @@ -8,9 +8,11 @@ import ( "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" - "github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights" + "github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" + validate2 "github.com/hashicorp/terraform-provider-azurerm/helpers/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/features" managmentGroupParse "github.com/hashicorp/terraform-provider-azurerm/internal/services/managementgroup/parse" managmentGroupValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/managementgroup/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/services/policy/parse" @@ -19,11 +21,10 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/internal/tf/suppress" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" - "github.com/hashicorp/terraform-provider-azurerm/utils" ) func resourceArmManagementGroupPolicyRemediation() *pluginsdk.Resource { - return &pluginsdk.Resource{ + resource := &pluginsdk.Resource{ Create: resourceArmManagementGroupPolicyRemediationCreateUpdate, Read: resourceArmManagementGroupPolicyRemediationRead, Update: resourceArmManagementGroupPolicyRemediationCreateUpdate, @@ -64,6 +65,24 @@ func resourceArmManagementGroupPolicyRemediation() *pluginsdk.Resource { ValidateFunc: validate.PolicyAssignmentID, }, + "failure_percentage": { + Type: pluginsdk.TypeFloat, + Optional: true, + ValidateFunc: validate2.FloatInRange(0, 1.0), + }, + + "parallel_deployments": { + Type: pluginsdk.TypeInt, + Optional: true, + ValidateFunc: validate2.IntegerPositive, + }, + + "resource_count": { + Type: pluginsdk.TypeInt, + Optional: true, + ValidateFunc: validate2.IntegerPositive, + }, + "location_filters": { Type: pluginsdk.TypeList, Optional: true, @@ -80,22 +99,26 @@ func resourceArmManagementGroupPolicyRemediation() *pluginsdk.Resource { DiffSuppressFunc: suppress.CaseDifference, ValidateFunc: validate.PolicyDefinitionID, }, - - "resource_discovery_mode": { - Type: pluginsdk.TypeString, - Optional: true, - Default: string(policyinsights.ResourceDiscoveryModeExistingNonCompliant), - ValidateFunc: validation.StringInSlice([]string{ - string(policyinsights.ResourceDiscoveryModeExistingNonCompliant), - string(policyinsights.ResourceDiscoveryModeReEvaluateCompliance), - }, false), - }, }, } + + if !features.FourPointOhBeta() { + resource.Schema["resource_discovery_mode"] = &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + Optional: true, + Default: string(remediations.ResourceDiscoveryModeExistingNonCompliant), + ValidateFunc: validation.StringInSlice([]string{ + string(remediations.ResourceDiscoveryModeExistingNonCompliant), + string(remediations.ResourceDiscoveryModeReEvaluateCompliance), + }, false), + Deprecated: "`resource_discovery_mode` will be removed in version 4.0 of the AzureRM Provider as evaluating compliance before remediation is only supported at subscription scope and below.", + } + } + return resource } func resourceArmManagementGroupPolicyRemediationCreateUpdate(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Policy.PolicyInsightsClient + client := meta.(*clients.Client).Policy.RemediationsClient ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) defer cancel() @@ -103,7 +126,7 @@ func resourceArmManagementGroupPolicyRemediationCreateUpdate(d *pluginsdk.Resour if err != nil { return err } - id := policyinsights.NewProviders2RemediationID(managementID.Name, d.Get("name").(string)) + id := remediations.NewProviders2RemediationID(managementID.Name, d.Get("name").(string)) if d.IsNewResource() { existing, err := client.RemediationsGetAtManagementGroup(ctx, id) @@ -117,17 +140,9 @@ func resourceArmManagementGroupPolicyRemediationCreateUpdate(d *pluginsdk.Resour } } - parameters := policyinsights.Remediation{ - Properties: &policyinsights.RemediationProperties{ - Filters: &policyinsights.RemediationFilters{ - Locations: utils.ExpandStringSlice(d.Get("location_filters").([]interface{})), - }, - PolicyAssignmentId: utils.String(d.Get("policy_assignment_id").(string)), - PolicyDefinitionReferenceId: utils.String(d.Get("policy_definition_id").(string)), - }, + parameters := remediations.Remediation{ + Properties: readRemediationProperties(d), } - mode := policyinsights.ResourceDiscoveryMode(d.Get("resource_discovery_mode").(string)) - parameters.Properties.ResourceDiscoveryMode = &mode if _, err := client.RemediationsCreateOrUpdateAtManagementGroup(ctx, id, parameters); err != nil { return fmt.Errorf("creating/updating %s: %+v", id.ID(), err) @@ -139,11 +154,11 @@ func resourceArmManagementGroupPolicyRemediationCreateUpdate(d *pluginsdk.Resour } func resourceArmManagementGroupPolicyRemediationRead(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Policy.PolicyInsightsClient + client := meta.(*clients.Client).Policy.RemediationsClient ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := policyinsights.ParseProviders2RemediationID(d.Id()) + id, err := remediations.ParseProviders2RemediationID(d.Id()) if err != nil { return fmt.Errorf("reading Policy Remediation: %+v", err) } @@ -162,29 +177,15 @@ func resourceArmManagementGroupPolicyRemediationRead(d *pluginsdk.ResourceData, managementGroupID := managmentGroupParse.NewManagementGroupId(id.ManagementGroupId) d.Set("management_group_id", managementGroupID.ID()) - if props := resp.Model.Properties; props != nil { - locations := []interface{}{} - if filters := props.Filters; filters != nil { - locations = utils.FlattenStringSlice(filters.Locations) - } - if err := d.Set("location_filters", locations); err != nil { - return fmt.Errorf("setting `location_filters`: %+v", err) - } - - d.Set("policy_assignment_id", props.PolicyAssignmentId) - d.Set("policy_definition_id", props.PolicyDefinitionReferenceId) - d.Set("resource_discovery_mode", props.ResourceDiscoveryMode) - } - - return nil + return setRemediationProperties(d, resp.Model.Properties) } func resourceArmManagementGroupPolicyRemediationDelete(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Policy.PolicyInsightsClient + client := meta.(*clients.Client).Policy.RemediationsClient ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := policyinsights.ParseProviders2RemediationID(d.Id()) + id, err := remediations.ParseProviders2RemediationID(d.Id()) if err != nil { return err } @@ -215,7 +216,7 @@ func resourceArmManagementGroupPolicyRemediationDelete(d *pluginsdk.ResourceData } func managementGroupPolicyRemediationCancellationRefreshFunc(ctx context.Context, - client *policyinsights.PolicyInsightsClient, id policyinsights.Providers2RemediationId) pluginsdk.StateRefreshFunc { + client *remediations.RemediationsClient, id remediations.Providers2RemediationId) pluginsdk.StateRefreshFunc { return func() (interface{}, string, error) { resp, err := client.RemediationsGetAtManagementGroup(ctx, id) diff --git a/internal/services/policy/remediation_management_group_test.go b/internal/services/policy/remediation_management_group_test.go index 99a447864838..d8299ae65dea 100644 --- a/internal/services/policy/remediation_management_group_test.go +++ b/internal/services/policy/remediation_management_group_test.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/hashicorp/go-azure-helpers/lang/response" - "github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights" + "github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" @@ -47,12 +47,12 @@ func TestAccAzureRMManagementGroupPolicyRemediation_complete(t *testing.T) { } func (r ManagementGroupPolicyRemediationResource) Exists(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := policyinsights.ParseProviders2RemediationID(state.ID) + id, err := remediations.ParseProviders2RemediationID(state.ID) if err != nil { return nil, err } - resp, err := client.Policy.PolicyInsightsClient.RemediationsGetAtManagementGroup(ctx, *id) + resp, err := client.Policy.RemediationsClient.RemediationsGetAtManagementGroup(ctx, *id) if err != nil || resp.Model == nil { if response.WasNotFound(resp.HttpResponse) { return utils.Bool(false), nil @@ -78,7 +78,7 @@ data "azurerm_policy_definition" "test" { } resource "azurerm_management_group_policy_assignment" "test" { - name = "acctestpol-%[2]s" + name = "acctestpa-mg-%[2]s" management_group_id = azurerm_management_group.test.id policy_definition_id = data.azurerm_policy_definition.test.id parameters = jsonencode({ diff --git a/internal/services/policy/remediation_resource.go b/internal/services/policy/remediation_resource.go index efe4bb667e29..4aa114ea95ef 100644 --- a/internal/services/policy/remediation_resource.go +++ b/internal/services/policy/remediation_resource.go @@ -8,9 +8,10 @@ import ( "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" - "github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights" + "github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" + validate2 "github.com/hashicorp/terraform-provider-azurerm/helpers/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/services/policy/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/policy/validate" @@ -63,6 +64,24 @@ func resourceArmResourcePolicyRemediation() *pluginsdk.Resource { ValidateFunc: validate.PolicyAssignmentID, }, + "failure_percentage": { + Type: pluginsdk.TypeFloat, + Optional: true, + ValidateFunc: validate2.FloatInRange(0, 1.0), + }, + + "parallel_deployments": { + Type: pluginsdk.TypeInt, + Optional: true, + ValidateFunc: validate2.IntegerPositive, + }, + + "resource_count": { + Type: pluginsdk.TypeInt, + Optional: true, + ValidateFunc: validate2.IntegerPositive, + }, + "location_filters": { Type: pluginsdk.TypeList, Optional: true, @@ -83,10 +102,10 @@ func resourceArmResourcePolicyRemediation() *pluginsdk.Resource { "resource_discovery_mode": { Type: pluginsdk.TypeString, Optional: true, - Default: string(policyinsights.ResourceDiscoveryModeExistingNonCompliant), + Default: string(remediations.ResourceDiscoveryModeExistingNonCompliant), ValidateFunc: validation.StringInSlice([]string{ - string(policyinsights.ResourceDiscoveryModeExistingNonCompliant), - string(policyinsights.ResourceDiscoveryModeReEvaluateCompliance), + string(remediations.ResourceDiscoveryModeExistingNonCompliant), + string(remediations.ResourceDiscoveryModeReEvaluateCompliance), }, false), }, }, @@ -94,13 +113,13 @@ func resourceArmResourcePolicyRemediation() *pluginsdk.Resource { } func resourceArmResourcePolicyRemediationCreateUpdate(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Policy.PolicyInsightsClient + client := meta.(*clients.Client).Policy.RemediationsClient ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) defer cancel() resourceId := d.Get("resource_id").(string) - id := policyinsights.NewScopedRemediationID(resourceId, d.Get("name").(string)) + id := remediations.NewScopedRemediationID(resourceId, d.Get("name").(string)) if d.IsNewResource() { existing, err := client.RemediationsGetAtResource(ctx, id) @@ -114,17 +133,9 @@ func resourceArmResourcePolicyRemediationCreateUpdate(d *pluginsdk.ResourceData, } } - parameters := policyinsights.Remediation{ - Properties: &policyinsights.RemediationProperties{ - Filters: &policyinsights.RemediationFilters{ - Locations: utils.ExpandStringSlice(d.Get("location_filters").([]interface{})), - }, - PolicyAssignmentId: utils.String(d.Get("policy_assignment_id").(string)), - PolicyDefinitionReferenceId: utils.String(d.Get("policy_definition_id").(string)), - }, + parameters := remediations.Remediation{ + Properties: readRemediationProperties(d), } - mode := policyinsights.ResourceDiscoveryMode(d.Get("resource_discovery_mode").(string)) - parameters.Properties.ResourceDiscoveryMode = &mode if _, err := client.RemediationsCreateOrUpdateAtResource(ctx, id, parameters); err != nil { return fmt.Errorf("creating/updating %s: %+v", id.ID(), err) @@ -136,11 +147,11 @@ func resourceArmResourcePolicyRemediationCreateUpdate(d *pluginsdk.ResourceData, } func resourceArmResourcePolicyRemediationRead(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Policy.PolicyInsightsClient + client := meta.(*clients.Client).Policy.RemediationsClient ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := policyinsights.ParseScopedRemediationID(d.Id()) + id, err := remediations.ParseScopedRemediationID(d.Id()) if err != nil { return fmt.Errorf("parsing Policy Scoped Remediation ID: %+v", err) } @@ -157,30 +168,15 @@ func resourceArmResourcePolicyRemediationRead(d *pluginsdk.ResourceData, meta in d.Set("name", id.RemediationName) d.Set("resource_id", id.ResourceId) - if props := resp.Model.Properties; props != nil { - locations := []interface{}{} - if filters := props.Filters; filters != nil { - locations = utils.FlattenStringSlice(filters.Locations) - } - if err := d.Set("location_filters", locations); err != nil { - return fmt.Errorf("setting `location_filters`: %+v", err) - } - - d.Set("policy_assignment_id", props.PolicyAssignmentId) - d.Set("policy_definition_id", props.PolicyDefinitionReferenceId) - d.Set("resource_discovery_mode", utils.NormalizeNilableString((*string)(props.ResourceDiscoveryMode))) - - } - - return nil + return setRemediationProperties(d, resp.Model.Properties) } func resourceArmResourcePolicyRemediationDelete(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Policy.PolicyInsightsClient + client := meta.(*clients.Client).Policy.RemediationsClient ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := policyinsights.ParseScopedRemediationID(d.Id()) + id, err := remediations.ParseScopedRemediationID(d.Id()) if err != nil { return fmt.Errorf("parsing Policy Scoped Remediation ID: %+v", err) } @@ -213,7 +209,7 @@ func resourceArmResourcePolicyRemediationDelete(d *pluginsdk.ResourceData, meta return err } -func resourcePolicyRemediationCancellationRefreshFunc(ctx context.Context, client *policyinsights.PolicyInsightsClient, id policyinsights.ScopedRemediationId) pluginsdk.StateRefreshFunc { +func resourcePolicyRemediationCancellationRefreshFunc(ctx context.Context, client *remediations.RemediationsClient, id remediations.ScopedRemediationId) pluginsdk.StateRefreshFunc { return func() (interface{}, string, error) { resp, err := client.RemediationsGetAtResource(ctx, id) if err != nil { @@ -232,7 +228,7 @@ func resourcePolicyRemediationCancellationRefreshFunc(ctx context.Context, clien // waitRemediationToDelete waits for the remediation to a status that allow to delete func waitRemediationToDelete(ctx context.Context, - prop *policyinsights.RemediationProperties, + prop *remediations.RemediationProperties, id string, timeout time.Duration, cancelFunc func() error, @@ -241,7 +237,7 @@ func waitRemediationToDelete(ctx context.Context, if prop == nil { return nil } - if mode := prop.ResourceDiscoveryMode; mode != nil && *mode == policyinsights.ResourceDiscoveryModeReEvaluateCompliance { + if mode := prop.ResourceDiscoveryMode; mode != nil && *mode == remediations.ResourceDiscoveryModeReEvaluateCompliance { // Remediation can only be canceld when it is in "Evaluating" or "Accepted" status, otherwise, API might raise error (e.g. canceling a "Completed" remediation returns 400). if state := prop.ProvisioningState; state != nil && (*state == "Evaluating" || *state == "Accepted") { log.Printf("[DEBUG] cancelling the remediation first before deleting it when `resource_discovery_mode` is set to `ReEvaluateCompliance`") @@ -267,3 +263,53 @@ func waitRemediationToDelete(ctx context.Context, } return nil } + +// readRemediationProperties sets the properties of the remediation, useful when add new properties to the model +func readRemediationProperties(d *pluginsdk.ResourceData) (prop *remediations.RemediationProperties) { + prop = &remediations.RemediationProperties{ + Filters: &remediations.RemediationFilters{ + Locations: utils.ExpandStringSlice(d.Get("location_filters").([]interface{})), + }, + PolicyAssignmentId: utils.String(d.Get("policy_assignment_id").(string)), + PolicyDefinitionReferenceId: utils.String(d.Get("policy_definition_id").(string)), + } + mode := remediations.ResourceDiscoveryMode(d.Get("resource_discovery_mode").(string)) + prop.ResourceDiscoveryMode = &mode + if v := d.Get("failure_percentage").(float64); v != 0 { + prop.FailureThreshold = &remediations.RemediationPropertiesFailureThreshold{ + Percentage: utils.Float(v), + } + } + if v := d.Get("parallel_deployments").(int); v != 0 { + prop.ParallelDeployments = utils.Int64(int64(v)) + } + if v := d.Get("resource_count").(int); v != 0 { + prop.ResourceCount = utils.Int64(int64(v)) + } + return +} + +// setRemediationProperties sets the properties of the remediation, useful when add new properties to the model +func setRemediationProperties(d *pluginsdk.ResourceData, prop *remediations.RemediationProperties) error { + if prop == nil { + return nil + } + locations := []interface{}{} + if filters := prop.Filters; filters != nil { + locations = utils.FlattenStringSlice(filters.Locations) + } + if err := d.Set("location_filters", locations); err != nil { + return fmt.Errorf("setting `location_filters`: %+v", err) + } + + d.Set("policy_assignment_id", prop.PolicyAssignmentId) + d.Set("policy_definition_id", prop.PolicyDefinitionReferenceId) + d.Set("resource_discovery_mode", utils.NormalizeNilableString((*string)(prop.ResourceDiscoveryMode))) + + d.Set("resource_count", prop.ResourceCount) + d.Set("parallel_deployments", prop.ParallelDeployments) + if prop.FailureThreshold != nil { + d.Set("failure_percentage", prop.FailureThreshold.Percentage) + } + return nil +} diff --git a/internal/services/policy/remediation_resource_group.go b/internal/services/policy/remediation_resource_group.go index 799934922629..3b441d6b6638 100644 --- a/internal/services/policy/remediation_resource_group.go +++ b/internal/services/policy/remediation_resource_group.go @@ -8,8 +8,9 @@ import ( "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" - "github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights" + "github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" + validate2 "github.com/hashicorp/terraform-provider-azurerm/helpers/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/services/policy/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/policy/validate" @@ -19,7 +20,6 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/internal/tf/suppress" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" - "github.com/hashicorp/terraform-provider-azurerm/utils" ) func resourceArmResourceGroupPolicyRemediation() *pluginsdk.Resource { @@ -64,6 +64,24 @@ func resourceArmResourceGroupPolicyRemediation() *pluginsdk.Resource { ValidateFunc: validate.PolicyAssignmentID, }, + "failure_percentage": { + Type: pluginsdk.TypeFloat, + Optional: true, + ValidateFunc: validate2.FloatInRange(0, 1.0), + }, + + "parallel_deployments": { + Type: pluginsdk.TypeInt, + Optional: true, + ValidateFunc: validate2.IntegerPositive, + }, + + "resource_count": { + Type: pluginsdk.TypeInt, + Optional: true, + ValidateFunc: validate2.IntegerPositive, + }, + "location_filters": { Type: pluginsdk.TypeList, Optional: true, @@ -84,10 +102,10 @@ func resourceArmResourceGroupPolicyRemediation() *pluginsdk.Resource { "resource_discovery_mode": { Type: pluginsdk.TypeString, Optional: true, - Default: string(policyinsights.ResourceDiscoveryModeExistingNonCompliant), + Default: string(remediations.ResourceDiscoveryModeExistingNonCompliant), ValidateFunc: validation.StringInSlice([]string{ - string(policyinsights.ResourceDiscoveryModeExistingNonCompliant), - string(policyinsights.ResourceDiscoveryModeReEvaluateCompliance), + string(remediations.ResourceDiscoveryModeExistingNonCompliant), + string(remediations.ResourceDiscoveryModeReEvaluateCompliance), }, false), }, }, @@ -95,7 +113,7 @@ func resourceArmResourceGroupPolicyRemediation() *pluginsdk.Resource { } func resourceArmResourceGroupPolicyRemediationCreateUpdate(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Policy.PolicyInsightsClient + client := meta.(*clients.Client).Policy.RemediationsClient ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) defer cancel() @@ -104,7 +122,7 @@ func resourceArmResourceGroupPolicyRemediationCreateUpdate(d *pluginsdk.Resource return err } - id := policyinsights.NewProviderRemediationID(resourceGroupId.SubscriptionId, resourceGroupId.ResourceGroup, d.Get("name").(string)) + id := remediations.NewProviderRemediationID(resourceGroupId.SubscriptionId, resourceGroupId.ResourceGroup, d.Get("name").(string)) if d.IsNewResource() { existing, err := client.RemediationsGetAtResourceGroup(ctx, id) @@ -118,17 +136,9 @@ func resourceArmResourceGroupPolicyRemediationCreateUpdate(d *pluginsdk.Resource } } - parameters := policyinsights.Remediation{ - Properties: &policyinsights.RemediationProperties{ - Filters: &policyinsights.RemediationFilters{ - Locations: utils.ExpandStringSlice(d.Get("location_filters").([]interface{})), - }, - PolicyAssignmentId: utils.String(d.Get("policy_assignment_id").(string)), - PolicyDefinitionReferenceId: utils.String(d.Get("policy_definition_id").(string)), - }, + parameters := remediations.Remediation{ + Properties: readRemediationProperties(d), } - mode := policyinsights.ResourceDiscoveryMode(d.Get("resource_discovery_mode").(string)) - parameters.Properties.ResourceDiscoveryMode = &mode if _, err = client.RemediationsCreateOrUpdateAtResourceGroup(ctx, id, parameters); err != nil { return fmt.Errorf("creating/updating %s: %+v", id.ID(), err) @@ -140,11 +150,11 @@ func resourceArmResourceGroupPolicyRemediationCreateUpdate(d *pluginsdk.Resource } func resourceArmResourceGroupPolicyRemediationRead(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Policy.PolicyInsightsClient + client := meta.(*clients.Client).Policy.RemediationsClient ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := policyinsights.ParseProviderRemediationID(d.Id()) + id, err := remediations.ParseProviderRemediationID(d.Id()) if err != nil { return fmt.Errorf("reading Policy Remediation: %+v", err) } @@ -164,30 +174,15 @@ func resourceArmResourceGroupPolicyRemediationRead(d *pluginsdk.ResourceData, me d.Set("name", id.RemediationName) d.Set("resource_group_id", resourceGroupId.ID()) - if props := resp.Model.Properties; props != nil { - locations := []interface{}{} - if filters := props.Filters; filters != nil { - locations = utils.FlattenStringSlice(filters.Locations) - } - if err := d.Set("location_filters", locations); err != nil { - return fmt.Errorf("setting `location_filters`: %+v", err) - } - - d.Set("policy_assignment_id", props.PolicyAssignmentId) - d.Set("policy_definition_id", props.PolicyDefinitionReferenceId) - d.Set("resource_discovery_mode", utils.NormalizeNilableString((*string)(props.ResourceDiscoveryMode))) - - } - - return nil + return setRemediationProperties(d, resp.Model.Properties) } func resourceArmResourceGroupPolicyRemediationDelete(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Policy.PolicyInsightsClient + client := meta.(*clients.Client).Policy.RemediationsClient ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := policyinsights.ParseProviderRemediationID(d.Id()) + id, err := remediations.ParseProviderRemediationID(d.Id()) if err != nil { return err } @@ -217,7 +212,7 @@ func resourceArmResourceGroupPolicyRemediationDelete(d *pluginsdk.ResourceData, return err } -func resourceGroupPolicyRemediationCancellationRefreshFunc(ctx context.Context, client *policyinsights.PolicyInsightsClient, id policyinsights.ProviderRemediationId) pluginsdk.StateRefreshFunc { +func resourceGroupPolicyRemediationCancellationRefreshFunc(ctx context.Context, client *remediations.RemediationsClient, id remediations.ProviderRemediationId) pluginsdk.StateRefreshFunc { return func() (interface{}, string, error) { resp, err := client.RemediationsGetAtResourceGroup(ctx, id) if err != nil { diff --git a/internal/services/policy/remediation_resource_group_test.go b/internal/services/policy/remediation_resource_group_test.go index 55c655a46424..6d14a23cbd3f 100644 --- a/internal/services/policy/remediation_resource_group_test.go +++ b/internal/services/policy/remediation_resource_group_test.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/hashicorp/go-azure-helpers/lang/response" - "github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights" + "github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" @@ -47,12 +47,12 @@ func TestAccAzureRMResourceGroupPolicyRemediation_complete(t *testing.T) { } func (r ResourceGroupPolicyRemediationResource) Exists(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := policyinsights.ParseProviderRemediationID(state.ID) + id, err := remediations.ParseProviderRemediationID(state.ID) if err != nil { return nil, err } - resp, err := client.Policy.PolicyInsightsClient.RemediationsGetAtResourceGroup(ctx, *id) + resp, err := client.Policy.RemediationsClient.RemediationsGetAtResourceGroup(ctx, *id) if err != nil || resp.Model == nil { if response.WasNotFound(resp.HttpResponse) { return utils.Bool(false), nil @@ -109,7 +109,7 @@ PARAMETERS } resource "azurerm_resource_group_policy_assignment" "test" { - name = "acctestpa-%[1]s" + name = "acctestpa-rg-%[1]s" resource_group_id = azurerm_resource_group.test.id policy_definition_id = azurerm_policy_definition.test.id @@ -149,6 +149,9 @@ resource "azurerm_resource_group_policy_remediation" "test" { location_filters = ["westus"] policy_definition_id = azurerm_policy_definition.test.id resource_discovery_mode = "ReEvaluateCompliance" + failure_percentage = 0.5 + parallel_deployments = 3 + resource_count = 3 } `, r.template(data), data.RandomString) } diff --git a/internal/services/policy/remediation_resource_test.go b/internal/services/policy/remediation_resource_test.go index 14c1498a3d4e..387cedc960b0 100644 --- a/internal/services/policy/remediation_resource_test.go +++ b/internal/services/policy/remediation_resource_test.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/hashicorp/go-azure-helpers/lang/response" - "github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights" + policyinsights "github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" @@ -52,7 +52,7 @@ func (r ResourcePolicyRemediationResource) Exists(ctx context.Context, client *c return nil, err } - resp, err := client.Policy.PolicyInsightsClient.RemediationsGetAtResource(ctx, *id) + resp, err := client.Policy.RemediationsClient.RemediationsGetAtResource(ctx, *id) if err != nil || resp.Model == nil { if response.WasNotFound(resp.HttpResponse) { return utils.Bool(false), nil @@ -86,7 +86,7 @@ data "azurerm_policy_definition" "test" { } resource "azurerm_resource_policy_assignment" "test" { - name = "acctestpa-%[1]s" + name = "acctestpa-res-%[1]s" resource_id = azurerm_virtual_network.test.id policy_definition_id = data.azurerm_policy_definition.test.id parameters = jsonencode({ @@ -121,6 +121,9 @@ resource "azurerm_resource_policy_remediation" "test" { location_filters = ["westus"] policy_definition_id = data.azurerm_policy_definition.test.id resource_discovery_mode = "ReEvaluateCompliance" + failure_percentage = 0.5 + parallel_deployments = 3 + resource_count = 3 } `, r.template(data), data.RandomString) } diff --git a/internal/services/policy/remediation_subscription.go b/internal/services/policy/remediation_subscription.go index 9ac266d7f89a..1cafdcc78236 100644 --- a/internal/services/policy/remediation_subscription.go +++ b/internal/services/policy/remediation_subscription.go @@ -9,8 +9,9 @@ import ( "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" - "github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights" + "github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" + validate2 "github.com/hashicorp/terraform-provider-azurerm/helpers/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/services/policy/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/policy/validate" @@ -18,7 +19,6 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/internal/tf/suppress" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" - "github.com/hashicorp/terraform-provider-azurerm/utils" ) func resourceArmSubscriptionPolicyRemediation() *pluginsdk.Resource { @@ -63,6 +63,24 @@ func resourceArmSubscriptionPolicyRemediation() *pluginsdk.Resource { ValidateFunc: validate.PolicyAssignmentID, }, + "failure_percentage": { + Type: pluginsdk.TypeFloat, + Optional: true, + ValidateFunc: validate2.FloatInRange(0, 1.0), + }, + + "parallel_deployments": { + Type: pluginsdk.TypeInt, + Optional: true, + ValidateFunc: validate2.IntegerPositive, + }, + + "resource_count": { + Type: pluginsdk.TypeInt, + Optional: true, + ValidateFunc: validate2.IntegerPositive, + }, + "location_filters": { Type: pluginsdk.TypeList, Optional: true, @@ -83,10 +101,10 @@ func resourceArmSubscriptionPolicyRemediation() *pluginsdk.Resource { "resource_discovery_mode": { Type: pluginsdk.TypeString, Optional: true, - Default: string(policyinsights.ResourceDiscoveryModeExistingNonCompliant), + Default: string(remediations.ResourceDiscoveryModeExistingNonCompliant), ValidateFunc: validation.StringInSlice([]string{ - string(policyinsights.ResourceDiscoveryModeExistingNonCompliant), - string(policyinsights.ResourceDiscoveryModeReEvaluateCompliance), + string(remediations.ResourceDiscoveryModeExistingNonCompliant), + string(remediations.ResourceDiscoveryModeReEvaluateCompliance), }, false), }, }, @@ -94,7 +112,7 @@ func resourceArmSubscriptionPolicyRemediation() *pluginsdk.Resource { } func resourceArmSubscriptionPolicyRemediationCreateUpdate(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Policy.PolicyInsightsClient + client := meta.(*clients.Client).Policy.RemediationsClient ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) defer cancel() @@ -103,7 +121,7 @@ func resourceArmSubscriptionPolicyRemediationCreateUpdate(d *pluginsdk.ResourceD return err } - id := policyinsights.NewRemediationID(subscriptionId.SubscriptionId, d.Get("name").(string)) + id := remediations.NewRemediationID(subscriptionId.SubscriptionId, d.Get("name").(string)) if d.IsNewResource() { existing, err := client.RemediationsGetAtSubscription(ctx, id) @@ -117,17 +135,9 @@ func resourceArmSubscriptionPolicyRemediationCreateUpdate(d *pluginsdk.ResourceD } } - parameters := policyinsights.Remediation{ - Properties: &policyinsights.RemediationProperties{ - Filters: &policyinsights.RemediationFilters{ - Locations: utils.ExpandStringSlice(d.Get("location_filters").([]interface{})), - }, - PolicyAssignmentId: utils.String(d.Get("policy_assignment_id").(string)), - PolicyDefinitionReferenceId: utils.String(d.Get("policy_definition_id").(string)), - }, + parameters := remediations.Remediation{ + Properties: readRemediationProperties(d), } - mode := policyinsights.ResourceDiscoveryMode(d.Get("resource_discovery_mode").(string)) - parameters.Properties.ResourceDiscoveryMode = &mode if _, err = client.RemediationsCreateOrUpdateAtSubscription(ctx, id, parameters); err != nil { return fmt.Errorf("creating/updating %s: %+v", id.ID(), err) @@ -139,11 +149,11 @@ func resourceArmSubscriptionPolicyRemediationCreateUpdate(d *pluginsdk.ResourceD } func resourceArmSubscriptionPolicyRemediationRead(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Policy.PolicyInsightsClient + client := meta.(*clients.Client).Policy.RemediationsClient ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := policyinsights.ParseRemediationID(d.Id()) + id, err := remediations.ParseRemediationID(d.Id()) if err != nil { return fmt.Errorf("reading Policy Remediation: %+v", err) } @@ -163,29 +173,15 @@ func resourceArmSubscriptionPolicyRemediationRead(d *pluginsdk.ResourceData, met d.Set("name", id.RemediationName) d.Set("subscription_id", subscriptionId.ID()) - if props := resp.Model.Properties; props != nil { - locations := []interface{}{} - if filters := props.Filters; filters != nil { - locations = utils.FlattenStringSlice(filters.Locations) - } - if err := d.Set("location_filters", locations); err != nil { - return fmt.Errorf("setting `location_filters`: %+v", err) - } - - d.Set("policy_assignment_id", props.PolicyAssignmentId) - d.Set("policy_definition_id", props.PolicyDefinitionReferenceId) - d.Set("resource_discovery_mode", utils.NormalizeNilableString((*string)(props.ResourceDiscoveryMode))) - } - - return nil + return setRemediationProperties(d, resp.Model.Properties) } func resourceArmSubscriptionPolicyRemediationDelete(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Policy.PolicyInsightsClient + client := meta.(*clients.Client).Policy.RemediationsClient ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := policyinsights.ParseRemediationID(d.Id()) + id, err := remediations.ParseRemediationID(d.Id()) if err != nil { return err } @@ -215,7 +211,7 @@ func resourceArmSubscriptionPolicyRemediationDelete(d *pluginsdk.ResourceData, m return err } -func subscriptionPolicyRemediationCancellationRefreshFunc(ctx context.Context, client *policyinsights.PolicyInsightsClient, id policyinsights.RemediationId) pluginsdk.StateRefreshFunc { +func subscriptionPolicyRemediationCancellationRefreshFunc(ctx context.Context, client *remediations.RemediationsClient, id remediations.RemediationId) pluginsdk.StateRefreshFunc { return func() (interface{}, string, error) { resp, err := client.RemediationsGetAtSubscription(ctx, id) if err != nil { diff --git a/internal/services/policy/remediation_subscription_test.go b/internal/services/policy/remediation_subscription_test.go index 0337874b5893..45792aa0f2e1 100644 --- a/internal/services/policy/remediation_subscription_test.go +++ b/internal/services/policy/remediation_subscription_test.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/hashicorp/go-azure-helpers/lang/response" - "github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/policyinsights" + "github.com/hashicorp/go-azure-sdk/resource-manager/policyinsights/2021-10-01/remediations" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" @@ -47,12 +47,12 @@ func TestAccAzureRMSubscriptionPolicyRemediation_complete(t *testing.T) { } func (r SubscriptionPolicyRemediationResource) Exists(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := policyinsights.ParseRemediationID(state.ID) + id, err := remediations.ParseRemediationID(state.ID) if err != nil { return nil, err } - resp, err := client.Policy.PolicyInsightsClient.RemediationsGetAtSubscription(ctx, *id) + resp, err := client.Policy.RemediationsClient.RemediationsGetAtSubscription(ctx, *id) if err != nil || resp.Model == nil { if response.WasNotFound(resp.HttpResponse) { return utils.Bool(false), nil @@ -76,16 +76,16 @@ data "azurerm_policy_definition" "test" { } resource "azurerm_subscription_policy_assignment" "test" { - name = "acctestpa-%[1]d" + name = "acctestpa-sub-%[1]d" subscription_id = data.azurerm_subscription.test.id policy_definition_id = data.azurerm_policy_definition.test.id parameters = jsonencode({ "listOfAllowedLocations" = { - "value" = ["%[2]s", "%[3]s"] + "value" = ["%[2]s", "%[3]s", "%[4]s"] } }) } -`, data.RandomInteger, data.Locations.Primary, data.Locations.Secondary) +`, data.RandomInteger, data.Locations.Primary, data.Locations.Secondary, data.Locations.Ternary) } func (r SubscriptionPolicyRemediationResource) basic(data acceptance.TestData) string { @@ -111,6 +111,9 @@ resource "azurerm_subscription_policy_remediation" "test" { location_filters = ["westus"] policy_definition_id = data.azurerm_policy_definition.test.id resource_discovery_mode = "ReEvaluateCompliance" + failure_percentage = 0.5 + parallel_deployments = 3 + resource_count = 3 } `, r.template(data), data.RandomString) } diff --git a/internal/services/postgres/client/client.go b/internal/services/postgres/client/client.go index eb9af7723fd6..c90a0be97a1b 100644 --- a/internal/services/postgres/client/client.go +++ b/internal/services/postgres/client/client.go @@ -1,65 +1,81 @@ package client import ( - "github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2020-01-01/postgresql" - "github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2021-06-01/postgresqlflexibleservers" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/configurations" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/databases" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/firewallrules" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/replicas" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/serveradministrators" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/serversecurityalertpolicies" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/virtualnetworkrules" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2020-01-01/serverkeys" + flexibleserverconfigurations "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/configurations" + flexibleserverdatabases "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/databases" + flexibleserverfirewallrules "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/firewallrules" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/serverrestart" + flexibleservers "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/servers" "github.com/hashicorp/terraform-provider-azurerm/internal/common" ) type Client struct { - ConfigurationsClient *postgresql.ConfigurationsClient - DatabasesClient *postgresql.DatabasesClient - FirewallRulesClient *postgresql.FirewallRulesClient - FlexibleServersClient *postgresqlflexibleservers.ServersClient - FlexibleServersConfigurationsClient *postgresqlflexibleservers.ConfigurationsClient - FlexibleServerFirewallRuleClient *postgresqlflexibleservers.FirewallRulesClient - FlexibleServerDatabaseClient *postgresqlflexibleservers.DatabasesClient - ServersClient *postgresql.ServersClient - ServerKeysClient *postgresql.ServerKeysClient - ServerSecurityAlertPoliciesClient *postgresql.ServerSecurityAlertPoliciesClient - VirtualNetworkRulesClient *postgresql.VirtualNetworkRulesClient - ServerAdministratorsClient *postgresql.ServerAdministratorsClient - ReplicasClient *postgresql.ReplicasClient + ConfigurationsClient *configurations.ConfigurationsClient + DatabasesClient *databases.DatabasesClient + FirewallRulesClient *firewallrules.FirewallRulesClient + FlexibleServersClient *flexibleservers.ServersClient + FlexibleServersConfigurationsClient *flexibleserverconfigurations.ConfigurationsClient + FlexibleServerFirewallRuleClient *flexibleserverfirewallrules.FirewallRulesClient + FlexibleServerDatabaseClient *flexibleserverdatabases.DatabasesClient + ServersClient *servers.ServersClient + ServerRestartClient *serverrestart.ServerRestartClient + ServerKeysClient *serverkeys.ServerKeysClient + ServerSecurityAlertPoliciesClient *serversecurityalertpolicies.ServerSecurityAlertPoliciesClient + VirtualNetworkRulesClient *virtualnetworkrules.VirtualNetworkRulesClient + ServerAdministratorsClient *serveradministrators.ServerAdministratorsClient + ReplicasClient *replicas.ReplicasClient } func NewClient(o *common.ClientOptions) *Client { - configurationsClient := postgresql.NewConfigurationsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + configurationsClient := configurations.NewConfigurationsClientWithBaseURI(o.ResourceManagerEndpoint) o.ConfigureClient(&configurationsClient.Client, o.ResourceManagerAuthorizer) - databasesClient := postgresql.NewDatabasesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + databasesClient := databases.NewDatabasesClientWithBaseURI(o.ResourceManagerEndpoint) o.ConfigureClient(&databasesClient.Client, o.ResourceManagerAuthorizer) - firewallRulesClient := postgresql.NewFirewallRulesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + firewallRulesClient := firewallrules.NewFirewallRulesClientWithBaseURI(o.ResourceManagerEndpoint) o.ConfigureClient(&firewallRulesClient.Client, o.ResourceManagerAuthorizer) - serversClient := postgresql.NewServersClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + serversClient := servers.NewServersClientWithBaseURI(o.ResourceManagerEndpoint) o.ConfigureClient(&serversClient.Client, o.ResourceManagerAuthorizer) - serverKeysClient := postgresql.NewServerKeysClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + serverKeysClient := serverkeys.NewServerKeysClientWithBaseURI(o.ResourceManagerEndpoint) o.ConfigureClient(&serverKeysClient.Client, o.ResourceManagerAuthorizer) - serverSecurityAlertPoliciesClient := postgresql.NewServerSecurityAlertPoliciesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + serverSecurityAlertPoliciesClient := serversecurityalertpolicies.NewServerSecurityAlertPoliciesClientWithBaseURI(o.ResourceManagerEndpoint) o.ConfigureClient(&serverSecurityAlertPoliciesClient.Client, o.ResourceManagerAuthorizer) - virtualNetworkRulesClient := postgresql.NewVirtualNetworkRulesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + virtualNetworkRulesClient := virtualnetworkrules.NewVirtualNetworkRulesClientWithBaseURI(o.ResourceManagerEndpoint) o.ConfigureClient(&virtualNetworkRulesClient.Client, o.ResourceManagerAuthorizer) - serverAdministratorsClient := postgresql.NewServerAdministratorsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + serverAdministratorsClient := serveradministrators.NewServerAdministratorsClientWithBaseURI(o.ResourceManagerEndpoint) o.ConfigureClient(&serverAdministratorsClient.Client, o.ResourceManagerAuthorizer) - replicasClient := postgresql.NewReplicasClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + replicasClient := replicas.NewReplicasClientWithBaseURI(o.ResourceManagerEndpoint) o.ConfigureClient(&replicasClient.Client, o.ResourceManagerAuthorizer) - flexibleServersClient := postgresqlflexibleservers.NewServersClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + flexibleServersClient := flexibleservers.NewServersClientWithBaseURI(o.ResourceManagerEndpoint) o.ConfigureClient(&flexibleServersClient.Client, o.ResourceManagerAuthorizer) - flexibleServerFirewallRuleClient := postgresqlflexibleservers.NewFirewallRulesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + restartServerClient := serverrestart.NewServerRestartClientWithBaseURI(o.ResourceManagerEndpoint) + o.ConfigureClient(&restartServerClient.Client, o.ResourceManagerAuthorizer) + + flexibleServerFirewallRuleClient := flexibleserverfirewallrules.NewFirewallRulesClientWithBaseURI(o.ResourceManagerEndpoint) o.ConfigureClient(&flexibleServerFirewallRuleClient.Client, o.ResourceManagerAuthorizer) - flexibleServerDatabaseClient := postgresqlflexibleservers.NewDatabasesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + flexibleServerDatabaseClient := flexibleserverdatabases.NewDatabasesClientWithBaseURI(o.ResourceManagerEndpoint) o.ConfigureClient(&flexibleServerDatabaseClient.Client, o.ResourceManagerAuthorizer) - flexibleServerConfigurationsClient := postgresqlflexibleservers.NewConfigurationsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + flexibleServerConfigurationsClient := flexibleserverconfigurations.NewConfigurationsClientWithBaseURI(o.ResourceManagerEndpoint) o.ConfigureClient(&flexibleServerConfigurationsClient.Client, o.ResourceManagerAuthorizer) return &Client{ @@ -68,6 +84,7 @@ func NewClient(o *common.ClientOptions) *Client { FirewallRulesClient: &firewallRulesClient, FlexibleServersConfigurationsClient: &flexibleServerConfigurationsClient, FlexibleServersClient: &flexibleServersClient, + ServerRestartClient: &restartServerClient, FlexibleServerFirewallRuleClient: &flexibleServerFirewallRuleClient, FlexibleServerDatabaseClient: &flexibleServerDatabaseClient, ServersClient: &serversClient, diff --git a/internal/services/postgres/migration/postgresql_aad_administrator.go b/internal/services/postgres/migration/postgresql_aad_administrator.go new file mode 100644 index 000000000000..1f86dfff4889 --- /dev/null +++ b/internal/services/postgres/migration/postgresql_aad_administrator.go @@ -0,0 +1,69 @@ +package migration + +import ( + "context" + "log" + + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/serveradministrators" + "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/validate" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/sql/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" +) + +var _ pluginsdk.StateUpgrade = PostgresqlAADAdministratorV0ToV1{} + +type PostgresqlAADAdministratorV0ToV1 struct{} + +func (PostgresqlAADAdministratorV0ToV1) Schema() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "server_name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + }, + + "resource_group_name": azure.SchemaResourceGroupName(), + + "login": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validate.AdminUsernames, + }, + + "object_id": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.IsUUID, + }, + + "tenant_id": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.IsUUID, + }, + } +} + +func (PostgresqlAADAdministratorV0ToV1) UpgradeFunc() pluginsdk.StateUpgraderFunc { + return func(ctx context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) { + // old + // /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DBforPostgreSQL/servers/{serverName}/administrators/activeDirectory + // new: + // /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DBforPostgreSQL/servers/{serverName} + // summary: + // Remove administrators chunk + oldId := rawState["id"].(string) + id, err := parse.AzureActiveDirectoryAdministratorID(oldId) + if err != nil { + return rawState, err + } + + newId := serveradministrators.NewServerID(id.SubscriptionId, id.ResourceGroup, id.ServerName) + log.Printf("[DEBUG] Updating ID from %q to %q", oldId, newId) + rawState["id"] = newId.ID() + + return rawState, nil + } +} diff --git a/internal/services/postgres/migration/postgresql_database.go b/internal/services/postgres/migration/postgresql_database.go new file mode 100644 index 000000000000..22a69c38a448 --- /dev/null +++ b/internal/services/postgres/migration/postgresql_database.go @@ -0,0 +1,74 @@ +package migration + +import ( + "context" + "log" + "strings" + + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/databases" + "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/validate" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/suppress" +) + +var _ pluginsdk.StateUpgrade = PostgresqlDatabaseV0ToV1{} + +type PostgresqlDatabaseV0ToV1 struct{} + +func (PostgresqlDatabaseV0ToV1) Schema() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + }, + + "resource_group_name": azure.SchemaResourceGroupName(), + + "server_name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.ServerName, + }, + + "charset": { + Type: pluginsdk.TypeString, + Required: true, + DiffSuppressFunc: suppress.CaseDifference, + ForceNew: true, + }, + + "collation": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.DatabaseCollation, + }, + } +} + +func (PostgresqlDatabaseV0ToV1) UpgradeFunc() pluginsdk.StateUpgraderFunc { + return func(ctx context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) { + // old + // /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DBForPostgreSQL/servers/{serverName}/databases/{databaseName} + // new: + // /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DBforPostgreSQL/servers/{serverName}/databases/{databaseName} + // summary: + // Check for `For` and swap to `for` + oldId := rawState["id"].(string) + if strings.Contains(oldId, "Microsoft.DBForPostgreSQL") { + modifiedId := strings.ReplaceAll(oldId, "Microsoft.DBForPostgreSQL", "Microsoft.DBforPostgreSQL") + + newId, err := databases.ParseDatabaseID(modifiedId) + if err != nil { + return rawState, err + } + log.Printf("[DEBUG] Updating ID from %q to %q", oldId, newId) + rawState["id"] = newId.ID() + } + + return rawState, nil + } +} diff --git a/internal/services/postgres/migration/postgresql_server.go b/internal/services/postgres/migration/postgresql_server.go new file mode 100644 index 000000000000..b7800d6d065b --- /dev/null +++ b/internal/services/postgres/migration/postgresql_server.go @@ -0,0 +1,264 @@ +package migration + +import ( + "context" + "log" + "strings" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers" + "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/validate" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" +) + +var _ pluginsdk.StateUpgrade = PostgresqlServerV0ToV1{} + +type PostgresqlServerV0ToV1 struct{} + +func (PostgresqlServerV0ToV1) Schema() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.ServerName, + }, + + "location": azure.SchemaLocation(), + + "resource_group_name": azure.SchemaResourceGroupName(), + + "sku_name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "version": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice(servers.PossibleValuesForServerVersion(), false), + }, + + "administrator_login": { + Type: pluginsdk.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ValidateFunc: validation.All(validation.StringIsNotWhiteSpace, validate.AdminUsernames), + }, + + "administrator_login_password": { + Type: pluginsdk.TypeString, + Optional: true, + Sensitive: true, + }, + + "auto_grow_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: true, + }, + + "backup_retention_days": { + Type: pluginsdk.TypeInt, + Optional: true, + Computed: true, + ValidateFunc: validation.IntBetween(7, 35), + }, + + "geo_redundant_backup_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + ForceNew: true, + Default: false, + }, + + "create_mode": { + Type: pluginsdk.TypeString, + Optional: true, + Default: string(servers.CreateModeDefault), + ValidateFunc: validation.StringInSlice(servers.PossibleValuesForCreateMode(), false), + }, + + "creation_source_server_id": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: servers.ValidateServerID, + }, + + "identity": commonschema.SystemAssignedIdentityOptional(), + + "infrastructure_encryption_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + ForceNew: true, + }, + + "public_network_access_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: true, + }, + + "restore_point_in_time": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.IsRFC3339Time, + }, + + "storage_mb": { + Type: pluginsdk.TypeInt, + Optional: true, + Computed: true, + ValidateFunc: validation.All( + validation.IntBetween(5120, 16777216), + validation.IntDivisibleBy(1024), + ), + }, + + "ssl_minimal_tls_version_enforced": { + Type: pluginsdk.TypeString, + Optional: true, + Default: string(servers.MinimalTlsVersionEnumTLSOneTwo), + ValidateFunc: validation.StringInSlice(servers.PossibleValuesForMinimalTlsVersionEnum(), false), + }, + + "ssl_enforcement_enabled": { + Type: pluginsdk.TypeBool, + Required: true, + }, + + "threat_detection_policy": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + AtLeastOneOf: []string{ + "threat_detection_policy.0.enabled", "threat_detection_policy.0.disabled_alerts", "threat_detection_policy.0.email_account_admins", + "threat_detection_policy.0.email_addresses", "threat_detection_policy.0.retention_days", "threat_detection_policy.0.storage_account_access_key", + "threat_detection_policy.0.storage_endpoint", + }, + }, + + "disabled_alerts": { + Type: pluginsdk.TypeSet, + Optional: true, + Set: pluginsdk.HashString, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringInSlice([]string{ + "Sql_Injection", + "Sql_Injection_Vulnerability", + "Access_Anomaly", + "Data_Exfiltration", + "Unsafe_Action", + }, false), + }, + AtLeastOneOf: []string{ + "threat_detection_policy.0.enabled", "threat_detection_policy.0.disabled_alerts", "threat_detection_policy.0.email_account_admins", + "threat_detection_policy.0.email_addresses", "threat_detection_policy.0.retention_days", "threat_detection_policy.0.storage_account_access_key", + "threat_detection_policy.0.storage_endpoint", + }, + }, + + "email_account_admins": { + Type: pluginsdk.TypeBool, + Optional: true, + AtLeastOneOf: []string{ + "threat_detection_policy.0.enabled", "threat_detection_policy.0.disabled_alerts", "threat_detection_policy.0.email_account_admins", + "threat_detection_policy.0.email_addresses", "threat_detection_policy.0.retention_days", "threat_detection_policy.0.storage_account_access_key", + "threat_detection_policy.0.storage_endpoint", + }, + }, + + "email_addresses": { + Type: pluginsdk.TypeSet, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + // todo email validation in code + }, + Set: pluginsdk.HashString, + AtLeastOneOf: []string{ + "threat_detection_policy.0.enabled", "threat_detection_policy.0.disabled_alerts", "threat_detection_policy.0.email_account_admins", + "threat_detection_policy.0.email_addresses", "threat_detection_policy.0.retention_days", "threat_detection_policy.0.storage_account_access_key", + "threat_detection_policy.0.storage_endpoint", + }, + }, + + "retention_days": { + Type: pluginsdk.TypeInt, + Optional: true, + ValidateFunc: validation.IntAtLeast(0), + AtLeastOneOf: []string{ + "threat_detection_policy.0.enabled", "threat_detection_policy.0.disabled_alerts", "threat_detection_policy.0.email_account_admins", + "threat_detection_policy.0.email_addresses", "threat_detection_policy.0.retention_days", "threat_detection_policy.0.storage_account_access_key", + "threat_detection_policy.0.storage_endpoint", + }, + }, + + "storage_account_access_key": { + Type: pluginsdk.TypeString, + Optional: true, + Sensitive: true, + ValidateFunc: validation.StringIsNotEmpty, + AtLeastOneOf: []string{ + "threat_detection_policy.0.enabled", "threat_detection_policy.0.disabled_alerts", "threat_detection_policy.0.email_account_admins", + "threat_detection_policy.0.email_addresses", "threat_detection_policy.0.retention_days", "threat_detection_policy.0.storage_account_access_key", + "threat_detection_policy.0.storage_endpoint", + }, + }, + + "storage_endpoint": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.StringIsNotEmpty, + AtLeastOneOf: []string{ + "threat_detection_policy.0.enabled", "threat_detection_policy.0.disabled_alerts", "threat_detection_policy.0.email_account_admins", + "threat_detection_policy.0.email_addresses", "threat_detection_policy.0.retention_days", "threat_detection_policy.0.storage_account_access_key", + "threat_detection_policy.0.storage_endpoint", + }, + }, + }, + }, + }, + + "fqdn": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "tags": commonschema.Tags(), + } +} + +func (PostgresqlServerV0ToV1) UpgradeFunc() pluginsdk.StateUpgraderFunc { + return func(ctx context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) { + // old + // /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DBForPostgreSQL/servers/{serverName} + // new: + // /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DBforPostgreSQL/servers/{serverName} + // summary: + // Check for `For` and swap to `for` + oldId := rawState["id"].(string) + if strings.Contains(oldId, "Microsoft.DBForPostgreSQL") { + modifiedId := strings.ReplaceAll(oldId, "Microsoft.DBForPostgreSQL", "Microsoft.DBforPostgreSQL") + + newId, err := servers.ParseServerID(modifiedId) + if err != nil { + return rawState, err + } + log.Printf("[DEBUG] Updating ID from %q to %q", oldId, newId) + rawState["id"] = newId.ID() + } + + return rawState, nil + } +} diff --git a/internal/services/postgres/parse/configuration.go b/internal/services/postgres/parse/configuration.go deleted file mode 100644 index 69dee5a0be6d..000000000000 --- a/internal/services/postgres/parse/configuration.go +++ /dev/null @@ -1,75 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - "strings" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -type ConfigurationId struct { - SubscriptionId string - ResourceGroup string - ServerName string - Name string -} - -func NewConfigurationID(subscriptionId, resourceGroup, serverName, name string) ConfigurationId { - return ConfigurationId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourceGroup, - ServerName: serverName, - Name: name, - } -} - -func (id ConfigurationId) String() string { - segments := []string{ - fmt.Sprintf("Name %q", id.Name), - fmt.Sprintf("Server Name %q", id.ServerName), - fmt.Sprintf("Resource Group %q", id.ResourceGroup), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Configuration", segmentsStr) -} - -func (id ConfigurationId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.DBforPostgreSQL/servers/%s/configurations/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.ServerName, id.Name) -} - -// ConfigurationID parses a Configuration ID into an ConfigurationId struct -func ConfigurationID(input string) (*ConfigurationId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := ConfigurationId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - if resourceId.ServerName, err = id.PopSegment("servers"); err != nil { - return nil, err - } - if resourceId.Name, err = id.PopSegment("configurations"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/postgres/parse/configuration_test.go b/internal/services/postgres/parse/configuration_test.go deleted file mode 100644 index cc5d86470471..000000000000 --- a/internal/services/postgres/parse/configuration_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "testing" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -var _ resourceids.Id = ConfigurationId{} - -func TestConfigurationIDFormatter(t *testing.T) { - actual := NewConfigurationID("12345678-1234-9876-4563-123456789012", "resGroup1", "server1", "configuration1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/configurations/configuration1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestConfigurationID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *ConfigurationId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - - { - // missing ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/", - Error: true, - }, - - { - // missing value for ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/", - Error: true, - }, - - { - // missing Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/", - Error: true, - }, - - { - // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/configurations/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/configurations/configuration1", - Expected: &ConfigurationId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - ServerName: "server1", - Name: "configuration1", - }, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.DBFORPOSTGRESQL/SERVERS/SERVER1/CONFIGURATIONS/CONFIGURATION1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := ConfigurationID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - if actual.ServerName != v.Expected.ServerName { - t.Fatalf("Expected %q but got %q for ServerName", v.Expected.ServerName, actual.ServerName) - } - if actual.Name != v.Expected.Name { - t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name) - } - } -} diff --git a/internal/services/postgres/parse/database.go b/internal/services/postgres/parse/database.go deleted file mode 100644 index 33e2dbf57aa3..000000000000 --- a/internal/services/postgres/parse/database.go +++ /dev/null @@ -1,75 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - "strings" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -type DatabaseId struct { - SubscriptionId string - ResourceGroup string - ServerName string - Name string -} - -func NewDatabaseID(subscriptionId, resourceGroup, serverName, name string) DatabaseId { - return DatabaseId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourceGroup, - ServerName: serverName, - Name: name, - } -} - -func (id DatabaseId) String() string { - segments := []string{ - fmt.Sprintf("Name %q", id.Name), - fmt.Sprintf("Server Name %q", id.ServerName), - fmt.Sprintf("Resource Group %q", id.ResourceGroup), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Database", segmentsStr) -} - -func (id DatabaseId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.DBforPostgreSQL/servers/%s/databases/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.ServerName, id.Name) -} - -// DatabaseID parses a Database ID into an DatabaseId struct -func DatabaseID(input string) (*DatabaseId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := DatabaseId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - if resourceId.ServerName, err = id.PopSegment("servers"); err != nil { - return nil, err - } - if resourceId.Name, err = id.PopSegment("databases"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/postgres/parse/database_test.go b/internal/services/postgres/parse/database_test.go deleted file mode 100644 index 944f54622b6f..000000000000 --- a/internal/services/postgres/parse/database_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "testing" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -var _ resourceids.Id = DatabaseId{} - -func TestDatabaseIDFormatter(t *testing.T) { - actual := NewDatabaseID("12345678-1234-9876-4563-123456789012", "resGroup1", "server1", "database1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/databases/database1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestDatabaseID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *DatabaseId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - - { - // missing ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/", - Error: true, - }, - - { - // missing value for ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/", - Error: true, - }, - - { - // missing Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/", - Error: true, - }, - - { - // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/databases/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/databases/database1", - Expected: &DatabaseId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - ServerName: "server1", - Name: "database1", - }, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.DBFORPOSTGRESQL/SERVERS/SERVER1/DATABASES/DATABASE1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := DatabaseID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - if actual.ServerName != v.Expected.ServerName { - t.Fatalf("Expected %q but got %q for ServerName", v.Expected.ServerName, actual.ServerName) - } - if actual.Name != v.Expected.Name { - t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name) - } - } -} diff --git a/internal/services/postgres/parse/firewall_rule.go b/internal/services/postgres/parse/firewall_rule.go deleted file mode 100644 index d18754cb95dd..000000000000 --- a/internal/services/postgres/parse/firewall_rule.go +++ /dev/null @@ -1,75 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - "strings" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -type FirewallRuleId struct { - SubscriptionId string - ResourceGroup string - ServerName string - Name string -} - -func NewFirewallRuleID(subscriptionId, resourceGroup, serverName, name string) FirewallRuleId { - return FirewallRuleId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourceGroup, - ServerName: serverName, - Name: name, - } -} - -func (id FirewallRuleId) String() string { - segments := []string{ - fmt.Sprintf("Name %q", id.Name), - fmt.Sprintf("Server Name %q", id.ServerName), - fmt.Sprintf("Resource Group %q", id.ResourceGroup), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Firewall Rule", segmentsStr) -} - -func (id FirewallRuleId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.DBforPostgreSQL/servers/%s/firewallRules/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.ServerName, id.Name) -} - -// FirewallRuleID parses a FirewallRule ID into an FirewallRuleId struct -func FirewallRuleID(input string) (*FirewallRuleId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := FirewallRuleId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - if resourceId.ServerName, err = id.PopSegment("servers"); err != nil { - return nil, err - } - if resourceId.Name, err = id.PopSegment("firewallRules"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/postgres/parse/firewall_rule_test.go b/internal/services/postgres/parse/firewall_rule_test.go deleted file mode 100644 index 9f8e0caf1986..000000000000 --- a/internal/services/postgres/parse/firewall_rule_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "testing" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -var _ resourceids.Id = FirewallRuleId{} - -func TestFirewallRuleIDFormatter(t *testing.T) { - actual := NewFirewallRuleID("12345678-1234-9876-4563-123456789012", "resGroup1", "server1", "firewallRule1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/firewallRules/firewallRule1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestFirewallRuleID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *FirewallRuleId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - - { - // missing ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/", - Error: true, - }, - - { - // missing value for ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/", - Error: true, - }, - - { - // missing Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/", - Error: true, - }, - - { - // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/firewallRules/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/firewallRules/firewallRule1", - Expected: &FirewallRuleId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - ServerName: "server1", - Name: "firewallRule1", - }, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.DBFORPOSTGRESQL/SERVERS/SERVER1/FIREWALLRULES/FIREWALLRULE1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := FirewallRuleID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - if actual.ServerName != v.Expected.ServerName { - t.Fatalf("Expected %q but got %q for ServerName", v.Expected.ServerName, actual.ServerName) - } - if actual.Name != v.Expected.Name { - t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name) - } - } -} diff --git a/internal/services/postgres/parse/flexible_server.go b/internal/services/postgres/parse/flexible_server.go deleted file mode 100644 index ae13a5c53a30..000000000000 --- a/internal/services/postgres/parse/flexible_server.go +++ /dev/null @@ -1,69 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - "strings" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -type FlexibleServerId struct { - SubscriptionId string - ResourceGroup string - Name string -} - -func NewFlexibleServerID(subscriptionId, resourceGroup, name string) FlexibleServerId { - return FlexibleServerId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourceGroup, - Name: name, - } -} - -func (id FlexibleServerId) String() string { - segments := []string{ - fmt.Sprintf("Name %q", id.Name), - fmt.Sprintf("Resource Group %q", id.ResourceGroup), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Flexible Server", segmentsStr) -} - -func (id FlexibleServerId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.DBforPostgreSQL/flexibleServers/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.Name) -} - -// FlexibleServerID parses a FlexibleServer ID into an FlexibleServerId struct -func FlexibleServerID(input string) (*FlexibleServerId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := FlexibleServerId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - if resourceId.Name, err = id.PopSegment("flexibleServers"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/postgres/parse/flexible_server_configuration.go b/internal/services/postgres/parse/flexible_server_configuration.go deleted file mode 100644 index 8667dc68fa20..000000000000 --- a/internal/services/postgres/parse/flexible_server_configuration.go +++ /dev/null @@ -1,75 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - "strings" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -type FlexibleServerConfigurationId struct { - SubscriptionId string - ResourceGroup string - FlexibleServerName string - ConfigurationName string -} - -func NewFlexibleServerConfigurationID(subscriptionId, resourceGroup, flexibleServerName, configurationName string) FlexibleServerConfigurationId { - return FlexibleServerConfigurationId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourceGroup, - FlexibleServerName: flexibleServerName, - ConfigurationName: configurationName, - } -} - -func (id FlexibleServerConfigurationId) String() string { - segments := []string{ - fmt.Sprintf("Configuration Name %q", id.ConfigurationName), - fmt.Sprintf("Flexible Server Name %q", id.FlexibleServerName), - fmt.Sprintf("Resource Group %q", id.ResourceGroup), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Flexible Server Configuration", segmentsStr) -} - -func (id FlexibleServerConfigurationId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.DBforPostgreSQL/flexibleServers/%s/configurations/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.FlexibleServerName, id.ConfigurationName) -} - -// FlexibleServerConfigurationID parses a FlexibleServerConfiguration ID into an FlexibleServerConfigurationId struct -func FlexibleServerConfigurationID(input string) (*FlexibleServerConfigurationId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := FlexibleServerConfigurationId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - if resourceId.FlexibleServerName, err = id.PopSegment("flexibleServers"); err != nil { - return nil, err - } - if resourceId.ConfigurationName, err = id.PopSegment("configurations"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/postgres/parse/flexible_server_configuration_test.go b/internal/services/postgres/parse/flexible_server_configuration_test.go deleted file mode 100644 index bd0adcadb08d..000000000000 --- a/internal/services/postgres/parse/flexible_server_configuration_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "testing" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -var _ resourceids.Id = FlexibleServerConfigurationId{} - -func TestFlexibleServerConfigurationIDFormatter(t *testing.T) { - actual := NewFlexibleServerConfigurationID("12345678-1234-9876-4563-123456789012", "resGroup1", "flexibleServer1", "configuration1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/flexibleServer1/configurations/configuration1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestFlexibleServerConfigurationID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *FlexibleServerConfigurationId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - - { - // missing FlexibleServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/", - Error: true, - }, - - { - // missing value for FlexibleServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/", - Error: true, - }, - - { - // missing ConfigurationName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/flexibleServer1/", - Error: true, - }, - - { - // missing value for ConfigurationName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/flexibleServer1/configurations/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/flexibleServer1/configurations/configuration1", - Expected: &FlexibleServerConfigurationId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - FlexibleServerName: "flexibleServer1", - ConfigurationName: "configuration1", - }, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.DBFORPOSTGRESQL/FLEXIBLESERVERS/FLEXIBLESERVER1/CONFIGURATIONS/CONFIGURATION1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := FlexibleServerConfigurationID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - if actual.FlexibleServerName != v.Expected.FlexibleServerName { - t.Fatalf("Expected %q but got %q for FlexibleServerName", v.Expected.FlexibleServerName, actual.FlexibleServerName) - } - if actual.ConfigurationName != v.Expected.ConfigurationName { - t.Fatalf("Expected %q but got %q for ConfigurationName", v.Expected.ConfigurationName, actual.ConfigurationName) - } - } -} diff --git a/internal/services/postgres/parse/flexible_server_database.go b/internal/services/postgres/parse/flexible_server_database.go deleted file mode 100644 index 35515795781f..000000000000 --- a/internal/services/postgres/parse/flexible_server_database.go +++ /dev/null @@ -1,75 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - "strings" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -type FlexibleServerDatabaseId struct { - SubscriptionId string - ResourceGroup string - FlexibleServerName string - DatabaseName string -} - -func NewFlexibleServerDatabaseID(subscriptionId, resourceGroup, flexibleServerName, databaseName string) FlexibleServerDatabaseId { - return FlexibleServerDatabaseId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourceGroup, - FlexibleServerName: flexibleServerName, - DatabaseName: databaseName, - } -} - -func (id FlexibleServerDatabaseId) String() string { - segments := []string{ - fmt.Sprintf("Database Name %q", id.DatabaseName), - fmt.Sprintf("Flexible Server Name %q", id.FlexibleServerName), - fmt.Sprintf("Resource Group %q", id.ResourceGroup), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Flexible Server Database", segmentsStr) -} - -func (id FlexibleServerDatabaseId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.DBforPostgreSQL/flexibleServers/%s/databases/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.FlexibleServerName, id.DatabaseName) -} - -// FlexibleServerDatabaseID parses a FlexibleServerDatabase ID into an FlexibleServerDatabaseId struct -func FlexibleServerDatabaseID(input string) (*FlexibleServerDatabaseId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := FlexibleServerDatabaseId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - if resourceId.FlexibleServerName, err = id.PopSegment("flexibleServers"); err != nil { - return nil, err - } - if resourceId.DatabaseName, err = id.PopSegment("databases"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/postgres/parse/flexible_server_database_test.go b/internal/services/postgres/parse/flexible_server_database_test.go deleted file mode 100644 index ca6f4d64eb8d..000000000000 --- a/internal/services/postgres/parse/flexible_server_database_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "testing" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -var _ resourceids.Id = FlexibleServerDatabaseId{} - -func TestFlexibleServerDatabaseIDFormatter(t *testing.T) { - actual := NewFlexibleServerDatabaseID("12345678-1234-9876-4563-123456789012", "resGroup1", "flexibleServer1", "database1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/flexibleServer1/databases/database1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestFlexibleServerDatabaseID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *FlexibleServerDatabaseId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - - { - // missing FlexibleServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/", - Error: true, - }, - - { - // missing value for FlexibleServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/", - Error: true, - }, - - { - // missing DatabaseName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/flexibleServer1/", - Error: true, - }, - - { - // missing value for DatabaseName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/flexibleServer1/databases/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/flexibleServer1/databases/database1", - Expected: &FlexibleServerDatabaseId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - FlexibleServerName: "flexibleServer1", - DatabaseName: "database1", - }, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.DBFORPOSTGRESQL/FLEXIBLESERVERS/FLEXIBLESERVER1/DATABASES/DATABASE1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := FlexibleServerDatabaseID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - if actual.FlexibleServerName != v.Expected.FlexibleServerName { - t.Fatalf("Expected %q but got %q for FlexibleServerName", v.Expected.FlexibleServerName, actual.FlexibleServerName) - } - if actual.DatabaseName != v.Expected.DatabaseName { - t.Fatalf("Expected %q but got %q for DatabaseName", v.Expected.DatabaseName, actual.DatabaseName) - } - } -} diff --git a/internal/services/postgres/parse/flexible_server_firewall_rule.go b/internal/services/postgres/parse/flexible_server_firewall_rule.go deleted file mode 100644 index 7a3d935c4c56..000000000000 --- a/internal/services/postgres/parse/flexible_server_firewall_rule.go +++ /dev/null @@ -1,75 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - "strings" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -type FlexibleServerFirewallRuleId struct { - SubscriptionId string - ResourceGroup string - FlexibleServerName string - FirewallRuleName string -} - -func NewFlexibleServerFirewallRuleID(subscriptionId, resourceGroup, flexibleServerName, firewallRuleName string) FlexibleServerFirewallRuleId { - return FlexibleServerFirewallRuleId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourceGroup, - FlexibleServerName: flexibleServerName, - FirewallRuleName: firewallRuleName, - } -} - -func (id FlexibleServerFirewallRuleId) String() string { - segments := []string{ - fmt.Sprintf("Firewall Rule Name %q", id.FirewallRuleName), - fmt.Sprintf("Flexible Server Name %q", id.FlexibleServerName), - fmt.Sprintf("Resource Group %q", id.ResourceGroup), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Flexible Server Firewall Rule", segmentsStr) -} - -func (id FlexibleServerFirewallRuleId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.DBforPostgreSQL/flexibleServers/%s/firewallRules/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.FlexibleServerName, id.FirewallRuleName) -} - -// FlexibleServerFirewallRuleID parses a FlexibleServerFirewallRule ID into an FlexibleServerFirewallRuleId struct -func FlexibleServerFirewallRuleID(input string) (*FlexibleServerFirewallRuleId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := FlexibleServerFirewallRuleId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - if resourceId.FlexibleServerName, err = id.PopSegment("flexibleServers"); err != nil { - return nil, err - } - if resourceId.FirewallRuleName, err = id.PopSegment("firewallRules"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/postgres/parse/flexible_server_firewall_rule_test.go b/internal/services/postgres/parse/flexible_server_firewall_rule_test.go deleted file mode 100644 index 0f938c5b3074..000000000000 --- a/internal/services/postgres/parse/flexible_server_firewall_rule_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "testing" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -var _ resourceids.Id = FlexibleServerFirewallRuleId{} - -func TestFlexibleServerFirewallRuleIDFormatter(t *testing.T) { - actual := NewFlexibleServerFirewallRuleID("12345678-1234-9876-4563-123456789012", "resGroup1", "flexibleServer1", "firewallRule1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/flexibleServer1/firewallRules/firewallRule1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestFlexibleServerFirewallRuleID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *FlexibleServerFirewallRuleId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - - { - // missing FlexibleServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/", - Error: true, - }, - - { - // missing value for FlexibleServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/", - Error: true, - }, - - { - // missing FirewallRuleName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/flexibleServer1/", - Error: true, - }, - - { - // missing value for FirewallRuleName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/flexibleServer1/firewallRules/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/flexibleServer1/firewallRules/firewallRule1", - Expected: &FlexibleServerFirewallRuleId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - FlexibleServerName: "flexibleServer1", - FirewallRuleName: "firewallRule1", - }, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.DBFORPOSTGRESQL/FLEXIBLESERVERS/FLEXIBLESERVER1/FIREWALLRULES/FIREWALLRULE1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := FlexibleServerFirewallRuleID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - if actual.FlexibleServerName != v.Expected.FlexibleServerName { - t.Fatalf("Expected %q but got %q for FlexibleServerName", v.Expected.FlexibleServerName, actual.FlexibleServerName) - } - if actual.FirewallRuleName != v.Expected.FirewallRuleName { - t.Fatalf("Expected %q but got %q for FirewallRuleName", v.Expected.FirewallRuleName, actual.FirewallRuleName) - } - } -} diff --git a/internal/services/postgres/parse/flexible_server_test.go b/internal/services/postgres/parse/flexible_server_test.go deleted file mode 100644 index 9902bf014fcc..000000000000 --- a/internal/services/postgres/parse/flexible_server_test.go +++ /dev/null @@ -1,112 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "testing" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -var _ resourceids.Id = FlexibleServerId{} - -func TestFlexibleServerIDFormatter(t *testing.T) { - actual := NewFlexibleServerID("12345678-1234-9876-4563-123456789012", "resGroup1", "flexibleServer1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/flexibleServer1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestFlexibleServerID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *FlexibleServerId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - - { - // missing Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/", - Error: true, - }, - - { - // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/flexibleServer1", - Expected: &FlexibleServerId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - Name: "flexibleServer1", - }, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.DBFORPOSTGRESQL/FLEXIBLESERVERS/FLEXIBLESERVER1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := FlexibleServerID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - if actual.Name != v.Expected.Name { - t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name) - } - } -} diff --git a/internal/services/postgres/parse/server.go b/internal/services/postgres/parse/server.go deleted file mode 100644 index 17dc8a9e70c8..000000000000 --- a/internal/services/postgres/parse/server.go +++ /dev/null @@ -1,69 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - "strings" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -type ServerId struct { - SubscriptionId string - ResourceGroup string - Name string -} - -func NewServerID(subscriptionId, resourceGroup, name string) ServerId { - return ServerId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourceGroup, - Name: name, - } -} - -func (id ServerId) String() string { - segments := []string{ - fmt.Sprintf("Name %q", id.Name), - fmt.Sprintf("Resource Group %q", id.ResourceGroup), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Server", segmentsStr) -} - -func (id ServerId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.DBforPostgreSQL/servers/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.Name) -} - -// ServerID parses a Server ID into an ServerId struct -func ServerID(input string) (*ServerId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := ServerId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - if resourceId.Name, err = id.PopSegment("servers"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/postgres/parse/server_key.go b/internal/services/postgres/parse/server_key.go deleted file mode 100644 index 31da5fcb0ec1..000000000000 --- a/internal/services/postgres/parse/server_key.go +++ /dev/null @@ -1,75 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - "strings" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -type ServerKeyId struct { - SubscriptionId string - ResourceGroup string - ServerName string - KeyName string -} - -func NewServerKeyID(subscriptionId, resourceGroup, serverName, keyName string) ServerKeyId { - return ServerKeyId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourceGroup, - ServerName: serverName, - KeyName: keyName, - } -} - -func (id ServerKeyId) String() string { - segments := []string{ - fmt.Sprintf("Key Name %q", id.KeyName), - fmt.Sprintf("Server Name %q", id.ServerName), - fmt.Sprintf("Resource Group %q", id.ResourceGroup), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Server Key", segmentsStr) -} - -func (id ServerKeyId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.DBforPostgreSQL/servers/%s/keys/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.ServerName, id.KeyName) -} - -// ServerKeyID parses a ServerKey ID into an ServerKeyId struct -func ServerKeyID(input string) (*ServerKeyId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := ServerKeyId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - if resourceId.ServerName, err = id.PopSegment("servers"); err != nil { - return nil, err - } - if resourceId.KeyName, err = id.PopSegment("keys"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/postgres/parse/server_key_test.go b/internal/services/postgres/parse/server_key_test.go deleted file mode 100644 index 4e4a93c4695f..000000000000 --- a/internal/services/postgres/parse/server_key_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "testing" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -var _ resourceids.Id = ServerKeyId{} - -func TestServerKeyIDFormatter(t *testing.T) { - actual := NewServerKeyID("12345678-1234-9876-4563-123456789012", "resGroup1", "server1", "key1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/keys/key1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestServerKeyID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *ServerKeyId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - - { - // missing ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/", - Error: true, - }, - - { - // missing value for ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/", - Error: true, - }, - - { - // missing KeyName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/", - Error: true, - }, - - { - // missing value for KeyName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/keys/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/keys/key1", - Expected: &ServerKeyId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - ServerName: "server1", - KeyName: "key1", - }, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.DBFORPOSTGRESQL/SERVERS/SERVER1/KEYS/KEY1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := ServerKeyID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - if actual.ServerName != v.Expected.ServerName { - t.Fatalf("Expected %q but got %q for ServerName", v.Expected.ServerName, actual.ServerName) - } - if actual.KeyName != v.Expected.KeyName { - t.Fatalf("Expected %q but got %q for KeyName", v.Expected.KeyName, actual.KeyName) - } - } -} diff --git a/internal/services/postgres/parse/server_test.go b/internal/services/postgres/parse/server_test.go deleted file mode 100644 index 7b13b5a04921..000000000000 --- a/internal/services/postgres/parse/server_test.go +++ /dev/null @@ -1,112 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "testing" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -var _ resourceids.Id = ServerId{} - -func TestServerIDFormatter(t *testing.T) { - actual := NewServerID("12345678-1234-9876-4563-123456789012", "resGroup1", "server1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestServerID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *ServerId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - - { - // missing Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/", - Error: true, - }, - - { - // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1", - Expected: &ServerId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - Name: "server1", - }, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.DBFORPOSTGRESQL/SERVERS/SERVER1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := ServerID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - if actual.Name != v.Expected.Name { - t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name) - } - } -} diff --git a/internal/services/postgres/parse/virtual_network_rule.go b/internal/services/postgres/parse/virtual_network_rule.go deleted file mode 100644 index f080046b235b..000000000000 --- a/internal/services/postgres/parse/virtual_network_rule.go +++ /dev/null @@ -1,75 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - "strings" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -type VirtualNetworkRuleId struct { - SubscriptionId string - ResourceGroup string - ServerName string - Name string -} - -func NewVirtualNetworkRuleID(subscriptionId, resourceGroup, serverName, name string) VirtualNetworkRuleId { - return VirtualNetworkRuleId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourceGroup, - ServerName: serverName, - Name: name, - } -} - -func (id VirtualNetworkRuleId) String() string { - segments := []string{ - fmt.Sprintf("Name %q", id.Name), - fmt.Sprintf("Server Name %q", id.ServerName), - fmt.Sprintf("Resource Group %q", id.ResourceGroup), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Virtual Network Rule", segmentsStr) -} - -func (id VirtualNetworkRuleId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.DBforPostgreSQL/servers/%s/virtualNetworkRules/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.ServerName, id.Name) -} - -// VirtualNetworkRuleID parses a VirtualNetworkRule ID into an VirtualNetworkRuleId struct -func VirtualNetworkRuleID(input string) (*VirtualNetworkRuleId, error) { - id, err := resourceids.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := VirtualNetworkRuleId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - if resourceId.ServerName, err = id.PopSegment("servers"); err != nil { - return nil, err - } - if resourceId.Name, err = id.PopSegment("virtualNetworkRules"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/internal/services/postgres/parse/virtual_network_rule_test.go b/internal/services/postgres/parse/virtual_network_rule_test.go deleted file mode 100644 index e0a631283c16..000000000000 --- a/internal/services/postgres/parse/virtual_network_rule_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "testing" - - "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" -) - -var _ resourceids.Id = VirtualNetworkRuleId{} - -func TestVirtualNetworkRuleIDFormatter(t *testing.T) { - actual := NewVirtualNetworkRuleID("12345678-1234-9876-4563-123456789012", "resGroup1", "server1", "virtualNetworkRule1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/virtualNetworkRules/virtualNetworkRule1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestVirtualNetworkRuleID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *VirtualNetworkRuleId - }{ - - { - // empty - Input: "", - Error: true, - }, - - { - // missing SubscriptionId - Input: "/", - Error: true, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Error: true, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - - { - // missing ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/", - Error: true, - }, - - { - // missing value for ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/", - Error: true, - }, - - { - // missing Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/", - Error: true, - }, - - { - // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/virtualNetworkRules/", - Error: true, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/virtualNetworkRules/virtualNetworkRule1", - Expected: &VirtualNetworkRuleId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resGroup1", - ServerName: "server1", - Name: "virtualNetworkRule1", - }, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.DBFORPOSTGRESQL/SERVERS/SERVER1/VIRTUALNETWORKRULES/VIRTUALNETWORKRULE1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := VirtualNetworkRuleID(v.Input) - if err != nil { - if v.Error { - continue - } - - t.Fatalf("Expect a value but got an error: %s", err) - } - if v.Error { - t.Fatal("Expect an error but didn't get one") - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - if actual.ServerName != v.Expected.ServerName { - t.Fatalf("Expected %q but got %q for ServerName", v.Expected.ServerName, actual.ServerName) - } - if actual.Name != v.Expected.Name { - t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name) - } - } -} diff --git a/internal/services/postgres/postgresql_aad_administrator_resource.go b/internal/services/postgres/postgresql_aad_administrator_resource.go index 6633b2828240..f511851b2504 100644 --- a/internal/services/postgres/postgresql_aad_administrator_resource.go +++ b/internal/services/postgres/postgresql_aad_administrator_resource.go @@ -5,17 +5,16 @@ import ( "log" "time" - "github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2020-01-01/postgresql" - "github.com/gofrs/uuid" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/serveradministrators" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/migration" "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" - "github.com/hashicorp/terraform-provider-azurerm/utils" ) func resourcePostgreSQLAdministrator() *pluginsdk.Resource { @@ -25,7 +24,7 @@ func resourcePostgreSQLAdministrator() *pluginsdk.Resource { Update: resourcePostgreSQLAdministratorCreateUpdate, Delete: resourcePostgreSQLAdministratorDelete, Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - _, err := parse.AzureActiveDirectoryAdministratorID(id) + _, err := serveradministrators.ParseServerID(id) return err }), @@ -36,6 +35,11 @@ func resourcePostgreSQLAdministrator() *pluginsdk.Resource { Delete: pluginsdk.DefaultTimeout(30 * time.Minute), }, + SchemaVersion: 1, + StateUpgraders: pluginsdk.StateUpgrades(map[int]pluginsdk.StateUpgrade{ + 0: migration.PostgresqlAADAdministratorV0ToV1{}, + }), + Schema: map[string]*pluginsdk.Schema{ "server_name": { Type: pluginsdk.TypeString, @@ -72,40 +76,32 @@ func resourcePostgreSQLAdministratorCreateUpdate(d *pluginsdk.ResourceData, meta ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - login := d.Get("login").(string) - objectId := uuid.FromStringOrNil(d.Get("object_id").(string)) - tenantId := uuid.FromStringOrNil(d.Get("tenant_id").(string)) - - id := parse.NewAzureActiveDirectoryAdministratorID(subscriptionId, d.Get("resource_group_name").(string), d.Get("server_name").(string), "activeDirectory") + id := serveradministrators.NewServerID(subscriptionId, d.Get("resource_group_name").(string), d.Get("server_name").(string)) if d.IsNewResource() { - existing, err := client.Get(ctx, id.ResourceGroup, id.ServerName) + existing, err := client.Get(ctx, id) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return fmt.Errorf("checking for presence of existing %s: %+v", id, err) } } - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return tf.ImportAsExistsError("azurerm_postgresql_active_directory_administrator", id.ID()) } } - parameters := postgresql.ServerAdministratorResource{ - ServerAdministratorProperties: &postgresql.ServerAdministratorProperties{ - AdministratorType: utils.String("ActiveDirectory"), - Login: utils.String(login), - Sid: &objectId, - TenantID: &tenantId, + parameters := serveradministrators.ServerAdministratorResource{ + Properties: &serveradministrators.ServerAdministratorProperties{ + AdministratorType: serveradministrators.AdministratorTypeActiveDirectory, + Login: d.Get("login").(string), + Sid: d.Get("object_id").(string), + TenantId: d.Get("tenant_id").(string), }, } - future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.ServerName, parameters) - if err != nil { + if err := client.CreateOrUpdateThenPoll(ctx, id, parameters); err != nil { return fmt.Errorf("creating/updating %s: %+v", id, err) } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for create/update of %s: %+v", id, err) - } d.SetId(id.ID()) return nil @@ -116,14 +112,14 @@ func resourcePostgreSQLAdministratorRead(d *pluginsdk.ResourceData, meta interfa ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.AzureActiveDirectoryAdministratorID(d.Id()) + id, err := serveradministrators.ParseServerID(d.Id()) if err != nil { return err } - resp, err := client.Get(ctx, id.ResourceGroup, id.ServerName) + resp, err := client.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { log.Printf("[INFO] %s was not found - removing from state", *id) d.SetId("") return nil @@ -132,23 +128,16 @@ func resourcePostgreSQLAdministratorRead(d *pluginsdk.ResourceData, meta interfa return fmt.Errorf("retrieving %s: %+v", *id, err) } - d.Set("resource_group_name", id.ResourceGroup) + d.Set("resource_group_name", id.ResourceGroupName) d.Set("server_name", id.ServerName) - if props := resp.ServerAdministratorProperties; props != nil { - d.Set("login", props.Login) - - objectId := "" - if props.Sid != nil { - objectId = props.Sid.String() + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("login", props.Login) + d.Set("object_id", props.Sid) + d.Set("tenant_id", props.TenantId) } - d.Set("object_id", objectId) - tenantId := "" - if props.TenantID != nil { - tenantId = props.TenantID.String() - } - d.Set("tenant_id", tenantId) } return nil @@ -159,18 +148,14 @@ func resourcePostgreSQLAdministratorDelete(d *pluginsdk.ResourceData, meta inter ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.AzureActiveDirectoryAdministratorID(d.Id()) + id, err := serveradministrators.ParseServerID(d.Id()) if err != nil { return err } - future, err := client.Delete(ctx, id.ResourceGroup, id.ServerName) - if err != nil { + if err := client.DeleteThenPoll(ctx, *id); err != nil { return fmt.Errorf("deleting %s: %+v", *id, err) } - if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for deletion of %s: %+v", *id, err) - } return nil } diff --git a/internal/services/postgres/postgresql_aad_administrator_resource_test.go b/internal/services/postgres/postgresql_aad_administrator_resource_test.go index eecf8310c1f8..f1aa60ba97ff 100644 --- a/internal/services/postgres/postgresql_aad_administrator_resource_test.go +++ b/internal/services/postgres/postgresql_aad_administrator_resource_test.go @@ -5,10 +5,11 @@ import ( "fmt" "testing" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/serveradministrators" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -70,26 +71,26 @@ func TestAccPostgreSqlAdministrator_disappears(t *testing.T) { } func (r PostgreSqlAdministratorResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.AzureActiveDirectoryAdministratorID(state.ID) + id, err := serveradministrators.ParseServerID(state.ID) if err != nil { return nil, err } - resp, err := clients.Postgres.ServerAdministratorsClient.Get(ctx, id.ResourceGroup, id.ServerName) + resp, err := clients.Postgres.ServerAdministratorsClient.Get(ctx, *id) if err != nil { return nil, fmt.Errorf("reading Postgresql AAD Administrator (%s): %+v", id.String(), err) } - return utils.Bool(resp.ID != nil), nil + return utils.Bool(resp.Model != nil), nil } func (r PostgreSqlAdministratorResource) Destroy(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.AzureActiveDirectoryAdministratorID(state.ID) + id, err := serveradministrators.ParseServerID(state.ID) if err != nil { return nil, err } - if _, err := client.Postgres.ServerAdministratorsClient.Delete(ctx, id.ResourceGroup, id.ServerName); err != nil { + if _, err := client.Postgres.ServerAdministratorsClient.Delete(ctx, *id); err != nil { return nil, fmt.Errorf("deleting Postgresql AAD Administrator (%s): %+v", id.String(), err) } diff --git a/internal/services/postgres/postgresql_configuration_resource.go b/internal/services/postgres/postgresql_configuration_resource.go index d872bfcbf28b..0b55f229df81 100644 --- a/internal/services/postgres/postgresql_configuration_resource.go +++ b/internal/services/postgres/postgresql_configuration_resource.go @@ -5,11 +5,11 @@ import ( "log" "time" - "github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2020-01-01/postgresql" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/configurations" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/locks" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" @@ -22,7 +22,7 @@ func resourcePostgreSQLConfiguration() *pluginsdk.Resource { Read: resourcePostgreSQLConfigurationRead, Delete: resourcePostgreSQLConfigurationDelete, Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - _, err := parse.ConfigurationID(id) + _, err := configurations.ParseConfigurationID(id) return err }), @@ -64,27 +64,22 @@ func resourcePostgreSQLConfigurationCreateUpdate(d *pluginsdk.ResourceData, meta ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - id := parse.NewConfigurationID(subscriptionId, d.Get("resource_group_name").(string), d.Get("server_name").(string), d.Get("name").(string)) + id := configurations.NewConfigurationID(subscriptionId, d.Get("resource_group_name").(string), d.Get("server_name").(string), d.Get("name").(string)) // TODO: support RequiresImport - this is possible to tell if it's the non-default value from the API (see Delete) locks.ByName(id.ServerName, postgreSQLServerResourceName) defer locks.UnlockByName(id.ServerName, postgreSQLServerResourceName) - properties := postgresql.Configuration{ - ConfigurationProperties: &postgresql.ConfigurationProperties{ + properties := configurations.Configuration{ + Properties: &configurations.ConfigurationProperties{ Value: utils.String(d.Get("value").(string)), }, } - future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.ServerName, id.Name, properties) - if err != nil { + if err := client.CreateOrUpdateThenPoll(ctx, id, properties); err != nil { return fmt.Errorf("creating/updating %s: %+v", id, err) } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for create/update of %s: %+v", id, err) - } - d.SetId(id.ID()) return resourcePostgreSQLConfigurationRead(d, meta) } @@ -94,14 +89,14 @@ func resourcePostgreSQLConfigurationRead(d *pluginsdk.ResourceData, meta interfa ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.ConfigurationID(d.Id()) + id, err := configurations.ParseConfigurationID(d.Id()) if err != nil { return err } - resp, err := client.Get(ctx, id.ResourceGroup, id.ServerName, id.Name) + resp, err := client.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { log.Printf("[WARN] %s was not found - removing from state", *id) d.SetId("") return nil @@ -110,12 +105,14 @@ func resourcePostgreSQLConfigurationRead(d *pluginsdk.ResourceData, meta interfa return fmt.Errorf("retrieving %s: %+v", *id, err) } - d.Set("name", id.Name) + d.Set("name", id.ConfigurationName) d.Set("server_name", id.ServerName) - d.Set("resource_group_name", id.ResourceGroup) + d.Set("resource_group_name", id.ResourceGroupName) - if props := resp.ConfigurationProperties; props != nil { - d.Set("value", props.Value) + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("value", props.Value) + } } return nil @@ -126,7 +123,7 @@ func resourcePostgreSQLConfigurationDelete(d *pluginsdk.ResourceData, meta inter ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.ConfigurationID(d.Id()) + id, err := configurations.ParseConfigurationID(d.Id()) if err != nil { return err } @@ -135,26 +132,26 @@ func resourcePostgreSQLConfigurationDelete(d *pluginsdk.ResourceData, meta inter defer locks.UnlockByName(id.ServerName, postgreSQLServerResourceName) // "delete" = resetting this to the default value - resp, err := client.Get(ctx, id.ResourceGroup, id.ServerName, id.Name) + resp, err := client.Get(ctx, *id) if err != nil { - return fmt.Errorf("retrieving Postgresql Configuration '%s': %+v", id.Name, err) + return fmt.Errorf("retrieving %s: %+v", id, err) } - properties := postgresql.Configuration{ - ConfigurationProperties: &postgresql.ConfigurationProperties{ + defaultValue := "" + if resp.Model != nil && resp.Model.Properties != nil && resp.Model.Properties.DefaultValue != nil { + defaultValue = *resp.Model.Properties.DefaultValue + } + + properties := configurations.Configuration{ + Properties: &configurations.ConfigurationProperties{ // we can alternatively set `source: "system-default"` - Value: resp.DefaultValue, + Value: &defaultValue, }, } - future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.ServerName, id.Name, properties) - if err != nil { + if err = client.CreateOrUpdateThenPoll(ctx, *id, properties); err != nil { return fmt.Errorf("resetting %s to it's default value: %+v", *id, err) } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for %s to reset to it's default value: %+v", *id, err) - } - return nil } diff --git a/internal/services/postgres/postgresql_configuration_resource_test.go b/internal/services/postgres/postgresql_configuration_resource_test.go index 519d4170784b..1f51289eff4a 100644 --- a/internal/services/postgres/postgresql_configuration_resource_test.go +++ b/internal/services/postgres/postgresql_configuration_resource_test.go @@ -5,10 +5,11 @@ import ( "fmt" "testing" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/configurations" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -95,24 +96,28 @@ func TestAccPostgreSQLConfiguration_multiplePostgreSQLConfigurations(t *testing. func (r PostgreSQLConfigurationResource) checkReset(configurationName string) acceptance.ClientCheckFunc { return func(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) error { - id, err := parse.ServerID(state.Attributes["id"]) + id, err := configurations.ParseServerID(state.Attributes["id"]) if err != nil { return err } - resp, err := clients.Postgres.ConfigurationsClient.Get(ctx, id.ResourceGroup, id.Name, configurationName) + configurationId := configurations.NewConfigurationID(id.SubscriptionId, id.ResourceGroupName, id.ServerName, configurationName) + + resp, err := clients.Postgres.ConfigurationsClient.Get(ctx, configurationId) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { - return fmt.Errorf("Bad: PostgreSQL Configuration %q (server %q resource group: %q) does not exist", configurationName, id.Name, id.ResourceGroup) + if response.WasNotFound(resp.HttpResponse) { + return fmt.Errorf("%s does not exist", id) } return fmt.Errorf("Bad: Get on postgresqlConfigurationsClient: %+v", err) } - actualValue := *resp.Value - defaultValue := *resp.DefaultValue + if resp.Model != nil && resp.Model.Properties != nil { + actualValue := *resp.Model.Properties.Value + defaultValue := *resp.Model.Properties.DefaultValue - if defaultValue != actualValue { - return fmt.Errorf("PostgreSQL Configuration wasn't set to the default value. Expected '%s' - got '%s': \n%+v", defaultValue, actualValue, resp) + if defaultValue != actualValue { + return fmt.Errorf("PostgreSQL Configuration wasn't set to the default value. Expected '%s' - got '%s': \n%+v", defaultValue, actualValue, resp) + } } return nil @@ -121,22 +126,26 @@ func (r PostgreSQLConfigurationResource) checkReset(configurationName string) ac func (r PostgreSQLConfigurationResource) checkValue(value string) acceptance.ClientCheckFunc { return func(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) error { - id, err := parse.ConfigurationID(state.Attributes["id"]) + id, err := configurations.ParseConfigurationID(state.Attributes["id"]) if err != nil { return err } - resp, err := clients.Postgres.ConfigurationsClient.Get(ctx, id.ResourceGroup, id.ServerName, id.Name) + resp, err := clients.Postgres.ConfigurationsClient.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { - return fmt.Errorf("Bad: PostgreSQL Configuration %q (server %q resource group: %q) does not exist", id.Name, id.ServerName, id.ResourceGroup) + if response.WasNotFound(resp.HttpResponse) { + return fmt.Errorf("%s does not exist", id) } return fmt.Errorf("Bad: Get on postgresqlConfigurationsClient: %+v", err) } - if *resp.Value != value { - return fmt.Errorf("PostgreSQL Configuration wasn't set. Expected '%s' - got '%s': \n%+v", value, *resp.Value, resp) + if resp.Model != nil && resp.Model.Properties != nil && resp.Model.Properties.Value != nil { + if *resp.Model.Properties.Value != value { + return fmt.Errorf("PostgreSQL Configuration wasn't set. Expected '%s' - got '%s': \n%+v", value, *resp.Model.Properties.Value, resp) + } + } else { + return fmt.Errorf("bad get on %s", id) } return nil @@ -144,17 +153,17 @@ func (r PostgreSQLConfigurationResource) checkValue(value string) acceptance.Cli } func (t PostgreSQLConfigurationResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.ConfigurationID(state.ID) + id, err := configurations.ParseConfigurationID(state.ID) if err != nil { return nil, err } - resp, err := clients.Postgres.ConfigurationsClient.Get(ctx, id.ResourceGroup, id.ServerName, id.Name) + resp, err := clients.Postgres.ConfigurationsClient.Get(ctx, *id) if err != nil { - return nil, fmt.Errorf("reading Postgresql Configuration (%s): %+v", id.String(), err) + return nil, fmt.Errorf("reading %s: %+v", id, err) } - return utils.Bool(resp.ID != nil), nil + return utils.Bool(resp.Model != nil), nil } func (r PostgreSQLConfigurationResource) backslashQuote(data acceptance.TestData) string { diff --git a/internal/services/postgres/postgresql_database_resource.go b/internal/services/postgres/postgresql_database_resource.go index 31e01422f839..ac051f4eaf7e 100644 --- a/internal/services/postgres/postgresql_database_resource.go +++ b/internal/services/postgres/postgresql_database_resource.go @@ -5,11 +5,12 @@ import ( "log" "time" - "github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2020-01-01/postgresql" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/databases" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/migration" "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/suppress" @@ -23,7 +24,7 @@ func resourcePostgreSQLDatabase() *pluginsdk.Resource { Read: resourcePostgreSQLDatabaseRead, Delete: resourcePostgreSQLDatabaseDelete, Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - _, err := parse.DatabaseID(id) + _, err := databases.ParseDatabaseID(id) return err }), @@ -34,6 +35,11 @@ func resourcePostgreSQLDatabase() *pluginsdk.Resource { Delete: pluginsdk.DefaultTimeout(60 * time.Minute), }, + SchemaVersion: 1, + StateUpgraders: pluginsdk.StateUpgrades(map[int]pluginsdk.StateUpgrade{ + 0: migration.PostgresqlDatabaseV0ToV1{}, + }), + Schema: map[string]*pluginsdk.Schema{ "name": { Type: pluginsdk.TypeString, @@ -73,34 +79,29 @@ func resourcePostgreSQLDatabaseCreate(d *pluginsdk.ResourceData, meta interface{ ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) defer cancel() - id := parse.NewDatabaseID(subscriptionId, d.Get("resource_group_name").(string), d.Get("server_name").(string), d.Get("name").(string)) - existing, err := client.Get(ctx, id.ResourceGroup, id.ServerName, id.Name) + id := databases.NewDatabaseID(subscriptionId, d.Get("resource_group_name").(string), d.Get("server_name").(string), d.Get("name").(string)) + existing, err := client.Get(ctx, id) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return fmt.Errorf("checking for presence of existing %s: %+v", id, err) } } - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return tf.ImportAsExistsError("azurerm_postgresql_database", id.ID()) } - properties := postgresql.Database{ - DatabaseProperties: &postgresql.DatabaseProperties{ + properties := databases.Database{ + Properties: &databases.DatabaseProperties{ Charset: utils.String(d.Get("charset").(string)), Collation: utils.String(d.Get("collation").(string)), }, } - future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.ServerName, id.Name, properties) - if err != nil { + if err = client.CreateOrUpdateThenPoll(ctx, id, properties); err != nil { return fmt.Errorf("creating/updating %s: %+v", id, err) } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for create/update of %s: %+v", id, err) - } - d.SetId(id.ID()) return resourcePostgreSQLDatabaseRead(d, meta) } @@ -110,14 +111,14 @@ func resourcePostgreSQLDatabaseRead(d *pluginsdk.ResourceData, meta interface{}) ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.DatabaseID(d.Id()) + id, err := databases.ParseDatabaseID(d.Id()) if err != nil { return err } - resp, err := client.Get(ctx, id.ResourceGroup, id.ServerName, id.Name) + resp, err := client.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { log.Printf("[WARN] %s was not found - removing from state", *id) d.SetId("") return nil @@ -126,13 +127,15 @@ func resourcePostgreSQLDatabaseRead(d *pluginsdk.ResourceData, meta interface{}) return fmt.Errorf("retrieving %s: %+v", *id, err) } - d.Set("name", id.Name) + d.Set("name", id.DatabaseName) d.Set("server_name", id.ServerName) - d.Set("resource_group_name", id.ResourceGroup) + d.Set("resource_group_name", id.ResourceGroupName) - if props := resp.DatabaseProperties; props != nil { - d.Set("charset", props.Charset) - d.Set("collation", props.Collation) + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("charset", props.Charset) + d.Set("collation", props.Collation) + } } return nil @@ -143,19 +146,14 @@ func resourcePostgreSQLDatabaseDelete(d *pluginsdk.ResourceData, meta interface{ ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.DatabaseID(d.Id()) + id, err := databases.ParseDatabaseID(d.Id()) if err != nil { return err } - future, err := client.Delete(ctx, id.ResourceGroup, id.ServerName, id.Name) - if err != nil { + if err = client.DeleteThenPoll(ctx, *id); err != nil { return fmt.Errorf("deleting %s: %+v", *id, err) } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for deletion of %s: %+v", *id, err) - } - return nil } diff --git a/internal/services/postgres/postgresql_database_resource_test.go b/internal/services/postgres/postgresql_database_resource_test.go index 4c93c28ac247..4e3a0a7ed217 100644 --- a/internal/services/postgres/postgresql_database_resource_test.go +++ b/internal/services/postgres/postgresql_database_resource_test.go @@ -5,10 +5,10 @@ import ( "fmt" "testing" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/databases" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -92,17 +92,17 @@ func TestAccPostgreSQLDatabase_charsetMixedcase(t *testing.T) { } func (t PostgreSQLDatabaseResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.DatabaseID(state.ID) + id, err := databases.ParseDatabaseID(state.ID) if err != nil { return nil, err } - resp, err := clients.Postgres.DatabasesClient.Get(ctx, id.ResourceGroup, id.ServerName, id.Name) + resp, err := clients.Postgres.DatabasesClient.Get(ctx, *id) if err != nil { - return nil, fmt.Errorf("reading Postgresql Database (%s): %+v", id.String(), err) + return nil, fmt.Errorf("reading %s: %+v", id, err) } - return utils.Bool(resp.ID != nil), nil + return utils.Bool(resp.Model != nil), nil } func (PostgreSQLDatabaseResource) basic(data acceptance.TestData) string { diff --git a/internal/services/postgres/postgresql_firewall_rule_resource.go b/internal/services/postgres/postgresql_firewall_rule_resource.go index 075dfb643abc..2dbc7304f92e 100644 --- a/internal/services/postgres/postgresql_firewall_rule_resource.go +++ b/internal/services/postgres/postgresql_firewall_rule_resource.go @@ -6,16 +6,15 @@ import ( "regexp" "time" - "github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2020-01-01/postgresql" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/firewallrules" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" - "github.com/hashicorp/terraform-provider-azurerm/utils" ) func resourcePostgreSQLFirewallRule() *pluginsdk.Resource { @@ -24,7 +23,7 @@ func resourcePostgreSQLFirewallRule() *pluginsdk.Resource { Read: resourcePostgreSQLFirewallRuleRead, Delete: resourcePostgreSQLFirewallRuleDelete, Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - _, err := parse.FirewallRuleID(id) + _, err := firewallrules.ParseFirewallRuleID(id) return err }), @@ -78,34 +77,29 @@ func resourcePostgreSQLFirewallRuleCreate(d *pluginsdk.ResourceData, meta interf ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) defer cancel() - id := parse.NewFirewallRuleID(subscriptionId, d.Get("resource_group_name").(string), d.Get("server_name").(string), d.Get("name").(string)) - existing, err := client.Get(ctx, id.ResourceGroup, id.ServerName, id.Name) + id := firewallrules.NewFirewallRuleID(subscriptionId, d.Get("resource_group_name").(string), d.Get("server_name").(string), d.Get("name").(string)) + existing, err := client.Get(ctx, id) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return fmt.Errorf("checking for presence of existing %s: %+v", id, err) } } - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return tf.ImportAsExistsError("azurerm_postgresql_firewall_rule", id.ID()) } - properties := postgresql.FirewallRule{ - FirewallRuleProperties: &postgresql.FirewallRuleProperties{ - StartIPAddress: utils.String(d.Get("start_ip_address").(string)), - EndIPAddress: utils.String(d.Get("end_ip_address").(string)), + properties := firewallrules.FirewallRule{ + Properties: firewallrules.FirewallRuleProperties{ + StartIPAddress: d.Get("start_ip_address").(string), + EndIPAddress: d.Get("end_ip_address").(string), }, } - future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.ServerName, id.Name, properties) - if err != nil { + if err = client.CreateOrUpdateThenPoll(ctx, id, properties); err != nil { return fmt.Errorf("creating/updating %s: %+v", id, err) } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for create/update of %s: %+v", id, err) - } - d.SetId(id.ID()) return resourcePostgreSQLFirewallRuleRead(d, meta) } @@ -115,14 +109,14 @@ func resourcePostgreSQLFirewallRuleRead(d *pluginsdk.ResourceData, meta interfac ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FirewallRuleID(d.Id()) + id, err := firewallrules.ParseFirewallRuleID(d.Id()) if err != nil { return err } - resp, err := client.Get(ctx, id.ResourceGroup, id.ServerName, id.Name) + resp, err := client.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { log.Printf("[WARN] %s was not found - removing from state", *id) d.SetId("") return nil @@ -131,13 +125,13 @@ func resourcePostgreSQLFirewallRuleRead(d *pluginsdk.ResourceData, meta interfac return fmt.Errorf("retrieving %s: %+v", *id, err) } - d.Set("name", id.Name) - d.Set("resource_group_name", id.ResourceGroup) + d.Set("name", id.FirewallRuleName) + d.Set("resource_group_name", id.ResourceGroupName) d.Set("server_name", id.ServerName) - if props := resp.FirewallRuleProperties; props != nil { - d.Set("start_ip_address", props.StartIPAddress) - d.Set("end_ip_address", props.EndIPAddress) + if model := resp.Model; model != nil { + d.Set("start_ip_address", resp.Model.Properties.StartIPAddress) + d.Set("end_ip_address", resp.Model.Properties.EndIPAddress) } return nil @@ -148,19 +142,14 @@ func resourcePostgreSQLFirewallRuleDelete(d *pluginsdk.ResourceData, meta interf ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FirewallRuleID(d.Id()) + id, err := firewallrules.ParseFirewallRuleID(d.Id()) if err != nil { return err } - future, err := client.Delete(ctx, id.ResourceGroup, id.ServerName, id.Name) - if err != nil { + if err = client.DeleteThenPoll(ctx, *id); err != nil { return fmt.Errorf("deleting %s: %+v", *id, err) } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for deletion of %s: %+v", *id, err) - } - return nil } diff --git a/internal/services/postgres/postgresql_firewall_rule_resource_test.go b/internal/services/postgres/postgresql_firewall_rule_resource_test.go index 7eddc2bdd7a1..6333570b6849 100644 --- a/internal/services/postgres/postgresql_firewall_rule_resource_test.go +++ b/internal/services/postgres/postgresql_firewall_rule_resource_test.go @@ -5,10 +5,10 @@ import ( "fmt" "testing" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/firewallrules" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -48,17 +48,17 @@ func TestAccPostgreSQLFirewallRule_requiresImport(t *testing.T) { } func (t PostgreSQLFirewallRuleResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.FirewallRuleID(state.ID) + id, err := firewallrules.ParseFirewallRuleID(state.ID) if err != nil { return nil, err } - resp, err := clients.Postgres.FirewallRulesClient.Get(ctx, id.ResourceGroup, id.ServerName, id.Name) + resp, err := clients.Postgres.FirewallRulesClient.Get(ctx, *id) if err != nil { return nil, fmt.Errorf("reading Postgresql Firewall Rule (%s): %+v", id.String(), err) } - return utils.Bool(resp.ID != nil), nil + return utils.Bool(resp.Model != nil), nil } func (PostgreSQLFirewallRuleResource) basic(data acceptance.TestData) string { diff --git a/internal/services/postgres/postgresql_flexible_server_configuration_resource.go b/internal/services/postgres/postgresql_flexible_server_configuration_resource.go index ea5c7ac9a7ef..2514a9eaf1a1 100644 --- a/internal/services/postgres/postgresql_flexible_server_configuration_resource.go +++ b/internal/services/postgres/postgresql_flexible_server_configuration_resource.go @@ -5,11 +5,10 @@ import ( "log" "time" - "github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2021-06-01/postgresqlflexibleservers" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/configurations" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/locks" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" @@ -31,7 +30,7 @@ func resourcePostgresqlFlexibleServerConfiguration() *pluginsdk.Resource { }, Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - _, err := parse.FlexibleServerConfigurationID(id) + _, err := configurations.ParseConfigurationID(id) return err }), @@ -47,7 +46,7 @@ func resourcePostgresqlFlexibleServerConfiguration() *pluginsdk.Resource { Type: pluginsdk.TypeString, Required: true, ForceNew: true, - ValidateFunc: validate.FlexibleServerID, + ValidateFunc: configurations.ValidateFlexibleServerID, }, "value": { @@ -67,33 +66,26 @@ func resourceFlexibleServerConfigurationUpdate(d *pluginsdk.ResourceData, meta i log.Printf("[INFO] preparing arguments for Azure Postgresql Flexible Server configuration creation.") - name := d.Get("name").(string) - serverId, err := parse.FlexibleServerID(d.Get("server_id").(string)) + serverId, err := configurations.ParseFlexibleServerID(d.Get("server_id").(string)) if err != nil { return err } + id := configurations.NewConfigurationID(subscriptionId, serverId.ResourceGroupName, serverId.ServerName, d.Get("name").(string)) - id := parse.NewFlexibleServerConfigurationID(subscriptionId, serverId.ResourceGroup, serverId.Name, name) + locks.ByName(id.ServerName, postgresqlFlexibleServerResourceName) + defer locks.UnlockByName(id.ServerName, postgresqlFlexibleServerResourceName) - locks.ByName(id.FlexibleServerName, postgresqlFlexibleServerResourceName) - defer locks.UnlockByName(id.FlexibleServerName, postgresqlFlexibleServerResourceName) - - props := postgresqlflexibleservers.Configuration{ - ConfigurationProperties: &postgresqlflexibleservers.ConfigurationProperties{ + props := configurations.Configuration{ + Properties: &configurations.ConfigurationProperties{ Value: utils.String(d.Get("value").(string)), Source: utils.String("user-override"), }, } - future, err := client.Update(ctx, serverId.ResourceGroup, serverId.Name, name, props) - if err != nil { + if err := client.UpdateThenPoll(ctx, id, props); err != nil { return fmt.Errorf("updating %s: %+v", id, err) } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for create/update of %s: %+v", id, err) - } - d.SetId(id.ID()) return resourceFlexibleServerConfigurationRead(d, meta) @@ -105,14 +97,14 @@ func resourceFlexibleServerConfigurationRead(d *pluginsdk.ResourceData, meta int ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FlexibleServerConfigurationID(d.Id()) + id, err := configurations.ParseConfigurationID(d.Id()) if err != nil { return err } - resp, err := client.Get(ctx, id.ResourceGroup, id.FlexibleServerName, id.ConfigurationName) + resp, err := client.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { log.Printf("[WARN] %s was not found, removing from state", id) d.SetId("") return nil @@ -122,10 +114,10 @@ func resourceFlexibleServerConfigurationRead(d *pluginsdk.ResourceData, meta int } d.Set("name", id.ConfigurationName) - d.Set("server_id", parse.NewFlexibleServerID(subscriptionId, id.ResourceGroup, id.FlexibleServerName).ID()) + d.Set("server_id", configurations.NewFlexibleServerID(subscriptionId, id.ResourceGroupName, id.ServerName).ID()) - if props := resp.ConfigurationProperties; props != nil { - d.Set("value", props.Value) + if resp.Model != nil && resp.Model.Properties != nil { + d.Set("value", resp.Model.Properties.Value) } return nil @@ -136,34 +128,34 @@ func resourceFlexibleServerConfigurationDelete(d *pluginsdk.ResourceData, meta i ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FlexibleServerConfigurationID(d.Id()) + id, err := configurations.ParseConfigurationID(d.Id()) if err != nil { return err } - locks.ByName(id.FlexibleServerName, postgresqlFlexibleServerResourceName) - defer locks.UnlockByName(id.FlexibleServerName, postgresqlFlexibleServerResourceName) + locks.ByName(id.ServerName, postgresqlFlexibleServerResourceName) + defer locks.UnlockByName(id.ServerName, postgresqlFlexibleServerResourceName) - resp, err := client.Get(ctx, id.ResourceGroup, id.FlexibleServerName, id.ConfigurationName) + resp, err := client.Get(ctx, *id) if err != nil { return fmt.Errorf("retrieving %s: %+v", id, err) } - props := postgresqlflexibleservers.Configuration{ - ConfigurationProperties: &postgresqlflexibleservers.ConfigurationProperties{ - Value: resp.DefaultValue, + defaultValue := "" + if resp.Model != nil && resp.Model.Properties != nil && resp.Model.Properties.DefaultValue != nil { + defaultValue = *resp.Model.Properties.DefaultValue + } + + props := configurations.Configuration{ + Properties: &configurations.ConfigurationProperties{ + Value: &defaultValue, Source: utils.String("user-override"), }, } - future, err := client.Update(ctx, id.ResourceGroup, id.FlexibleServerName, id.ConfigurationName, props) - if err != nil { + if err = client.UpdateThenPoll(ctx, *id, props); err != nil { return fmt.Errorf("deleting %s: %+v", id, err) } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for deletion of %s: %+v", id, err) - } - return nil } diff --git a/internal/services/postgres/postgresql_flexible_server_configuration_resource_test.go b/internal/services/postgres/postgresql_flexible_server_configuration_resource_test.go index 58661d87c5c0..1ed5128bab04 100644 --- a/internal/services/postgres/postgresql_flexible_server_configuration_resource_test.go +++ b/internal/services/postgres/postgresql_flexible_server_configuration_resource_test.go @@ -5,10 +5,12 @@ import ( "fmt" "testing" + "github.com/hashicorp/go-azure-helpers/lang/response" + + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/configurations" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -111,24 +113,32 @@ func TestAccFlexibleServerConfiguration_updateApplicationName(t *testing.T) { func (r PostgresqlFlexibleServerConfigurationResource) checkReset(configurationName string) acceptance.ClientCheckFunc { return func(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) error { - id, err := parse.FlexibleServerID(state.ID) + id, err := configurations.ParseFlexibleServerID(state.ID) if err != nil { return err } - resp, err := clients.Postgres.FlexibleServersConfigurationsClient.Get(ctx, id.ResourceGroup, id.Name, configurationName) + configurationId := configurations.NewConfigurationID(id.SubscriptionId, id.ResourceGroupName, id.ServerName, configurationName) + + resp, err := clients.Postgres.FlexibleServersConfigurationsClient.Get(ctx, configurationId) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { - return fmt.Errorf("Bad: Azure Postgresql Flexible Server configuration %q (server %q resource group: %q) does not exist", configurationName, id.Name, id.ResourceGroup) + if response.WasNotFound(resp.HttpResponse) { + return fmt.Errorf("%s does not exist", id) } return fmt.Errorf("Bad: Get on postgresqlConfigurationsClient: %+v", err) } - actualValue := *resp.Value - defaultValue := *resp.DefaultValue + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + if props.Value != nil && props.DefaultValue != nil { + actualValue := *props.Value + defaultValue := *props.DefaultValue - if defaultValue != actualValue { - return fmt.Errorf("Azure Postgresql Flexible Server configuration wasn't set to the default value. Expected '%s' - got '%s': \n%+v", defaultValue, actualValue, resp) + if defaultValue != actualValue { + return fmt.Errorf("Azure Postgresql Flexible Server configuration wasn't set to the default value. Expected '%s' - got '%s': \n%+v", defaultValue, actualValue, resp) + } + } + } } return nil @@ -152,17 +162,17 @@ func TestAccFlexibleServerConfiguration_multiplePostgresqlFlexibleServerConfigur // Helper functions for verification func (r PostgresqlFlexibleServerConfigurationResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.FlexibleServerConfigurationID(state.ID) + id, err := configurations.ParseConfigurationID(state.ID) if err != nil { return nil, err } - resp, err := clients.Postgres.FlexibleServersConfigurationsClient.Get(ctx, id.ResourceGroup, id.FlexibleServerName, state.Attributes["name"]) + resp, err := clients.Postgres.FlexibleServersConfigurationsClient.Get(ctx, *id) if err != nil { return nil, fmt.Errorf("reading Postgresql Configuration (%s): %+v", id.String(), err) } - return utils.Bool(resp.ID != nil), nil + return utils.Bool(resp.Model != nil), nil } func (PostgresqlFlexibleServerConfigurationResource) template(data acceptance.TestData) string { diff --git a/internal/services/postgres/postgresql_flexible_server_data_source.go b/internal/services/postgres/postgresql_flexible_server_data_source.go index c8eb4192896e..968b30c54a26 100644 --- a/internal/services/postgres/postgresql_flexible_server_data_source.go +++ b/internal/services/postgres/postgresql_flexible_server_data_source.go @@ -4,15 +4,14 @@ import ( "fmt" "time" - "github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2021-06-01/postgresqlflexibleservers" + "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/servers" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" - "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" - "github.com/hashicorp/terraform-provider-azurerm/utils" ) func dataSourcePostgresqlFlexibleServer() *pluginsdk.Resource { @@ -73,7 +72,7 @@ func dataSourcePostgresqlFlexibleServer() *pluginsdk.Resource { Computed: true, }, - "tags": tags.SchemaDataSource(), + "tags": commonschema.TagsDataSource(), }, } } @@ -87,45 +86,56 @@ func dataSourceArmPostgresqlFlexibleServerRead(d *pluginsdk.ResourceData, meta i name := d.Get("name").(string) resourceGroup := d.Get("resource_group_name").(string) - id := parse.NewFlexibleServerID(subscriptionId, resourceGroup, name) + id := servers.NewFlexibleServerID(subscriptionId, resourceGroup, name) - resp, err := client.Get(ctx, id.ResourceGroup, id.Name) + resp, err := client.Get(ctx, id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { - return fmt.Errorf("Postgresqlflexibleservers Server %q does not exist", id.Name) + if response.WasNotFound(resp.HttpResponse) { + return fmt.Errorf("%s does not exist", id) } - return fmt.Errorf("retrieving Postgresqlflexibleservers Server %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + return fmt.Errorf("retrieving %s: %+v", id, err) } d.SetId(id.ID()) - d.Set("name", id.Name) - d.Set("resource_group_name", id.ResourceGroup) - d.Set("location", location.NormalizeNilable(resp.Location)) + d.Set("name", id.ServerName) + d.Set("resource_group_name", id.ResourceGroupName) + + if model := resp.Model; model != nil { + d.Set("location", location.NormalizeNilable(&model.Location)) + + if props := model.Properties; props != nil { + d.Set("administrator_login", props.AdministratorLogin) + d.Set("version", props.Version) + d.Set("fqdn", props.FullyQualifiedDomainName) + + if storage := props.Storage; storage != nil && storage.StorageSizeGB != nil { + d.Set("storage_mb", (*props.Storage.StorageSizeGB * 1024)) + } + + if backup := props.Backup; backup != nil { + d.Set("backup_retention_days", props.Backup.BackupRetentionDays) + } + + if network := props.Network; network != nil { + d.Set("delegated_subnet_id", network.DelegatedSubnetResourceId) + publicNetworkAccess := false + if network.PublicNetworkAccess != nil { + publicNetworkAccess = *network.PublicNetworkAccess == servers.ServerPublicNetworkAccessStateEnabled + } + d.Set("public_network_access_enabled", publicNetworkAccess) + } - if props := resp.ServerProperties; props != nil { - d.Set("administrator_login", props.AdministratorLogin) - d.Set("version", props.Version) - d.Set("fqdn", props.FullyQualifiedDomainName) - - if storage := props.Storage; storage != nil && storage.StorageSizeGB != nil { - d.Set("storage_mb", (*props.Storage.StorageSizeGB * 1024)) } - if backup := props.Backup; backup != nil { - d.Set("backup_retention_days", props.Backup.BackupRetentionDays) + sku, err := flattenFlexibleServerSku(model.Sku) + if err != nil { + return fmt.Errorf("flattening `sku_name`: %+v", err) } - if network := props.Network; network != nil { - d.Set("delegated_subnet_id", network.DelegatedSubnetResourceID) - d.Set("public_network_access_enabled", network.PublicNetworkAccess == postgresqlflexibleservers.ServerPublicNetworkAccessStateEnabled) - } - } + d.Set("sku_name", sku) - sku, err := flattenFlexibleServerSku(resp.Sku) - if err != nil { - return fmt.Errorf("flattening `sku_name` for PostgreSQL Flexible Server %s (Resource Group %q): %v", id.Name, id.ResourceGroup, err) + return tags.FlattenAndSet(d, model.Tags) } - d.Set("sku_name", sku) - return tags.FlattenAndSet(d, resp.Tags) + return nil } diff --git a/internal/services/postgres/postgresql_flexible_server_database_resource.go b/internal/services/postgres/postgresql_flexible_server_database_resource.go index 3d88d980233b..5e67ec8a3636 100644 --- a/internal/services/postgres/postgresql_flexible_server_database_resource.go +++ b/internal/services/postgres/postgresql_flexible_server_database_resource.go @@ -5,10 +5,10 @@ import ( "log" "time" - "github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2021-06-01/postgresqlflexibleservers" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/databases" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/suppress" @@ -22,7 +22,7 @@ func resourcePostgresqlFlexibleServerDatabase() *pluginsdk.Resource { Read: resourcePostgresqlFlexibleServerDatabaseRead, Delete: resourcePostgresqlFlexibleServerDatabaseDelete, Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - _, err := parse.FlexibleServerDatabaseID(id) + _, err := databases.ParseDatabaseID(id) return err }), @@ -44,7 +44,7 @@ func resourcePostgresqlFlexibleServerDatabase() *pluginsdk.Resource { Type: pluginsdk.TypeString, Required: true, ForceNew: true, - ValidateFunc: validate.FlexibleServerID, + ValidateFunc: databases.ValidateFlexibleServerID, }, "charset": { @@ -73,42 +73,36 @@ func resourcePostgresqlFlexibleServerDatabaseCreate(d *pluginsdk.ResourceData, m ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) defer cancel() - name := d.Get("name").(string) - serverId, err := parse.FlexibleServerID(d.Get("server_id").(string)) + serverId, err := databases.ParseFlexibleServerID(d.Get("server_id").(string)) if err != nil { return err } - id := parse.NewFlexibleServerDatabaseID(subscriptionId, serverId.ResourceGroup, serverId.Name, name) + id := databases.NewDatabaseID(subscriptionId, serverId.ResourceGroupName, serverId.ServerName, d.Get("name").(string)) if d.IsNewResource() { - existing, err := client.Get(ctx, serverId.ResourceGroup, serverId.Name, name) + existing, err := client.Get(ctx, id) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return fmt.Errorf("checking for presence of existing %q: %+v", id, err) } } - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return tf.ImportAsExistsError("azurerm_postgresql_flexible_server_database", id.ID()) } } - properties := postgresqlflexibleservers.Database{ - DatabaseProperties: &postgresqlflexibleservers.DatabaseProperties{ + properties := databases.Database{ + Properties: &databases.DatabaseProperties{ Charset: utils.String(d.Get("charset").(string)), Collation: utils.String(d.Get("collation").(string)), }, } - future, err := client.Create(ctx, id.ResourceGroup, id.FlexibleServerName, id.DatabaseName, properties) - if err != nil { + if err = client.CreateThenPoll(ctx, id, properties); err != nil { return fmt.Errorf("creating %s: %+v", id, err) } - if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for creation of %s: %+v", id, err) - } - d.SetId(id.ID()) return resourcePostgresqlFlexibleServerDatabaseRead(d, meta) } @@ -119,14 +113,14 @@ func resourcePostgresqlFlexibleServerDatabaseRead(d *pluginsdk.ResourceData, met ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FlexibleServerDatabaseID(d.Id()) + id, err := databases.ParseDatabaseID(d.Id()) if err != nil { return err } - resp, err := client.Get(ctx, id.ResourceGroup, id.FlexibleServerName, id.DatabaseName) + resp, err := client.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if !response.WasNotFound(resp.HttpResponse) { log.Printf("[INFO] %s does not exist - removing from state", *id) d.SetId("") return nil @@ -134,11 +128,13 @@ func resourcePostgresqlFlexibleServerDatabaseRead(d *pluginsdk.ResourceData, met return fmt.Errorf("retrieving %s: %+v", *id, err) } d.Set("name", id.DatabaseName) - d.Set("server_id", parse.NewFlexibleServerID(subscriptionId, id.ResourceGroup, id.FlexibleServerName).ID()) + d.Set("server_id", databases.NewFlexibleServerID(subscriptionId, id.ResourceGroupName, id.ServerName).ID()) - if props := resp.DatabaseProperties; props != nil { - d.Set("charset", props.Charset) - d.Set("collation", props.Collation) + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("charset", props.Charset) + d.Set("collation", props.Collation) + } } return nil @@ -149,19 +145,14 @@ func resourcePostgresqlFlexibleServerDatabaseDelete(d *pluginsdk.ResourceData, m ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FlexibleServerDatabaseID(d.Id()) + id, err := databases.ParseDatabaseID(d.Id()) if err != nil { return err } - future, err := client.Delete(ctx, id.ResourceGroup, id.FlexibleServerName, id.DatabaseName) - if err != nil { + if err = client.DeleteThenPoll(ctx, *id); err != nil { return fmt.Errorf("deleting %s: %+v", *id, err) } - if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for deleting of %s: %+v", *id, err) - } - return nil } diff --git a/internal/services/postgres/postgresql_flexible_server_database_resource_test.go b/internal/services/postgres/postgresql_flexible_server_database_resource_test.go index 115efd5a8b01..353a0c5b3e8d 100644 --- a/internal/services/postgres/postgresql_flexible_server_database_resource_test.go +++ b/internal/services/postgres/postgresql_flexible_server_database_resource_test.go @@ -5,10 +5,10 @@ import ( "fmt" "testing" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/databases" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -76,17 +76,17 @@ func TestAccPostgresqlFlexibleServerDatabase_withoutCharsetAndCollation(t *testi } func (PostgresqlFlexibleServerDatabaseResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.FlexibleServerDatabaseID(state.ID) + id, err := databases.ParseDatabaseID(state.ID) if err != nil { return nil, err } - resp, err := clients.Postgres.FlexibleServerDatabaseClient.Get(ctx, id.ResourceGroup, id.FlexibleServerName, id.DatabaseName) + resp, err := clients.Postgres.FlexibleServerDatabaseClient.Get(ctx, *id) if err != nil { return nil, fmt.Errorf("retrieving %s: %+v", *id, err) } - return utils.Bool(resp.DatabaseProperties != nil), nil + return utils.Bool(resp.Model != nil), nil } func (r PostgresqlFlexibleServerDatabaseResource) requiresImport(data acceptance.TestData) string { diff --git a/internal/services/postgres/postgresql_flexible_server_firewall_rule_resource.go b/internal/services/postgres/postgresql_flexible_server_firewall_rule_resource.go index b051ca083bf9..6a2e282df01a 100644 --- a/internal/services/postgres/postgresql_flexible_server_firewall_rule_resource.go +++ b/internal/services/postgres/postgresql_flexible_server_firewall_rule_resource.go @@ -5,15 +5,14 @@ import ( "log" "time" - "github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2021-06-01/postgresqlflexibleservers" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/firewallrules" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" - "github.com/hashicorp/terraform-provider-azurerm/utils" ) func resourcePostgresqlFlexibleServerFirewallRule() *pluginsdk.Resource { @@ -31,7 +30,7 @@ func resourcePostgresqlFlexibleServerFirewallRule() *pluginsdk.Resource { }, Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - _, err := parse.FlexibleServerFirewallRuleID(id) + _, err := firewallrules.ParseFirewallRuleID(id) return err }), @@ -47,7 +46,7 @@ func resourcePostgresqlFlexibleServerFirewallRule() *pluginsdk.Resource { Type: pluginsdk.TypeString, Required: true, ForceNew: true, - ValidateFunc: validate.FlexibleServerID, + ValidateFunc: firewallrules.ValidateFlexibleServerID, }, "end_ip_address": { @@ -71,42 +70,36 @@ func resourcePostgresqlFlexibleServerFirewallRuleCreateUpdate(d *pluginsdk.Resou ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - name := d.Get("name").(string) - serverId, err := parse.FlexibleServerID(d.Get("server_id").(string)) + serverId, err := firewallrules.ParseFlexibleServerID(d.Get("server_id").(string)) if err != nil { return err } - id := parse.NewFlexibleServerFirewallRuleID(subscriptionId, serverId.ResourceGroup, serverId.Name, name) + id := firewallrules.NewFirewallRuleID(subscriptionId, serverId.ResourceGroupName, serverId.ServerName, d.Get("name").(string)) if d.IsNewResource() { - existing, err := client.Get(ctx, serverId.ResourceGroup, serverId.Name, name) + existing, err := client.Get(ctx, id) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return fmt.Errorf("checking for present of existing %q: %+v", id, err) } } - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return tf.ImportAsExistsError("azurerm_postgresql_flexible_server_firewall_rule", id.ID()) } } - properties := postgresqlflexibleservers.FirewallRule{ - FirewallRuleProperties: &postgresqlflexibleservers.FirewallRuleProperties{ - EndIPAddress: utils.String(d.Get("end_ip_address").(string)), - StartIPAddress: utils.String(d.Get("start_ip_address").(string)), + properties := firewallrules.FirewallRule{ + Properties: firewallrules.FirewallRuleProperties{ + EndIPAddress: d.Get("end_ip_address").(string), + StartIPAddress: d.Get("start_ip_address").(string), }, } - future, err := client.CreateOrUpdate(ctx, serverId.ResourceGroup, serverId.Name, name, properties) - if err != nil { + if err = client.CreateOrUpdateThenPoll(ctx, id, properties); err != nil { return fmt.Errorf("creating/updating %q: %+v", id, err) } - if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for the creation/ update of %q: %+v", id, err) - } - d.SetId(id.ID()) return resourcePostgresqlFlexibleServerFirewallRuleRead(d, meta) } @@ -117,14 +110,14 @@ func resourcePostgresqlFlexibleServerFirewallRuleRead(d *pluginsdk.ResourceData, ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FlexibleServerFirewallRuleID(d.Id()) + id, err := firewallrules.ParseFirewallRuleID(d.Id()) if err != nil { return err } - resp, err := client.Get(ctx, id.ResourceGroup, id.FlexibleServerName, id.FirewallRuleName) + resp, err := client.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { log.Printf("[INFO] Postgresql Flexible Server Firewall Rule %q does not exist - removing from state", d.Id()) d.SetId("") return nil @@ -132,10 +125,11 @@ func resourcePostgresqlFlexibleServerFirewallRuleRead(d *pluginsdk.ResourceData, return fmt.Errorf("retrieving %q: %+v", id, err) } d.Set("name", id.FirewallRuleName) - d.Set("server_id", parse.NewFlexibleServerID(subscriptionId, id.ResourceGroup, id.FlexibleServerName).ID()) - if props := resp.FirewallRuleProperties; props != nil { - d.Set("end_ip_address", props.EndIPAddress) - d.Set("start_ip_address", props.StartIPAddress) + d.Set("server_id", firewallrules.NewFlexibleServerID(subscriptionId, id.ResourceGroupName, id.ServerName).ID()) + + if model := resp.Model; model != nil { + d.Set("end_ip_address", model.Properties.EndIPAddress) + d.Set("start_ip_address", model.Properties.StartIPAddress) } return nil } @@ -145,18 +139,14 @@ func resourcePostgresqlFlexibleServerFirewallRuleDelete(d *pluginsdk.ResourceDat ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FlexibleServerFirewallRuleID(d.Id()) + id, err := firewallrules.ParseFirewallRuleID(d.Id()) if err != nil { return err } - future, err := client.Delete(ctx, id.ResourceGroup, id.FlexibleServerName, id.FirewallRuleName) - if err != nil { + if err = client.DeleteThenPoll(ctx, *id); err != nil { return fmt.Errorf("deleting %q: %+v", id, err) } - if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for the delete of %q: %+v", id, err) - } return nil } diff --git a/internal/services/postgres/postgresql_flexible_server_firewall_rule_resource_test.go b/internal/services/postgres/postgresql_flexible_server_firewall_rule_resource_test.go index 270f7417fe78..80419a2e6aff 100644 --- a/internal/services/postgres/postgresql_flexible_server_firewall_rule_resource_test.go +++ b/internal/services/postgres/postgresql_flexible_server_firewall_rule_resource_test.go @@ -5,10 +5,10 @@ import ( "fmt" "testing" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/firewallrules" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -72,17 +72,17 @@ func TestAccPostgresqlFlexibleServerFirewallRule_update(t *testing.T) { } func (PostgresqlFlexibleServerFirewallRuleResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.FlexibleServerFirewallRuleID(state.ID) + id, err := firewallrules.ParseFirewallRuleID(state.ID) if err != nil { return nil, err } - resp, err := clients.Postgres.FlexibleServerFirewallRuleClient.Get(ctx, id.ResourceGroup, id.FlexibleServerName, id.FirewallRuleName) + resp, err := clients.Postgres.FlexibleServerFirewallRuleClient.Get(ctx, *id) if err != nil { - return nil, fmt.Errorf("retrieving Postgresql Flexible Server Firewall Rule %q ( Flexible Server: %q / resource group: %q): %+v", id.FirewallRuleName, id.FlexibleServerName, id.ResourceGroup, err) + return nil, fmt.Errorf("retrieving %s: %+v", id, err) } - return utils.Bool(resp.FirewallRuleProperties != nil), nil + return utils.Bool(resp.Model != nil), nil } func (PostgresqlFlexibleServerFirewallRuleResource) basic(data acceptance.TestData) string { diff --git a/internal/services/postgres/postgresql_flexible_server_resource.go b/internal/services/postgres/postgresql_flexible_server_resource.go index e705b417c27e..fe5dc76b6397 100644 --- a/internal/services/postgres/postgresql_flexible_server_resource.go +++ b/internal/services/postgres/postgresql_flexible_server_resource.go @@ -6,18 +6,18 @@ import ( "strings" "time" - "github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2021-06-01/postgresqlflexibleservers" - "github.com/Azure/go-autorest/autorest/date" + "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/serverrestart" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/servers" "github.com/hashicorp/go-azure-sdk/resource-manager/privatedns/2018-09-01/privatezones" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" networkValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/validate" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/validate" - "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" @@ -46,7 +46,7 @@ func resourcePostgresqlFlexibleServer() *pluginsdk.Resource { }, Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - _, err := parse.FlexibleServerID(id) + _, err := servers.ParseFlexibleServerID(id) return err }), @@ -92,15 +92,11 @@ func resourcePostgresqlFlexibleServer() *pluginsdk.Resource { }, "version": { - Type: pluginsdk.TypeString, - Optional: true, - Computed: true, - ForceNew: true, - ValidateFunc: validation.StringInSlice([]string{ - string(postgresqlflexibleservers.ServerVersionOneOne), - string(postgresqlflexibleservers.ServerVersionOneTwo), - string(postgresqlflexibleservers.ServerVersionOneThree), - }, false), + Type: pluginsdk.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice(servers.PossibleValuesForServerVersion(), false), }, "zone": commonschema.ZoneSingleOptional(), @@ -110,8 +106,8 @@ func resourcePostgresqlFlexibleServer() *pluginsdk.Resource { Optional: true, ForceNew: true, ValidateFunc: validation.StringInSlice([]string{ - string(postgresqlflexibleservers.CreateModeDefault), - string(postgresqlflexibleservers.CreateModePointInTimeRestore), + string(servers.CreateModeDefault), + string(servers.CreateModePointInTimeRestore), }, false), }, @@ -144,7 +140,7 @@ func resourcePostgresqlFlexibleServer() *pluginsdk.Resource { Type: pluginsdk.TypeString, Optional: true, ForceNew: true, - ValidateFunc: validate.FlexibleServerID, + ValidateFunc: servers.ValidateFlexibleServerID, }, "maintenance_window": { @@ -201,7 +197,7 @@ func resourcePostgresqlFlexibleServer() *pluginsdk.Resource { Type: pluginsdk.TypeString, Required: true, ValidateFunc: validation.StringInSlice([]string{ - string(postgresqlflexibleservers.HighAvailabilityModeZoneRedundant), + string(servers.HighAvailabilityModeZoneRedundant), }, false), }, @@ -220,7 +216,7 @@ func resourcePostgresqlFlexibleServer() *pluginsdk.Resource { Computed: true, }, - "tags": tags.Schema(), + "tags": commonschema.Tags(), }, } } @@ -234,21 +230,21 @@ func resourcePostgresqlFlexibleServerCreate(d *pluginsdk.ResourceData, meta inte name := d.Get("name").(string) resourceGroup := d.Get("resource_group_name").(string) - id := parse.NewFlexibleServerID(subscriptionId, resourceGroup, name) + id := servers.NewFlexibleServerID(subscriptionId, resourceGroup, name) - existing, err := client.Get(ctx, id.ResourceGroup, id.Name) + existing, err := client.Get(ctx, id) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { - return fmt.Errorf("checking for present of existing Postgresql Flexible Server %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + if !response.WasNotFound(existing.HttpResponse) { + return fmt.Errorf("checking for presence of %s: %+v", id, err) } } - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return tf.ImportAsExistsError("azurerm_postgresql_flexible_server", id.ID()) } createMode := d.Get("create_mode").(string) - if postgresqlflexibleservers.CreateMode(createMode) == postgresqlflexibleservers.CreateModePointInTimeRestore { + if servers.CreateMode(createMode) == servers.CreateModePointInTimeRestore { if _, ok := d.GetOk("source_server_id"); !ok { return fmt.Errorf("`source_server_id` is required when `create_mode` is `PointInTimeRestore`") } @@ -257,7 +253,7 @@ func resourcePostgresqlFlexibleServerCreate(d *pluginsdk.ResourceData, meta inte } } - if createMode == "" || postgresqlflexibleservers.CreateMode(createMode) == postgresqlflexibleservers.CreateModeDefault { + if createMode == "" || servers.CreateMode(createMode) == servers.CreateModeDefault { if _, ok := d.GetOk("administrator_login"); !ok { return fmt.Errorf("`administrator_login` is required when `create_mode` is `Default`") } @@ -277,15 +273,13 @@ func resourcePostgresqlFlexibleServerCreate(d *pluginsdk.ResourceData, meta inte sku, err := expandFlexibleServerSku(d.Get("sku_name").(string)) if err != nil { - return fmt.Errorf("expanding `sku_name` for PostgreSQL Flexible Server %s (Resource Group %q): %v", id.Name, id.ResourceGroup, err) + return fmt.Errorf("expanding `sku_name` for %s: %v", id, err) } - parameters := postgresqlflexibleservers.Server{ - Location: utils.String(location.Normalize(d.Get("location").(string))), - ServerProperties: &postgresqlflexibleservers.ServerProperties{ - CreateMode: postgresqlflexibleservers.CreateMode(d.Get("create_mode").(string)), + parameters := servers.Server{ + Location: location.Normalize(d.Get("location").(string)), + Properties: &servers.ServerProperties{ Network: expandArmServerNetwork(d), - Version: postgresqlflexibleservers.ServerVersion(d.Get("version").(string)), Storage: expandArmServerStorage(d), HighAvailability: expandFlexibleServerHighAvailability(d.Get("high_availability").([]interface{}), true), Backup: expandArmServerBackup(d), @@ -295,19 +289,29 @@ func resourcePostgresqlFlexibleServerCreate(d *pluginsdk.ResourceData, meta inte } if v, ok := d.GetOk("administrator_login"); ok && v.(string) != "" { - parameters.ServerProperties.AdministratorLogin = utils.String(v.(string)) + parameters.Properties.AdministratorLogin = utils.String(v.(string)) } if v, ok := d.GetOk("administrator_password"); ok && v.(string) != "" { - parameters.ServerProperties.AdministratorLoginPassword = utils.String(v.(string)) + parameters.Properties.AdministratorLoginPassword = utils.String(v.(string)) + } + + if createMode != "" { + createModeAttr := servers.CreateMode(createMode) + parameters.Properties.CreateMode = &createModeAttr + } + + if v, ok := d.GetOk("version"); ok && v.(string) != "" { + version := servers.ServerVersion(v.(string)) + parameters.Properties.Version = &version } if v, ok := d.GetOk("zone"); ok && v.(string) != "" { - parameters.ServerProperties.AvailabilityZone = utils.String(v.(string)) + parameters.Properties.AvailabilityZone = utils.String(v.(string)) } if v, ok := d.GetOk("source_server_id"); ok && v.(string) != "" { - parameters.SourceServerResourceID = utils.String(v.(string)) + parameters.Properties.SourceServerResourceId = utils.String(v.(string)) } pointInTimeUTC := d.Get("point_in_time_restore_time_in_utc").(string) @@ -316,32 +320,22 @@ func resourcePostgresqlFlexibleServerCreate(d *pluginsdk.ResourceData, meta inte if err != nil { return fmt.Errorf("unable to parse `point_in_time_restore_time_in_utc` value") } - parameters.ServerProperties.PointInTimeUTC = &date.Time{Time: v} - } - - future, err := client.Create(ctx, id.ResourceGroup, id.Name, parameters) - if err != nil { - return fmt.Errorf("creating Postgresql Flexible Server %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + parameters.Properties.PointInTimeUTC = utils.String(v.Format(time.RFC3339)) } - if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for creation of the Postgresql Flexible Server %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + if err = client.CreateThenPoll(ctx, id, parameters); err != nil { + return fmt.Errorf("creating %s: %+v", id, err) } // `maintenance_window` could only be updated with, could not be created with if v, ok := d.GetOk("maintenance_window"); ok { - mwParams := postgresqlflexibleservers.ServerForUpdate{ - ServerPropertiesForUpdate: &postgresqlflexibleservers.ServerPropertiesForUpdate{ + mwParams := servers.ServerForUpdate{ + Properties: &servers.ServerPropertiesForUpdate{ MaintenanceWindow: expandArmServerMaintenanceWindow(v.([]interface{})), }, } - mwFuture, err := client.Update(ctx, id.ResourceGroup, id.Name, mwParams) - if err != nil { - return fmt.Errorf("updating Postgresql Flexible Server %q maintenance window (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) - } - - if err := mwFuture.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for the update of the Postgresql Flexible Server %q maintenance window (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + if err = client.UpdateThenPoll(ctx, id, mwParams); err != nil { + return fmt.Errorf("updating %s: %+v", id, err) } } @@ -355,63 +349,78 @@ func resourcePostgresqlFlexibleServerRead(d *pluginsdk.ResourceData, meta interf ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FlexibleServerID(d.Id()) + id, err := servers.ParseFlexibleServerID(d.Id()) if err != nil { return err } - resp, err := client.Get(ctx, id.ResourceGroup, id.Name) + resp, err := client.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { log.Printf("[INFO] Postgresql Flexibleserver %q does not exist - removing from state", d.Id()) d.SetId("") return nil } - return fmt.Errorf("retrieving Postgresql Flexible Server %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + return fmt.Errorf("retrieving %s: %+v", id, err) } - d.Set("name", id.Name) - d.Set("resource_group_name", id.ResourceGroup) - d.Set("location", location.NormalizeNilable(resp.Location)) + d.Set("name", id.ServerName) + d.Set("resource_group_name", id.ResourceGroupName) - if props := resp.ServerProperties; props != nil { - d.Set("administrator_login", props.AdministratorLogin) - d.Set("zone", props.AvailabilityZone) - d.Set("version", props.Version) - d.Set("fqdn", props.FullyQualifiedDomainName) + if model := resp.Model; model != nil { + d.Set("location", location.NormalizeNilable(&model.Location)) - if network := props.Network; network != nil { - d.Set("public_network_access_enabled", network.PublicNetworkAccess == postgresqlflexibleservers.ServerPublicNetworkAccessStateEnabled) - d.Set("delegated_subnet_id", network.DelegatedSubnetResourceID) - d.Set("private_dns_zone_id", network.PrivateDNSZoneArmResourceID) - } + if props := model.Properties; props != nil { + d.Set("administrator_login", props.AdministratorLogin) + d.Set("zone", props.AvailabilityZone) + d.Set("version", props.Version) + d.Set("fqdn", props.FullyQualifiedDomainName) - if err := d.Set("maintenance_window", flattenArmServerMaintenanceWindow(props.MaintenanceWindow)); err != nil { - return fmt.Errorf("setting `maintenance_window`: %+v", err) - } + if network := props.Network; network != nil { + publicNetworkAccess := false + if network.PublicNetworkAccess != nil { + publicNetworkAccess = *network.PublicNetworkAccess == servers.ServerPublicNetworkAccessStateEnabled + } + d.Set("public_network_access_enabled", publicNetworkAccess) + d.Set("delegated_subnet_id", network.DelegatedSubnetResourceId) + d.Set("private_dns_zone_id", network.PrivateDnsZoneArmResourceId) + } - if storage := props.Storage; storage != nil && storage.StorageSizeGB != nil { - d.Set("storage_mb", (*storage.StorageSizeGB * 1024)) - } + if err := d.Set("maintenance_window", flattenArmServerMaintenanceWindow(props.MaintenanceWindow)); err != nil { + return fmt.Errorf("setting `maintenance_window`: %+v", err) + } - if backup := props.Backup; backup != nil { - d.Set("backup_retention_days", backup.BackupRetentionDays) - d.Set("geo_redundant_backup_enabled", backup.GeoRedundantBackup == postgresqlflexibleservers.GeoRedundantBackupEnumEnabled) + if storage := props.Storage; storage != nil && storage.StorageSizeGB != nil { + d.Set("storage_mb", (*storage.StorageSizeGB * 1024)) + } + + if backup := props.Backup; backup != nil { + d.Set("backup_retention_days", backup.BackupRetentionDays) + + geoRedundantBackup := false + if backup.GeoRedundantBackup != nil { + geoRedundantBackup = *backup.GeoRedundantBackup == servers.GeoRedundantBackupEnumEnabled + } + d.Set("geo_redundant_backup_enabled", geoRedundantBackup) + } + + if err := d.Set("high_availability", flattenFlexibleServerHighAvailability(props.HighAvailability)); err != nil { + return fmt.Errorf("setting `high_availability`: %+v", err) + } } - if err := d.Set("high_availability", flattenFlexibleServerHighAvailability(props.HighAvailability)); err != nil { - return fmt.Errorf("setting `high_availability`: %+v", err) + sku, err := flattenFlexibleServerSku(model.Sku) + if err != nil { + return fmt.Errorf("flattening `sku_name` for %s: %v", id, err) } - } - sku, err := flattenFlexibleServerSku(resp.Sku) - if err != nil { - return fmt.Errorf("flattening `sku_name` for PostgreSQL Flexible Server %s (Resource Group %q): %v", id.Name, id.ResourceGroup, err) - } + d.Set("sku_name", sku) + + return tags.FlattenAndSet(d, model.Tags) - d.Set("sku_name", sku) + } - return tags.FlattenAndSet(d, resp.Tags) + return nil } func resourcePostgresqlFlexibleServerUpdate(d *pluginsdk.ResourceData, meta interface{}) error { @@ -419,24 +428,24 @@ func resourcePostgresqlFlexibleServerUpdate(d *pluginsdk.ResourceData, meta inte ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FlexibleServerID(d.Id()) + id, err := servers.ParseFlexibleServerID(d.Id()) if err != nil { return err } - parameters := postgresqlflexibleservers.ServerForUpdate{ - Location: utils.String(location.Normalize(d.Get("location").(string))), - ServerPropertiesForUpdate: &postgresqlflexibleservers.ServerPropertiesForUpdate{}, + parameters := servers.ServerForUpdate{ + Location: utils.String(location.Normalize(d.Get("location").(string))), + Properties: &servers.ServerPropertiesForUpdate{}, } var requireFailover bool // failover is only supported when `zone` and `high_availability.0.standby_availability_zone` are exchanged with each other if d.HasChanges("zone", "high_availability") { - resp, err := client.Get(ctx, id.ResourceGroup, id.Name) - if err != nil { + resp, err := client.Get(ctx, *id) + if err != nil || resp.Model == nil { return err } - props := resp.ServerProperties + props := resp.Model.Properties if d.HasChange("zone") { @@ -460,9 +469,9 @@ func resourcePostgresqlFlexibleServerUpdate(d *pluginsdk.ResourceData, meta inte // changes can occur in high_availability.0.standby_availability_zone when zone has not changed in the case where a high_availability block has been newly added or a high_availability block is removed, meaning HA is now disabled } else if d.HasChange("high_availability.0.standby_availability_zone") { - if props != nil && props.HighAvailability != nil { + if props != nil && props.HighAvailability != nil && props.HighAvailability.Mode != nil { // if HA Mode is currently "ZoneRedundant" and is still set to "ZoneRedundant", high_availability.0.standby_availability_zone cannot be changed - if props.HighAvailability.Mode == postgresqlflexibleservers.HighAvailabilityModeZoneRedundant && !d.HasChange("high_availability.0.mode") { + if *props.HighAvailability.Mode == servers.HighAvailabilityModeZoneRedundant && !d.HasChange("high_availability.0.mode") { return fmt.Errorf("an existing `high_availability.0.standby_availability_zone` can only be changed when exchanged with the zone specified in `zone`") } // if high_availability.0.mode changes from "ZoneRedundant", an existing high_availability block has been removed as this is a required field @@ -472,25 +481,25 @@ func resourcePostgresqlFlexibleServerUpdate(d *pluginsdk.ResourceData, meta inte } if d.HasChange("administrator_password") { - parameters.ServerPropertiesForUpdate.AdministratorLoginPassword = utils.String(d.Get("administrator_password").(string)) + parameters.Properties.AdministratorLoginPassword = utils.String(d.Get("administrator_password").(string)) } if d.HasChange("storage_mb") { - parameters.ServerPropertiesForUpdate.Storage = expandArmServerStorage(d) + parameters.Properties.Storage = expandArmServerStorage(d) } if d.HasChange("backup_retention_days") { - parameters.ServerPropertiesForUpdate.Backup = expandArmServerBackup(d) + parameters.Properties.Backup = expandArmServerBackup(d) } if d.HasChange("maintenance_window") { - parameters.ServerPropertiesForUpdate.MaintenanceWindow = expandArmServerMaintenanceWindow(d.Get("maintenance_window").([]interface{})) + parameters.Properties.MaintenanceWindow = expandArmServerMaintenanceWindow(d.Get("maintenance_window").([]interface{})) } if d.HasChange("sku_name") { sku, err := expandFlexibleServerSku(d.Get("sku_name").(string)) if err != nil { - return fmt.Errorf("expanding `sku_name` for PostgreSQL Flexible Server %s (Resource Group %q): %v", id.Name, id.ResourceGroup, err) + return fmt.Errorf("expanding `sku_name` for %s: %v", id, err) } parameters.Sku = sku } @@ -500,32 +509,26 @@ func resourcePostgresqlFlexibleServerUpdate(d *pluginsdk.ResourceData, meta inte } if d.HasChange("high_availability") { - parameters.HighAvailability = expandFlexibleServerHighAvailability(d.Get("high_availability").([]interface{}), false) + parameters.Properties.HighAvailability = expandFlexibleServerHighAvailability(d.Get("high_availability").([]interface{}), false) } - future, err := client.Update(ctx, id.ResourceGroup, id.Name, parameters) - if err != nil { - return fmt.Errorf("updating Postgresql Flexible Server %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) - } - - if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for the update of the Postgresql Flexible Server %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + if err = client.UpdateThenPoll(ctx, *id, parameters); err != nil { + return fmt.Errorf("updating %s: %+v", id, err) } if requireFailover { - restartParameters := &postgresqlflexibleservers.RestartParameter{ + restartClient := meta.(*clients.Client).Postgres.ServerRestartClient + + restartServerId := serverrestart.NewFlexibleServerID(id.SubscriptionId, id.ResourceGroupName, id.ServerName) + failoverMode := serverrestart.FailoverModePlannedFailover + restartParameters := serverrestart.RestartParameter{ RestartWithFailover: utils.Bool(true), - FailoverMode: postgresqlflexibleservers.FailoverModePlannedFailover, + FailoverMode: &failoverMode, } - future, err := client.Restart(ctx, id.ResourceGroup, id.Name, restartParameters) - if err != nil { + if err = restartClient.ServersRestartThenPoll(ctx, restartServerId, restartParameters); err != nil { return fmt.Errorf("failing over %s: %+v", *id, err) } - - if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for failover of %s: %+v", *id, err) - } } return resourcePostgresqlFlexibleServerRead(d, meta) @@ -536,139 +539,135 @@ func resourcePostgresqlFlexibleServerDelete(d *pluginsdk.ResourceData, meta inte ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.FlexibleServerID(d.Id()) + id, err := servers.ParseFlexibleServerID(d.Id()) if err != nil { return err } - future, err := client.Delete(ctx, id.ResourceGroup, id.Name) - if err != nil { - return fmt.Errorf("deleting Postgresql Flexible Server %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) - } - - if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for the deletion of the Postgresql Flexible Server %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + if err = client.DeleteThenPoll(ctx, *id); err != nil { + return fmt.Errorf("deleting %s: %+v", id, err) } return nil } -func expandArmServerNetwork(d *pluginsdk.ResourceData) *postgresqlflexibleservers.Network { - network := postgresqlflexibleservers.Network{} +func expandArmServerNetwork(d *pluginsdk.ResourceData) *servers.Network { + network := servers.Network{} if v, ok := d.GetOk("delegated_subnet_id"); ok { - network.DelegatedSubnetResourceID = utils.String(v.(string)) + network.DelegatedSubnetResourceId = utils.String(v.(string)) } if v, ok := d.GetOk("private_dns_zone_id"); ok { - network.PrivateDNSZoneArmResourceID = utils.String(v.(string)) + network.PrivateDnsZoneArmResourceId = utils.String(v.(string)) } return &network } -func expandArmServerMaintenanceWindow(input []interface{}) *postgresqlflexibleservers.MaintenanceWindow { +func expandArmServerMaintenanceWindow(input []interface{}) *servers.MaintenanceWindow { if len(input) == 0 { - return &postgresqlflexibleservers.MaintenanceWindow{ + return &servers.MaintenanceWindow{ CustomWindow: utils.String(ServerMaintenanceWindowDisabled), } } v := input[0].(map[string]interface{}) - maintenanceWindow := postgresqlflexibleservers.MaintenanceWindow{ + maintenanceWindow := servers.MaintenanceWindow{ CustomWindow: utils.String(ServerMaintenanceWindowEnabled), - StartHour: utils.Int32(int32(v["start_hour"].(int))), - StartMinute: utils.Int32(int32(v["start_minute"].(int))), - DayOfWeek: utils.Int32(int32(v["day_of_week"].(int))), + StartHour: utils.Int64(int64(v["start_hour"].(int))), + StartMinute: utils.Int64(int64(v["start_minute"].(int))), + DayOfWeek: utils.Int64(int64(v["day_of_week"].(int))), } return &maintenanceWindow } -func expandArmServerStorage(d *pluginsdk.ResourceData) *postgresqlflexibleservers.Storage { - storage := postgresqlflexibleservers.Storage{} +func expandArmServerStorage(d *pluginsdk.ResourceData) *servers.Storage { + storage := servers.Storage{} if v, ok := d.GetOk("storage_mb"); ok { - storage.StorageSizeGB = utils.Int32(int32(v.(int) / 1024)) + storage.StorageSizeGB = utils.Int64(int64(v.(int) / 1024)) } return &storage } -func expandArmServerBackup(d *pluginsdk.ResourceData) *postgresqlflexibleservers.Backup { - backup := postgresqlflexibleservers.Backup{} +func expandArmServerBackup(d *pluginsdk.ResourceData) *servers.Backup { + backup := servers.Backup{} if v, ok := d.GetOk("backup_retention_days"); ok { - backup.BackupRetentionDays = utils.Int32(int32(v.(int))) + backup.BackupRetentionDays = utils.Int64(int64(v.(int))) } + geoRedundantEnabled := servers.GeoRedundantBackupEnumDisabled if geoRedundantBackupEnabled := d.Get("geo_redundant_backup_enabled").(bool); geoRedundantBackupEnabled { - backup.GeoRedundantBackup = postgresqlflexibleservers.GeoRedundantBackupEnumEnabled - } else { - backup.GeoRedundantBackup = postgresqlflexibleservers.GeoRedundantBackupEnumDisabled + geoRedundantEnabled = servers.GeoRedundantBackupEnumEnabled } + backup.GeoRedundantBackup = &geoRedundantEnabled + return &backup } -func expandFlexibleServerSku(name string) (*postgresqlflexibleservers.Sku, error) { +func expandFlexibleServerSku(name string) (*servers.Sku, error) { if name == "" { return nil, nil } parts := strings.SplitAfterN(name, "_", 2) - var tier postgresqlflexibleservers.SkuTier + var tier servers.SkuTier switch strings.TrimSuffix(parts[0], "_") { case "B": - tier = postgresqlflexibleservers.SkuTierBurstable + tier = servers.SkuTierBurstable case "GP": - tier = postgresqlflexibleservers.SkuTierGeneralPurpose + tier = servers.SkuTierGeneralPurpose case "MO": - tier = postgresqlflexibleservers.SkuTierMemoryOptimized + tier = servers.SkuTierMemoryOptimized default: return nil, fmt.Errorf("sku_name %s has unknown sku tier %s", name, parts[0]) } - return &postgresqlflexibleservers.Sku{ - Name: utils.String(parts[1]), + return &servers.Sku{ + Name: parts[1], Tier: tier, }, nil } -func flattenFlexibleServerSku(sku *postgresqlflexibleservers.Sku) (string, error) { - if sku == nil || sku.Name == nil || sku.Tier == "" { +func flattenFlexibleServerSku(sku *servers.Sku) (string, error) { + if sku == nil || sku.Tier == "" { return "", nil } var tier string switch sku.Tier { - case postgresqlflexibleservers.SkuTierBurstable: + case servers.SkuTierBurstable: tier = "B" - case postgresqlflexibleservers.SkuTierGeneralPurpose: + case servers.SkuTierGeneralPurpose: tier = "GP" - case postgresqlflexibleservers.SkuTierMemoryOptimized: + case servers.SkuTierMemoryOptimized: tier = "MO" default: return "", fmt.Errorf("sku_name has unknown sku tier %s", sku.Tier) } - return strings.Join([]string{tier, *sku.Name}, "_"), nil + return strings.Join([]string{tier, sku.Name}, "_"), nil } -func flattenArmServerMaintenanceWindow(input *postgresqlflexibleservers.MaintenanceWindow) []interface{} { - if input == nil || input.CustomWindow == nil || *input.CustomWindow == string(ServerMaintenanceWindowDisabled) { +func flattenArmServerMaintenanceWindow(input *servers.MaintenanceWindow) []interface{} { + if input == nil || input.CustomWindow == nil || *input.CustomWindow == ServerMaintenanceWindowDisabled { return make([]interface{}, 0) } - var dayOfWeek int32 + var dayOfWeek int64 if input.DayOfWeek != nil { dayOfWeek = *input.DayOfWeek } - var startHour int32 + var startHour int64 if input.StartHour != nil { startHour = *input.StartHour } - var startMinute int32 + var startMinute int64 if input.StartMinute != nil { startMinute = *input.StartMinute } @@ -681,17 +680,19 @@ func flattenArmServerMaintenanceWindow(input *postgresqlflexibleservers.Maintena } } -func expandFlexibleServerHighAvailability(inputs []interface{}, isCreate bool) *postgresqlflexibleservers.HighAvailability { +func expandFlexibleServerHighAvailability(inputs []interface{}, isCreate bool) *servers.HighAvailability { if len(inputs) == 0 || inputs[0] == nil { - return &postgresqlflexibleservers.HighAvailability{ - Mode: postgresqlflexibleservers.HighAvailabilityModeDisabled, + highAvailability := servers.HighAvailabilityModeDisabled + return &servers.HighAvailability{ + Mode: &highAvailability, } } input := inputs[0].(map[string]interface{}) - result := postgresqlflexibleservers.HighAvailability{ - Mode: postgresqlflexibleservers.HighAvailabilityMode(input["mode"].(string)), + mode := servers.HighAvailabilityMode(input["mode"].(string)) + result := servers.HighAvailability{ + Mode: &mode, } // service team confirmed it doesn't support to update `high_availability.0.standby_availability_zone` after the PostgreSQL Flexible Server resource is created @@ -704,8 +705,8 @@ func expandFlexibleServerHighAvailability(inputs []interface{}, isCreate bool) * return &result } -func flattenFlexibleServerHighAvailability(ha *postgresqlflexibleservers.HighAvailability) []interface{} { - if ha == nil || ha.Mode == postgresqlflexibleservers.HighAvailabilityModeDisabled { +func flattenFlexibleServerHighAvailability(ha *servers.HighAvailability) []interface{} { + if ha == nil || ha.Mode == nil || *ha.Mode == servers.HighAvailabilityModeDisabled { return []interface{}{} } @@ -716,7 +717,7 @@ func flattenFlexibleServerHighAvailability(ha *postgresqlflexibleservers.HighAva return []interface{}{ map[string]interface{}{ - "mode": string(ha.Mode), + "mode": string(*ha.Mode), "standby_availability_zone": zone, }, } diff --git a/internal/services/postgres/postgresql_flexible_server_resource_test.go b/internal/services/postgres/postgresql_flexible_server_resource_test.go index 9e874fff3c70..d5415ce1cb3e 100644 --- a/internal/services/postgres/postgresql_flexible_server_resource_test.go +++ b/internal/services/postgres/postgresql_flexible_server_resource_test.go @@ -6,10 +6,10 @@ import ( "testing" "time" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2021-06-01/servers" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -241,17 +241,17 @@ func TestAccPostgresqlFlexibleServer_geoRedundantBackupEnabled(t *testing.T) { } func (PostgresqlFlexibleServerResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.FlexibleServerID(state.ID) + id, err := servers.ParseFlexibleServerID(state.ID) if err != nil { return nil, err } - resp, err := clients.Postgres.FlexibleServersClient.Get(ctx, id.ResourceGroup, id.Name) + resp, err := clients.Postgres.FlexibleServersClient.Get(ctx, *id) if err != nil { - return nil, fmt.Errorf("retrieving Postgresql Flexible Server %q (resource group: %q): %+v", id.Name, id.ResourceGroup, err) + return nil, fmt.Errorf("retrieving %s: %+v", id, err) } - return utils.Bool(resp.ServerProperties != nil), nil + return utils.Bool(resp.Model != nil), nil } func (PostgresqlFlexibleServerResource) template(data acceptance.TestData) string { diff --git a/internal/services/postgres/postgresql_server_data_source.go b/internal/services/postgres/postgresql_server_data_source.go index 684e80077672..a4787299d113 100644 --- a/internal/services/postgres/postgresql_server_data_source.go +++ b/internal/services/postgres/postgresql_server_data_source.go @@ -4,14 +4,15 @@ import ( "fmt" "time" + "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/identity" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" - "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" - "github.com/hashicorp/terraform-provider-azurerm/utils" ) func dataSourcePostgreSqlServer() *pluginsdk.Resource { @@ -57,7 +58,7 @@ func dataSourcePostgreSqlServer() *pluginsdk.Resource { "identity": commonschema.SystemAssignedIdentityComputed(), - "tags": tags.SchemaDataSource(), + "tags": commonschema.TagsDataSource(), }, } } @@ -68,10 +69,10 @@ func dataSourcePostgreSqlServerRead(d *pluginsdk.ResourceData, meta interface{}) ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id := parse.NewServerID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) - resp, err := client.Get(ctx, id.ResourceGroup, id.Name) + id := servers.NewServerID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) + resp, err := client.Get(ctx, id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { return fmt.Errorf("%s was not found", id) } @@ -79,23 +80,26 @@ func dataSourcePostgreSqlServerRead(d *pluginsdk.ResourceData, meta interface{}) } d.SetId(id.ID()) - if location := resp.Location; location != nil { - d.Set("location", azure.NormalizeLocation(*location)) - } - if err := d.Set("identity", flattenServerIdentity(resp.Identity)); err != nil { - return fmt.Errorf("setting `identity`: %+v", err) - } + if model := resp.Model; model != nil { + d.Set("location", azure.NormalizeLocation(model.Location)) - if props := resp.ServerProperties; props != nil { - d.Set("fqdn", props.FullyQualifiedDomainName) - d.Set("version", props.Version) - d.Set("administrator_login", props.AdministratorLogin) - } + if err := d.Set("identity", identity.FlattenSystemAssigned(model.Identity)); err != nil { + return fmt.Errorf("setting `identity`: %+v", err) + } + + if props := model.Properties; props != nil { + d.Set("fqdn", props.FullyQualifiedDomainName) + d.Set("version", props.Version) + d.Set("administrator_login", props.AdministratorLogin) + } + + if sku := model.Sku; sku != nil { + d.Set("sku_name", sku.Name) + } - if sku := resp.Sku; sku != nil { - d.Set("sku_name", sku.Name) + return tags.FlattenAndSet(d, model.Tags) } - return tags.FlattenAndSet(d, resp.Tags) + return nil } diff --git a/internal/services/postgres/postgresql_server_key_resource.go b/internal/services/postgres/postgresql_server_key_resource.go index c44038a3d35e..1d54ce9cd313 100644 --- a/internal/services/postgres/postgresql_server_key_resource.go +++ b/internal/services/postgres/postgresql_server_key_resource.go @@ -6,15 +6,14 @@ import ( "log" "time" - "github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2020-01-01/postgresql" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2020-01-01/serverkeys" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/locks" "github.com/hashicorp/terraform-provider-azurerm/internal/services/keyvault/client" keyVaultParse "github.com/hashicorp/terraform-provider-azurerm/internal/services/keyvault/parse" keyVaultValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/keyvault/validate" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/validate" resourcesClient "github.com/hashicorp/terraform-provider-azurerm/internal/services/resource/client" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" @@ -29,7 +28,7 @@ func resourcePostgreSQLServerKey() *pluginsdk.Resource { Delete: resourcePostgreSQLServerKeyDelete, Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - _, err := parse.ServerKeyID(id) + _, err := serverkeys.ParseKeyID(id) return err }), @@ -45,7 +44,7 @@ func resourcePostgreSQLServerKey() *pluginsdk.Resource { Type: pluginsdk.TypeString, Required: true, ForceNew: true, - ValidateFunc: validate.ServerID, + ValidateFunc: serverkeys.ValidateServerID, }, "key_vault_key_id": { @@ -84,31 +83,31 @@ func resourcePostgreSQLServerKeyCreateUpdate(d *pluginsdk.ResourceData, meta int ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) defer cancel() - serverId, err := parse.ServerID(d.Get("server_id").(string)) + serverId, err := serverkeys.ParseServerID(d.Get("server_id").(string)) if err != nil { return err } keyVaultKeyURI := d.Get("key_vault_key_id").(string) name, err := getPostgreSQLServerKeyName(ctx, keyVaultsClient, resourcesClient, keyVaultKeyURI) if err != nil { - return fmt.Errorf("cannot compose name for PostgreSQL Server Key (Resource Group %q / Server %q): %+v", serverId.ResourceGroup, serverId.Name, err) + return fmt.Errorf("cannot compose name for %s: %+v", serverId, err) } - locks.ByName(serverId.Name, postgreSQLServerResourceName) - defer locks.UnlockByName(serverId.Name, postgreSQLServerResourceName) + locks.ByName(serverId.ServerName, postgreSQLServerResourceName) + defer locks.UnlockByName(serverId.ServerName, postgreSQLServerResourceName) if d.IsNewResource() { // This resource is a singleton, but its name can be anything. // If you create a new key with different name with the old key, the service will not give you any warning but directly replace the old key with the new key. // Therefore sometimes you cannot get the old key using the GET API since you may not know the name of the old key - resp, err := keysClient.List(ctx, serverId.ResourceGroup, serverId.Name) + resp, err := keysClient.List(ctx, *serverId) if err != nil { - return fmt.Errorf("listing existing PostgreSQL Server Keys in Resource Group %q / Server %q: %+v", serverId.ResourceGroup, serverId.Name, err) + return fmt.Errorf("listing existing Keys in %s: %+v", serverId, err) } - keys := resp.Values() - if len(keys) >= 1 { - if rawId := keys[0].ID; rawId != nil && *rawId != "" { - id, err := parse.ServerKeyID(*rawId) + if resp.Model != nil && len(*resp.Model) >= 1 { + keys := *resp.Model + if rawId := keys[0].Id; rawId != nil && *rawId != "" { + id, err := serverkeys.ParseKeyID(*rawId) if err != nil { return fmt.Errorf("parsing existing Server Key ID %q: %+v", *rawId, err) } @@ -118,21 +117,17 @@ func resourcePostgreSQLServerKeyCreateUpdate(d *pluginsdk.ResourceData, meta int } } - param := postgresql.ServerKey{ - ServerKeyProperties: &postgresql.ServerKeyProperties{ - ServerKeyType: utils.String("AzureKeyVault"), - URI: utils.String(d.Get("key_vault_key_id").(string)), + param := serverkeys.ServerKey{ + Properties: &serverkeys.ServerKeyProperties{ + ServerKeyType: serverkeys.ServerKeyTypeAzureKeyVault, + Uri: utils.String(d.Get("key_vault_key_id").(string)), }, } - id := parse.NewServerKeyID(serverId.SubscriptionId, serverId.ResourceGroup, serverId.Name, *name) - future, err := keysClient.CreateOrUpdate(ctx, id.ServerName, id.KeyName, param, id.ResourceGroup) - if err != nil { + id := serverkeys.NewKeyID(serverId.SubscriptionId, serverId.ResourceGroupName, serverId.ServerName, *name) + if err = keysClient.CreateOrUpdateThenPoll(ctx, id, param); err != nil { return fmt.Errorf("creating/updating %s: %+v", id, err) } - if err := future.WaitForCompletionRef(ctx, keysClient.Client); err != nil { - return fmt.Errorf("waiting for creation/update of %s: %+v", id, err) - } d.SetId(id.ID()) return resourcePostgreSQLServerKeyRead(d, meta) @@ -143,14 +138,14 @@ func resourcePostgreSQLServerKeyRead(d *pluginsdk.ResourceData, meta interface{} ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.ServerKeyID(d.Id()) + id, err := serverkeys.ParseKeyID(d.Id()) if err != nil { return err } - resp, err := keysClient.Get(ctx, id.ResourceGroup, id.ServerName, id.KeyName) + resp, err := keysClient.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { log.Printf("[WARN] %s was not found - removing from state", *id) d.SetId("") return nil @@ -159,9 +154,9 @@ func resourcePostgreSQLServerKeyRead(d *pluginsdk.ResourceData, meta interface{} return fmt.Errorf("retrieving %s: %+v", *id, err) } - d.Set("server_id", parse.NewServerID(id.SubscriptionId, id.ResourceGroup, id.ServerName).ID()) - if props := resp.ServerKeyProperties; props != nil { - d.Set("key_vault_key_id", props.URI) + d.Set("server_id", serverkeys.NewServerID(id.SubscriptionId, id.ResourceGroupName, id.ServerName).ID()) + if resp.Model != nil && resp.Model.Properties != nil { + d.Set("key_vault_key_id", resp.Model.Properties.Uri) } return nil @@ -172,7 +167,7 @@ func resourcePostgreSQLServerKeyDelete(d *pluginsdk.ResourceData, meta interface ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.ServerKeyID(d.Id()) + id, err := serverkeys.ParseKeyID(d.Id()) if err != nil { return err } @@ -180,13 +175,9 @@ func resourcePostgreSQLServerKeyDelete(d *pluginsdk.ResourceData, meta interface locks.ByName(id.ServerName, postgreSQLServerResourceName) defer locks.UnlockByName(id.ServerName, postgreSQLServerResourceName) - future, err := client.Delete(ctx, id.ServerName, id.KeyName, id.ResourceGroup) - if err != nil { + if err = client.DeleteThenPoll(ctx, *id); err != nil { return fmt.Errorf("deleting %s: %+v", *id, err) } - if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for deletion of %s: %+v", *id, err) - } return nil } diff --git a/internal/services/postgres/postgresql_server_key_resource_test.go b/internal/services/postgres/postgresql_server_key_resource_test.go index 5e2a2f1f563e..ae8ec247aa10 100644 --- a/internal/services/postgres/postgresql_server_key_resource_test.go +++ b/internal/services/postgres/postgresql_server_key_resource_test.go @@ -5,10 +5,10 @@ import ( "fmt" "testing" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2020-01-01/serverkeys" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -68,17 +68,17 @@ func TestAccPostgreSQLServerKey_requiresImport(t *testing.T) { } func (t PostgreSQLServerKeyResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.ServerKeyID(state.ID) + id, err := serverkeys.ParseKeyID(state.ID) if err != nil { return nil, err } - resp, err := clients.Postgres.ServerKeysClient.Get(ctx, id.ResourceGroup, id.ServerName, id.KeyName) + resp, err := clients.Postgres.ServerKeysClient.Get(ctx, *id) if err != nil { return nil, fmt.Errorf("reading Postgresql Server Key (%s): %+v", id.String(), err) } - return utils.Bool(resp.ID != nil), nil + return utils.Bool(resp.Model != nil), nil } func (PostgreSQLServerKeyResource) template(data acceptance.TestData) string { diff --git a/internal/services/postgres/postgresql_server_resource.go b/internal/services/postgres/postgresql_server_resource.go index 7df6d83f677e..d65cb06779f6 100644 --- a/internal/services/postgres/postgresql_server_resource.go +++ b/internal/services/postgres/postgresql_server_resource.go @@ -8,18 +8,21 @@ import ( "strings" "time" - "github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2020-01-01/postgresql" - "github.com/Azure/go-autorest/autorest/date" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/migration" + + "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/identity" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/replicas" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/serversecurityalertpolicies" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/locks" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/validate" - "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" @@ -61,30 +64,34 @@ func resourcePostgreSQLServer() *pluginsdk.Resource { Delete: resourcePostgreSQLServerDelete, Importer: pluginsdk.ImporterValidatingResourceIdThen(func(id string) error { - _, err := parse.ServerID(id) + _, err := servers.ParseServerID(id) return err }, func(ctx context.Context, d *pluginsdk.ResourceData, meta interface{}) ([]*pluginsdk.ResourceData, error) { client := meta.(*clients.Client).Postgres.ServersClient - id, err := parse.ServerID(d.Id()) + id, err := servers.ParseServerID(d.Id()) if err != nil { return []*pluginsdk.ResourceData{d}, err } - resp, err := client.Get(ctx, id.ResourceGroup, id.Name) + resp, err := client.Get(ctx, *id) if err != nil { - return []*pluginsdk.ResourceData{d}, fmt.Errorf("reading PostgreSQL Server %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + return []*pluginsdk.ResourceData{d}, fmt.Errorf("reading %s: %+v", id, err) } d.Set("create_mode", "Default") - if resp.ReplicationRole != nil && *resp.ReplicationRole != "Master" && *resp.ReplicationRole != "None" { - d.Set("create_mode", resp.ReplicationRole) - - sourceServerId, err := parse.ServerID(*resp.MasterServerID) - if err != nil { - return []*pluginsdk.ResourceData{d}, fmt.Errorf("parsing Postgres Main Server ID : %v", err) + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + if props.ReplicationRole != nil && *props.ReplicationRole != "Master" && *props.ReplicationRole != "None" { + d.Set("create_mode", props.ReplicationRole) + + sourceServerId, err := servers.ParseServerID(*props.MasterServerId) + if err != nil { + return []*pluginsdk.ResourceData{d}, fmt.Errorf("parsing Postgres Main Server ID : %v", err) + } + d.Set("creation_source_server_id", sourceServerId.ID()) + } } - d.Set("creation_source_server_id", sourceServerId.ID()) } return []*pluginsdk.ResourceData{d}, nil @@ -97,6 +104,11 @@ func resourcePostgreSQLServer() *pluginsdk.Resource { Delete: pluginsdk.DefaultTimeout(60 * time.Minute), }, + SchemaVersion: 1, + StateUpgraders: pluginsdk.StateUpgrades(map[int]pluginsdk.StateUpgrade{ + 0: migration.PostgresqlServerV0ToV1{}, + }), + Schema: map[string]*pluginsdk.Schema{ "name": { Type: pluginsdk.TypeString, @@ -116,16 +128,10 @@ func resourcePostgreSQLServer() *pluginsdk.Resource { }, "version": { - Type: pluginsdk.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validation.StringInSlice([]string{ - string(postgresql.NineFullStopFive), - string(postgresql.NineFullStopSix), - string(postgresql.OneOne), - string(postgresql.OneZero), - string(postgresql.OneZeroFullStopZero), - }, false), + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice(servers.PossibleValuesForServerVersion(), false), }, "administrator_login": { @@ -163,21 +169,16 @@ func resourcePostgreSQLServer() *pluginsdk.Resource { }, "create_mode": { - Type: pluginsdk.TypeString, - Optional: true, - Default: string(postgresql.CreateModeDefault), - ValidateFunc: validation.StringInSlice([]string{ - string(postgresql.CreateModeDefault), - string(postgresql.CreateModeGeoRestore), - string(postgresql.CreateModePointInTimeRestore), - string(postgresql.CreateModeReplica), - }, false), + Type: pluginsdk.TypeString, + Optional: true, + Default: string(servers.CreateModeDefault), + ValidateFunc: validation.StringInSlice(servers.PossibleValuesForCreateMode(), false), }, "creation_source_server_id": { Type: pluginsdk.TypeString, Optional: true, - ValidateFunc: validate.ServerID, + ValidateFunc: servers.ValidateServerID, }, "identity": commonschema.SystemAssignedIdentityOptional(), @@ -211,15 +212,10 @@ func resourcePostgreSQLServer() *pluginsdk.Resource { }, "ssl_minimal_tls_version_enforced": { - Type: pluginsdk.TypeString, - Optional: true, - Default: string(postgresql.TLS12), - ValidateFunc: validation.StringInSlice([]string{ - string(postgresql.TLSEnforcementDisabled), - string(postgresql.TLS10), - string(postgresql.TLS11), - string(postgresql.TLS12), - }, false), + Type: pluginsdk.TypeString, + Optional: true, + Default: string(servers.MinimalTlsVersionEnumTLSOneTwo), + ValidateFunc: validation.StringInSlice(servers.PossibleValuesForMinimalTlsVersionEnum(), false), }, "ssl_enforcement_enabled": { @@ -331,7 +327,7 @@ func resourcePostgreSQLServer() *pluginsdk.Resource { Computed: true, }, - "tags": tags.Schema(), + "tags": commonschema.Tags(), }, CustomizeDiff: pluginsdk.CustomDiffWithAll( @@ -349,10 +345,10 @@ func resourcePostgreSQLServer() *pluginsdk.Resource { return false }), pluginsdk.ForceNewIfChange("create_mode", func(ctx context.Context, old, new, meta interface{}) bool { - oldMode := postgresql.CreateMode(old.(string)) - newMode := postgresql.CreateMode(new.(string)) + oldMode := servers.CreateMode(old.(string)) + newMode := servers.CreateMode(new.(string)) // Instance could not be changed from Default to Replica - if oldMode == postgresql.CreateModeDefault && newMode == postgresql.CreateModeReplica { + if oldMode == servers.CreateModeDefault && newMode == servers.CreateModeReplica { return true } return false @@ -370,52 +366,51 @@ func resourcePostgreSQLServerCreate(d *pluginsdk.ResourceData, meta interface{}) log.Printf("[INFO] preparing arguments for AzureRM PostgreSQL Server creation.") - id := parse.NewServerID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) - existing, err := client.Get(ctx, id.ResourceGroup, id.Name) + id := servers.NewServerID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) + existing, err := client.Get(ctx, id) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return fmt.Errorf("checking for presence of existing %s: %+v", id, err) } } - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return tf.ImportAsExistsError("azurerm_postgresql_server", id.ID()) } - mode := postgresql.CreateMode(d.Get("create_mode").(string)) + mode := servers.CreateMode(d.Get("create_mode").(string)) source := d.Get("creation_source_server_id").(string) - version := postgresql.ServerVersion(d.Get("version").(string)) + version := servers.ServerVersion(d.Get("version").(string)) sku, err := expandServerSkuName(d.Get("sku_name").(string)) if err != nil { return fmt.Errorf("expanding `sku_name`: %+v", err) } - infraEncrypt := postgresql.InfrastructureEncryptionEnabled + infraEncrypt := servers.InfrastructureEncryptionEnabled if v := d.Get("infrastructure_encryption_enabled"); !v.(bool) { - infraEncrypt = postgresql.InfrastructureEncryptionDisabled + infraEncrypt = servers.InfrastructureEncryptionDisabled } - publicAccess := postgresql.PublicNetworkAccessEnumEnabled + publicAccess := servers.PublicNetworkAccessEnumEnabled if v := d.Get("public_network_access_enabled"); !v.(bool) { - publicAccess = postgresql.PublicNetworkAccessEnumDisabled + publicAccess = servers.PublicNetworkAccessEnumDisabled } - ssl := postgresql.SslEnforcementEnumEnabled + ssl := servers.SslEnforcementEnumEnabled if v := d.Get("ssl_enforcement_enabled"); !v.(bool) { - ssl = postgresql.SslEnforcementEnumDisabled + ssl = servers.SslEnforcementEnumDisabled } - tlsMin := postgresql.MinimalTLSVersionEnum(d.Get("ssl_minimal_tls_version_enforced").(string)) - if ssl == postgresql.SslEnforcementEnumDisabled && tlsMin != postgresql.TLSEnforcementDisabled { + tlsMin := servers.MinimalTlsVersionEnum(d.Get("ssl_minimal_tls_version_enforced").(string)) + if ssl == servers.SslEnforcementEnumDisabled && tlsMin != servers.MinimalTlsVersionEnumTLSEnforcementDisabled { return fmt.Errorf("`ssl_minimal_tls_version_enforced` must be set to `TLSEnforcementDisabled` if `ssl_enforcement_enabled` is set to `false`") } storage := expandPostgreSQLStorageProfile(d) - - var props postgresql.BasicServerPropertiesForCreate + var props servers.ServerPropertiesForCreate switch mode { - case postgresql.CreateModeDefault: + case servers.CreateModeDefault: admin := d.Get("administrator_login").(string) pass := d.Get("administrator_login_password").(string) if admin == "" { @@ -430,89 +425,77 @@ func resourcePostgreSQLServerCreate(d *pluginsdk.ResourceData, meta interface{}) } // check admin - props = &postgresql.ServerPropertiesForDefaultCreate{ - AdministratorLogin: &admin, - AdministratorLoginPassword: &pass, - CreateMode: mode, - InfrastructureEncryption: infraEncrypt, - PublicNetworkAccess: publicAccess, - MinimalTLSVersion: tlsMin, - SslEnforcement: ssl, + props = servers.ServerPropertiesForDefaultCreate{ + AdministratorLogin: admin, + AdministratorLoginPassword: pass, + InfrastructureEncryption: &infraEncrypt, + PublicNetworkAccess: &publicAccess, + MinimalTlsVersion: &tlsMin, + SslEnforcement: &ssl, StorageProfile: storage, - Version: version, + Version: &version, } - case postgresql.CreateModePointInTimeRestore: + case servers.CreateModePointInTimeRestore: v, ok := d.GetOk("restore_point_in_time") if !ok || v.(string) == "" { return fmt.Errorf("restore_point_in_time must be set when create_mode is PointInTimeRestore") } - time, _ := time.Parse(time.RFC3339, v.(string)) // should be validated by the schema // d.GetOk cannot identify whether user sets the property that is bool type and has default value. So it has to identify it using `d.GetRawConfig()` if v := d.GetRawConfig().AsValueMap()["public_network_access_enabled"]; !v.IsNull() { return fmt.Errorf("`public_network_access_enabled` doesn't support PointInTimeRestore mode") } - props = &postgresql.ServerPropertiesForRestore{ - CreateMode: mode, - SourceServerID: &source, - RestorePointInTime: &date.Time{ - Time: time, - }, - InfrastructureEncryption: infraEncrypt, - MinimalTLSVersion: tlsMin, - SslEnforcement: ssl, + props = &servers.ServerPropertiesForRestore{ + SourceServerId: source, + RestorePointInTime: v.(string), + InfrastructureEncryption: &infraEncrypt, + MinimalTlsVersion: &tlsMin, + SslEnforcement: &ssl, StorageProfile: storage, - Version: version, - } - case postgresql.CreateModeGeoRestore: - props = &postgresql.ServerPropertiesForGeoRestore{ - CreateMode: mode, - SourceServerID: &source, - InfrastructureEncryption: infraEncrypt, - PublicNetworkAccess: publicAccess, - MinimalTLSVersion: tlsMin, - SslEnforcement: ssl, + Version: &version, + } + case servers.CreateModeGeoRestore: + props = &servers.ServerPropertiesForGeoRestore{ + SourceServerId: source, + InfrastructureEncryption: &infraEncrypt, + PublicNetworkAccess: &publicAccess, + MinimalTlsVersion: &tlsMin, + SslEnforcement: &ssl, StorageProfile: storage, - Version: version, + Version: &version, } - case postgresql.CreateModeReplica: - props = &postgresql.ServerPropertiesForReplica{ - CreateMode: mode, - SourceServerID: &source, - InfrastructureEncryption: infraEncrypt, - PublicNetworkAccess: publicAccess, - MinimalTLSVersion: tlsMin, - SslEnforcement: ssl, - Version: version, + case servers.CreateModeReplica: + props = &servers.ServerPropertiesForReplica{ + SourceServerId: source, + InfrastructureEncryption: &infraEncrypt, + PublicNetworkAccess: &publicAccess, + MinimalTlsVersion: &tlsMin, + SslEnforcement: &ssl, + Version: &version, } } - expandedIdentity, err := expandServerIdentity(d.Get("identity").([]interface{})) + expandedIdentity, err := identity.ExpandSystemAssigned(d.Get("identity").([]interface{})) if err != nil { return fmt.Errorf("expanding `identity`: %+v", err) } - server := postgresql.ServerForCreate{ + server := servers.ServerForCreate{ Identity: expandedIdentity, - Location: utils.String(location.Normalize(d.Get("location").(string))), + Location: location.Normalize(d.Get("location").(string)), Properties: props, Sku: sku, Tags: tags.Expand(d.Get("tags").(map[string]interface{})), } - future, err := client.Create(ctx, id.ResourceGroup, id.Name, server) - if err != nil { + if err = client.CreateThenPoll(ctx, id, server); err != nil { return fmt.Errorf("creating %s: %+v", id, err) } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for creation of %s: %+v", id, err) - } - log.Printf("[DEBUG] Waiting for %s to become available", id) stateConf := &pluginsdk.StateChangeConf{ - Pending: []string{string(postgresql.ServerStateInaccessible)}, - Target: []string{string(postgresql.ServerStateReady)}, + Pending: []string{string(servers.ServerStateInaccessible)}, + Target: []string{string(servers.ServerStateReady)}, Refresh: postgreSqlStateRefreshFunc(ctx, client, id), MinTimeout: 15 * time.Second, Timeout: d.Timeout(pluginsdk.TimeoutCreate), @@ -525,36 +508,28 @@ func resourcePostgreSQLServerCreate(d *pluginsdk.ResourceData, meta interface{}) d.SetId(id.ID()) if v, ok := d.GetOk("threat_detection_policy"); ok { + securityAlertId := serversecurityalertpolicies.NewServerID(id.SubscriptionId, id.ResourceGroupName, id.ServerName) alert := expandSecurityAlertPolicy(v) if alert != nil { - future, err := securityClient.CreateOrUpdate(ctx, id.ResourceGroup, id.Name, *alert) - if err != nil { + if err = securityClient.CreateOrUpdateThenPoll(ctx, securityAlertId, *alert); err != nil { return fmt.Errorf("updataing security alert policy for %s: %v", id, err) } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for update of security alert policy for %s: %+v", id, err) - } } } // Issue tracking the REST API update failure: https://github.com/Azure/azure-rest-api-specs/issues/14117 - if mode == postgresql.CreateModeReplica { + if mode == servers.CreateModeReplica { log.Printf("[INFO] updating `public_network_access_enabled` for %s", id) - properties := postgresql.ServerUpdateParameters{ - ServerUpdateParametersProperties: &postgresql.ServerUpdateParametersProperties{ - PublicNetworkAccess: publicAccess, + properties := servers.ServerUpdateParameters{ + Properties: &servers.ServerUpdateParametersProperties{ + PublicNetworkAccess: &publicAccess, }, } - future, err := client.Update(ctx, id.ResourceGroup, id.Name, properties) - if err != nil { + if err = client.UpdateThenPoll(ctx, id, properties); err != nil { return fmt.Errorf("updating Public Network Access for Replica %q: %+v", id, err) } - - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for update of Public Network Access for Replica %q: %+v", id, err) - } } return resourcePostgreSQLServerRead(d, meta) @@ -569,22 +544,22 @@ func resourcePostgreSQLServerUpdate(d *pluginsdk.ResourceData, meta interface{}) // TODO: support for Delta updates - id, err := parse.ServerID(d.Id()) + id, err := servers.ParseServerID(d.Id()) if err != nil { return fmt.Errorf("parsing Postgres Server ID : %v", err) } // Locks for upscaling of replicas - mode := postgresql.CreateMode(d.Get("create_mode").(string)) + mode := servers.CreateMode(d.Get("create_mode").(string)) primaryID := id.String() - if mode == postgresql.CreateModeReplica { + if mode == servers.CreateModeReplica { primaryID = d.Get("creation_source_server_id").(string) // Wait for possible restarts triggered by scaling primary (and its replicas) log.Printf("[DEBUG] Waiting for %s to become available", *id) stateConf := &pluginsdk.StateChangeConf{ - Pending: []string{string(postgresql.ServerStateInaccessible), "Restarting"}, - Target: []string{string(postgresql.ServerStateReady)}, + Pending: []string{string(servers.ServerStateInaccessible), "Restarting"}, + Target: []string{string(servers.ServerStateReady)}, Refresh: postgreSqlStateRefreshFunc(ctx, client, *id), MinTimeout: 15 * time.Second, Timeout: d.Timeout(pluginsdk.TimeoutCreate), @@ -602,121 +577,110 @@ func resourcePostgreSQLServerUpdate(d *pluginsdk.ResourceData, meta interface{}) return fmt.Errorf("expanding `sku_name`: %v", err) } - if d.HasChange("sku_name") && mode != postgresql.CreateModeReplica { + if d.HasChange("sku_name") && mode != servers.CreateModeReplica { oldRaw, newRaw := d.GetChange("sku_name") old := oldRaw.(string) new := newRaw.(string) if indexOfSku(old) < indexOfSku(new) { - listReplicas, err := replicasClient.ListByServer(ctx, id.ResourceGroup, id.Name) + replicasId := replicas.NewServerID(id.SubscriptionId, id.ResourceGroupName, id.ServerName) + listReplicas, err := replicasClient.ListByServer(ctx, replicasId) if err != nil { return fmt.Errorf("listing replicas for %s: %+v", *id, err) } - propertiesReplica := postgresql.ServerUpdateParameters{ + propertiesReplica := servers.ServerUpdateParameters{ Sku: sku, } - for _, replica := range *listReplicas.Value { - replicaId, err := parse.ServerID(*replica.ID) - if err != nil { - return fmt.Errorf("parsing Postgres Server Replica ID : %v", err) - } - future, err := client.Update(ctx, replicaId.ResourceGroup, replicaId.Name, propertiesReplica) - if err != nil { - return fmt.Errorf("updating SKU for Replica %s: %+v", *replicaId, err) - } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for SKU update for Replica %s: %+v", *replicaId, err) + if listReplicas.Model != nil && listReplicas.Model.Value != nil { + replicaList := *listReplicas.Model.Value + for _, replica := range replicaList { + replicaId, err := servers.ParseServerID(*replica.Id) + if err != nil { + return fmt.Errorf("parsing Postgres Server Replica ID : %v", err) + } + if err = client.UpdateThenPoll(ctx, *replicaId, propertiesReplica); err != nil { + return fmt.Errorf("updating SKU for Replica %s: %+v", *replicaId, err) + } } } } } - ssl := postgresql.SslEnforcementEnumEnabled + ssl := servers.SslEnforcementEnumEnabled if v := d.Get("ssl_enforcement_enabled"); !v.(bool) { - ssl = postgresql.SslEnforcementEnumDisabled + ssl = servers.SslEnforcementEnumDisabled } - tlsMin := postgresql.MinimalTLSVersionEnum(d.Get("ssl_minimal_tls_version_enforced").(string)) + tlsMin := servers.MinimalTlsVersionEnum(d.Get("ssl_minimal_tls_version_enforced").(string)) - if ssl == postgresql.SslEnforcementEnumDisabled && tlsMin != postgresql.TLSEnforcementDisabled { + if ssl == servers.SslEnforcementEnumDisabled && tlsMin != servers.MinimalTlsVersionEnumTLSEnforcementDisabled { return fmt.Errorf("`ssl_minimal_tls_version_enforced` must be set to `TLSEnforcementDisabled` if `ssl_enforcement_enabled` is set to `false`") } - expandedIdentity, err := expandServerIdentity(d.Get("identity").([]interface{})) + expandedIdentity, err := identity.ExpandSystemAssigned(d.Get("identity").([]interface{})) if err != nil { return fmt.Errorf("expanding `identity`: %+v", err) } - properties := postgresql.ServerUpdateParameters{ + serverVersion := servers.ServerVersion(d.Get("version").(string)) + properties := servers.ServerUpdateParameters{ Identity: expandedIdentity, - ServerUpdateParametersProperties: &postgresql.ServerUpdateParametersProperties{ - SslEnforcement: ssl, - MinimalTLSVersion: tlsMin, + Properties: &servers.ServerUpdateParametersProperties{ + SslEnforcement: &ssl, + MinimalTlsVersion: &tlsMin, StorageProfile: expandPostgreSQLStorageProfile(d), - Version: postgresql.ServerVersion(d.Get("version").(string)), + Version: &serverVersion, }, Sku: sku, Tags: tags.Expand(d.Get("tags").(map[string]interface{})), } - if mode == postgresql.CreateModePointInTimeRestore { + if mode == servers.CreateModePointInTimeRestore { // d.GetOk cannot identify whether user sets the property that is bool type and has default value. So it has to identify it using `d.GetRawConfig()` if v := d.GetRawConfig().AsValueMap()["public_network_access_enabled"]; !v.IsNull() { return fmt.Errorf("`public_network_access_enabled` doesn't support PointInTimeRestore mode") } } else { - publicAccess := postgresql.PublicNetworkAccessEnumEnabled + publicAccess := servers.PublicNetworkAccessEnumEnabled if v := d.Get("public_network_access_enabled"); !v.(bool) { - publicAccess = postgresql.PublicNetworkAccessEnumDisabled + publicAccess = servers.PublicNetworkAccessEnumDisabled } - properties.ServerUpdateParametersProperties.PublicNetworkAccess = publicAccess + properties.Properties.PublicNetworkAccess = &publicAccess } oldCreateMode, newCreateMode := d.GetChange("create_mode") - replicaUpdatedToDefault := postgresql.CreateMode(oldCreateMode.(string)) == postgresql.CreateModeReplica && postgresql.CreateMode(newCreateMode.(string)) == postgresql.CreateModeDefault + replicaUpdatedToDefault := servers.CreateMode(oldCreateMode.(string)) == servers.CreateModeReplica && servers.CreateMode(newCreateMode.(string)) == servers.CreateModeDefault if replicaUpdatedToDefault { - properties.ServerUpdateParametersProperties.ReplicationRole = utils.String("None") + properties.Properties.ReplicationRole = utils.String("None") } // Update Admin Password in the separate call when Replication is stopped: https://github.com/Azure/azure-rest-api-specs/issues/16898 if d.HasChange("administrator_login_password") && !replicaUpdatedToDefault { - properties.ServerUpdateParametersProperties.AdministratorLoginPassword = utils.String(d.Get("administrator_login_password").(string)) + properties.Properties.AdministratorLoginPassword = utils.String(d.Get("administrator_login_password").(string)) } - future, err := client.Update(ctx, id.ResourceGroup, id.Name, properties) - if err != nil { + if err = client.UpdateThenPoll(ctx, *id, properties); err != nil { return fmt.Errorf("updating %s: %+v", *id, err) } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for update of %s: %+v", *id, err) - } // Update Admin Password in a separate call when Replication is stopped: https://github.com/Azure/azure-rest-api-specs/issues/16898 if d.HasChange("administrator_login_password") && replicaUpdatedToDefault { - properties.ServerUpdateParametersProperties.AdministratorLoginPassword = utils.String(d.Get("administrator_login_password").(string)) + properties.Properties.AdministratorLoginPassword = utils.String(d.Get("administrator_login_password").(string)) - future, err := client.Update(ctx, id.ResourceGroup, id.Name, properties) - if err != nil { + if err = client.UpdateThenPoll(ctx, *id, properties); err != nil { return fmt.Errorf("updating Admin Password of %q: %+v", id, err) } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for Admin Password update of %q: %+v", id, err) - } } if v, ok := d.GetOk("threat_detection_policy"); ok { alert := expandSecurityAlertPolicy(v) + securityId := serversecurityalertpolicies.NewServerID(id.SubscriptionId, id.ResourceGroupName, id.ServerName) if alert != nil { - future, err := securityClient.CreateOrUpdate(ctx, id.ResourceGroup, id.Name, *alert) - if err != nil { + if err = securityClient.CreateOrUpdateThenPoll(ctx, securityId, *alert); err != nil { return fmt.Errorf("updating security alert policy for %s: %+v", *id, err) } - - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for update of security alert policy for %s: %+v", *id, err) - } } } @@ -729,14 +693,14 @@ func resourcePostgreSQLServerRead(d *pluginsdk.ResourceData, meta interface{}) e ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.ServerID(d.Id()) + id, err := servers.ParseServerID(d.Id()) if err != nil { return fmt.Errorf("parsing Postgres Server ID : %v", err) } - resp, err := client.Get(ctx, id.ResourceGroup, id.Name) + resp, err := client.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { log.Printf("[WARN] %s was not found - removing from state", *id) d.SetId("") return nil @@ -745,56 +709,95 @@ func resourcePostgreSQLServerRead(d *pluginsdk.ResourceData, meta interface{}) e return fmt.Errorf("retrieving %s: %+v", *id, err) } - d.Set("name", id.Name) - d.Set("resource_group_name", id.ResourceGroup) - d.Set("location", location.NormalizeNilable(resp.Location)) + d.Set("name", id.ServerName) + d.Set("resource_group_name", id.ResourceGroupName) - tier := postgresql.Basic - if sku := resp.Sku; sku != nil { - d.Set("sku_name", sku.Name) - tier = sku.Tier - } + if model := resp.Model; model != nil { + d.Set("location", location.NormalizeNilable(&model.Location)) - if err := d.Set("identity", flattenServerIdentity(resp.Identity)); err != nil { - return fmt.Errorf("setting `identity`: %+v", err) - } + tier := servers.SkuTierBasic + if sku := model.Sku; sku != nil { + d.Set("sku_name", sku.Name) + if sku.Tier != nil { + tier = *sku.Tier + } + } - if props := resp.ServerProperties; props != nil { - d.Set("administrator_login", props.AdministratorLogin) - d.Set("ssl_minimal_tls_version_enforced", props.MinimalTLSVersion) - d.Set("version", string(props.Version)) + if err := d.Set("identity", identity.FlattenSystemAssigned(model.Identity)); err != nil { + return fmt.Errorf("setting `identity`: %+v", err) + } - d.Set("infrastructure_encryption_enabled", props.InfrastructureEncryption == postgresql.InfrastructureEncryptionEnabled) - d.Set("public_network_access_enabled", props.PublicNetworkAccess == postgresql.PublicNetworkAccessEnumEnabled) - d.Set("ssl_enforcement_enabled", props.SslEnforcement == postgresql.SslEnforcementEnumEnabled) + if props := model.Properties; props != nil { + d.Set("administrator_login", props.AdministratorLogin) + d.Set("ssl_minimal_tls_version_enforced", props.MinimalTlsVersion) - if storage := props.StorageProfile; storage != nil { - d.Set("storage_mb", storage.StorageMB) - d.Set("backup_retention_days", storage.BackupRetentionDays) - d.Set("auto_grow_enabled", storage.StorageAutogrow == postgresql.StorageAutogrowEnabled) - d.Set("geo_redundant_backup_enabled", storage.GeoRedundantBackup == postgresql.Enabled) - } + version := "" + if props.Version != nil { + version = string(*props.Version) + } + d.Set("version", version) - // Computed - d.Set("fqdn", props.FullyQualifiedDomainName) - } + infrastructureEncryption := false + if props.InfrastructureEncryption != nil { + infrastructureEncryption = *props.InfrastructureEncryption == servers.InfrastructureEncryptionEnabled + } + d.Set("infrastructure_encryption_enabled", infrastructureEncryption) + + publicNetworkAccess := false + if props.PublicNetworkAccess != nil { + publicNetworkAccess = *props.PublicNetworkAccess == servers.PublicNetworkAccessEnumEnabled + } + d.Set("public_network_access_enabled", publicNetworkAccess) + + sslEnforcement := false + if props.SslEnforcement != nil { + sslEnforcement = *props.SslEnforcement == servers.SslEnforcementEnumEnabled + } + d.Set("ssl_enforcement_enabled", sslEnforcement) + + if storage := props.StorageProfile; storage != nil { + d.Set("storage_mb", storage.StorageMB) + d.Set("backup_retention_days", storage.BackupRetentionDays) + + autoGrow := false + if storage.StorageAutogrow != nil { + autoGrow = *storage.StorageAutogrow == servers.StorageAutogrowEnabled + } + d.Set("auto_grow_enabled", autoGrow) - // the basic does not support threat detection policies - if tier == postgresql.GeneralPurpose || tier == postgresql.MemoryOptimized { - secResp, err := securityClient.Get(ctx, id.ResourceGroup, id.Name) - if err != nil && !utils.ResponseWasNotFound(secResp.Response) { - return fmt.Errorf("making read request to postgres server security alert policy: %+v", err) + geoRedundant := false + if storage.GeoRedundantBackup != nil { + geoRedundant = *storage.GeoRedundantBackup == servers.GeoRedundantBackupEnabled + } + d.Set("geo_redundant_backup_enabled", geoRedundant) + } + + // Computed + d.Set("fqdn", props.FullyQualifiedDomainName) } - if !utils.ResponseWasNotFound(secResp.Response) { - block := flattenSecurityAlertPolicy(secResp.SecurityAlertPolicyProperties, d.Get("threat_detection_policy.0.storage_account_access_key").(string)) - if err := d.Set("threat_detection_policy", block); err != nil { - return fmt.Errorf("setting `threat_detection_policy`: %+v", err) + // the basic does not support threat detection policies + if tier == servers.SkuTierGeneralPurpose || tier == servers.SkuTierMemoryOptimized { + securityId := serversecurityalertpolicies.NewServerID(id.SubscriptionId, id.ResourceGroupName, id.ServerName) + secResp, err := securityClient.Get(ctx, securityId) + if err != nil && !response.WasNotFound(secResp.HttpResponse) { + return fmt.Errorf("making read request to postgres server security alert policy: %+v", err) + } + + if !response.WasNotFound(secResp.HttpResponse) { + if secResp.Model != nil { + block := flattenSecurityAlertPolicy(secResp.Model.Properties, d.Get("threat_detection_policy.0.storage_account_access_key").(string)) + if err := d.Set("threat_detection_policy", block); err != nil { + return fmt.Errorf("setting `threat_detection_policy`: %+v", err) + } + } } } + + return tags.FlattenAndSet(d, model.Tags) } - return tags.FlattenAndSet(d, resp.Tags) + return nil } func resourcePostgreSQLServerDelete(d *pluginsdk.ResourceData, meta interface{}) error { @@ -802,20 +805,15 @@ func resourcePostgreSQLServerDelete(d *pluginsdk.ResourceData, meta interface{}) ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.ServerID(d.Id()) + id, err := servers.ParseServerID(d.Id()) if err != nil { return err } - future, err := client.Delete(ctx, id.ResourceGroup, id.Name) - if err != nil { + if err = client.DeleteThenPoll(ctx, *id); err != nil { return fmt.Errorf("deleting %s: %+v", *id, err) } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for deletion of %s: %+v", *id, err) - } - return nil } @@ -828,20 +826,20 @@ func indexOfSku(skuName string) int { return -1 // not found. } -func expandServerSkuName(skuName string) (*postgresql.Sku, error) { +func expandServerSkuName(skuName string) (*servers.Sku, error) { parts := strings.Split(skuName, "_") if len(parts) != 3 { return nil, fmt.Errorf("sku_name (%s) has the wrong number of parts (%d) after splitting on _", skuName, len(parts)) } - var tier postgresql.SkuTier + var tier servers.SkuTier switch parts[0] { case "B": - tier = postgresql.Basic + tier = servers.SkuTierBasic case "GP": - tier = postgresql.GeneralPurpose + tier = servers.SkuTierGeneralPurpose case "MO": - tier = postgresql.MemoryOptimized + tier = servers.SkuTierMemoryOptimized default: return nil, fmt.Errorf("sku_name %s has unknown sku tier %s", skuName, parts[0]) } @@ -851,44 +849,47 @@ func expandServerSkuName(skuName string) (*postgresql.Sku, error) { return nil, fmt.Errorf("cannot convert skuname %s capcity %s to int", skuName, parts[2]) } - return &postgresql.Sku{ - Name: utils.String(skuName), - Tier: tier, - Capacity: utils.Int32(int32(capacity)), + return &servers.Sku{ + Name: skuName, + Tier: &tier, + Capacity: utils.Int64(int64(capacity)), Family: utils.String(parts[1]), }, nil } -func expandPostgreSQLStorageProfile(d *pluginsdk.ResourceData) *postgresql.StorageProfile { - storage := postgresql.StorageProfile{} +func expandPostgreSQLStorageProfile(d *pluginsdk.ResourceData) *servers.StorageProfile { + storage := servers.StorageProfile{} // now override whatever we may have from the block with the top level properties if v, ok := d.GetOk("auto_grow_enabled"); ok { - storage.StorageAutogrow = postgresql.StorageAutogrowDisabled + autogrowEnabled := servers.StorageAutogrowDisabled if v.(bool) { - storage.StorageAutogrow = postgresql.StorageAutogrowEnabled + autogrowEnabled = servers.StorageAutogrowEnabled } + storage.StorageAutogrow = &autogrowEnabled } if v, ok := d.GetOk("backup_retention_days"); ok { - storage.BackupRetentionDays = utils.Int32(int32(v.(int))) + storage.BackupRetentionDays = utils.Int64(int64(v.(int))) } if v, ok := d.GetOk("geo_redundant_backup_enabled"); ok { - storage.GeoRedundantBackup = postgresql.Disabled + geoRedundantBackup := servers.GeoRedundantBackupDisabled + if v.(bool) { - storage.GeoRedundantBackup = postgresql.Enabled + geoRedundantBackup = servers.GeoRedundantBackupEnabled } + storage.GeoRedundantBackup = &geoRedundantBackup } if v, ok := d.GetOk("storage_mb"); ok { - storage.StorageMB = utils.Int32(int32(v.(int))) + storage.StorageMB = utils.Int64(int64(v.(int))) } return &storage } -func expandSecurityAlertPolicy(i interface{}) *postgresql.ServerSecurityAlertPolicy { +func expandSecurityAlertPolicy(i interface{}) *serversecurityalertpolicies.ServerSecurityAlertPolicy { slice := i.([]interface{}) if len(slice) == 0 { return nil @@ -896,12 +897,12 @@ func expandSecurityAlertPolicy(i interface{}) *postgresql.ServerSecurityAlertPol block := slice[0].(map[string]interface{}) - state := postgresql.ServerSecurityAlertPolicyStateEnabled + state := serversecurityalertpolicies.ServerSecurityAlertPolicyStateEnabled if !block["enabled"].(bool) { - state = postgresql.ServerSecurityAlertPolicyStateDisabled + state = serversecurityalertpolicies.ServerSecurityAlertPolicyStateDisabled } - props := &postgresql.SecurityAlertPolicyProperties{ + props := &serversecurityalertpolicies.SecurityAlertPolicyProperties{ State: state, } @@ -918,7 +919,7 @@ func expandSecurityAlertPolicy(i interface{}) *postgresql.ServerSecurityAlertPol } if v, ok := block["retention_days"]; ok { - props.RetentionDays = utils.Int32(int32(v.(int))) + props.RetentionDays = utils.Int64(int64(v.(int))) } if v, ok := block["storage_account_access_key"]; ok && v.(string) != "" { @@ -929,12 +930,12 @@ func expandSecurityAlertPolicy(i interface{}) *postgresql.ServerSecurityAlertPol props.StorageEndpoint = utils.String(v.(string)) } - return &postgresql.ServerSecurityAlertPolicy{ - SecurityAlertPolicyProperties: props, + return &serversecurityalertpolicies.ServerSecurityAlertPolicy{ + Properties: props, } } -func flattenSecurityAlertPolicy(props *postgresql.SecurityAlertPolicyProperties, accessKey string) interface{} { +func flattenSecurityAlertPolicy(props *serversecurityalertpolicies.SecurityAlertPolicyProperties, accessKey string) interface{} { if props == nil { return nil } @@ -946,13 +947,13 @@ func flattenSecurityAlertPolicy(props *postgresql.SecurityAlertPolicyProperties, props.StorageEndpoint != nil && *props.StorageEndpoint == "" && props.RetentionDays != nil && *props.RetentionDays == 0 && props.EmailAccountAdmins != nil && !*props.EmailAccountAdmins && - props.State == postgresql.ServerSecurityAlertPolicyStateDisabled { + props.State == serversecurityalertpolicies.ServerSecurityAlertPolicyStateDisabled { return nil } block := map[string]interface{}{} - block["enabled"] = props.State == postgresql.ServerSecurityAlertPolicyStateEnabled + block["enabled"] = props.State == serversecurityalertpolicies.ServerSecurityAlertPolicyStateEnabled block["disabled_alerts"] = flattenSecurityAlertPolicySet(props.DisabledAlerts) block["email_addresses"] = flattenSecurityAlertPolicySet(props.EmailAddresses) @@ -972,39 +973,6 @@ func flattenSecurityAlertPolicy(props *postgresql.SecurityAlertPolicyProperties, return []interface{}{block} } -func expandServerIdentity(input []interface{}) (*postgresql.ResourceIdentity, error) { - expanded, err := identity.ExpandSystemAssigned(input) - if err != nil { - return nil, err - } - - if expanded.Type == identity.TypeNone { - return nil, nil - } - - return &postgresql.ResourceIdentity{ - Type: postgresql.IdentityType(string(expanded.Type)), - }, nil -} - -func flattenServerIdentity(input *postgresql.ResourceIdentity) []interface{} { - var transition *identity.SystemAssigned - - if input != nil { - transition = &identity.SystemAssigned{ - Type: identity.Type(string(input.Type)), - } - if input.PrincipalID != nil { - transition.PrincipalId = input.PrincipalID.String() - } - if input.TenantID != nil { - transition.TenantId = input.TenantID.String() - } - } - - return identity.FlattenSystemAssigned(transition) -} - func flattenSecurityAlertPolicySet(input *[]string) []interface{} { if input == nil { return make([]interface{}, 0) @@ -1020,23 +988,23 @@ func flattenSecurityAlertPolicySet(input *[]string) []interface{} { return utils.FlattenStringSlice(input) } -func postgreSqlStateRefreshFunc(ctx context.Context, client *postgresql.ServersClient, id parse.ServerId) pluginsdk.StateRefreshFunc { +func postgreSqlStateRefreshFunc(ctx context.Context, client *servers.ServersClient, id servers.ServerId) pluginsdk.StateRefreshFunc { return func() (interface{}, string, error) { - res, err := client.Get(ctx, id.ResourceGroup, id.Name) - if !utils.ResponseWasNotFound(res.Response) && err != nil { + res, err := client.Get(ctx, id) + if !response.WasNotFound(res.HttpResponse) && err != nil { return nil, "", fmt.Errorf("retrieving status of %s: %+v", id, err) } // This is an issue with the RP, there is a 10 to 15 second lag before the // service will actually return the server - if utils.ResponseWasNotFound(res.Response) { - return res, string(postgresql.ServerStateInaccessible), nil + if response.WasNotFound(res.HttpResponse) { + return res, string(servers.ServerStateInaccessible), nil } - if res.ServerProperties != nil && res.ServerProperties.UserVisibleState != "" { - return res, string(res.ServerProperties.UserVisibleState), nil + if res.Model != nil && res.Model.Properties != nil && res.Model.Properties.UserVisibleState != nil && *res.Model.Properties.UserVisibleState != "" { + return res, string(*res.Model.Properties.UserVisibleState), nil } - return res, string(postgresql.ServerStateInaccessible), nil + return res, string(servers.ServerStateInaccessible), nil } } diff --git a/internal/services/postgres/postgresql_server_resource_test.go b/internal/services/postgres/postgresql_server_resource_test.go index 5174e8fa6153..4bef238fd4f6 100644 --- a/internal/services/postgres/postgresql_server_resource_test.go +++ b/internal/services/postgres/postgresql_server_resource_test.go @@ -6,10 +6,10 @@ import ( "testing" "time" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -393,17 +393,17 @@ func TestMinTlsVersionOnServerUpdate(t *testing.T) { } func (t PostgreSQLServerResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.ServerID(state.ID) + id, err := servers.ParseServerID(state.ID) if err != nil { return nil, err } - resp, err := clients.Postgres.ServersClient.Get(ctx, id.ResourceGroup, id.Name) + resp, err := clients.Postgres.ServersClient.Get(ctx, *id) if err != nil { return nil, fmt.Errorf("reading Postgresql Server (%s): %+v", id.String(), err) } - return utils.Bool(resp.ID != nil), nil + return utils.Bool(resp.Model != nil), nil } func (PostgreSQLServerResource) template(data acceptance.TestData, sku, version string) string { diff --git a/internal/services/postgres/postgresql_virtual_network_rule_resource.go b/internal/services/postgres/postgresql_virtual_network_rule_resource.go index 56db2624ee7e..1e72e7443f6f 100644 --- a/internal/services/postgres/postgresql_virtual_network_rule_resource.go +++ b/internal/services/postgres/postgresql_virtual_network_rule_resource.go @@ -6,12 +6,12 @@ import ( "log" "time" - "github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2020-01-01/postgresql" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/virtualnetworkrules" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" networkValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/validate" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" @@ -25,7 +25,7 @@ func resourcePostgreSQLVirtualNetworkRule() *pluginsdk.Resource { Update: resourcePostgreSQLVirtualNetworkRuleCreateUpdate, Delete: resourcePostgreSQLVirtualNetworkRuleDelete, Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - _, err := parse.VirtualNetworkRuleID(id) + _, err := virtualnetworkrules.ParseVirtualNetworkRuleID(id) return err }), @@ -74,38 +74,33 @@ func resourcePostgreSQLVirtualNetworkRuleCreateUpdate(d *pluginsdk.ResourceData, ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - id := parse.NewVirtualNetworkRuleID(subscriptionId, d.Get("resource_group_name").(string), d.Get("server_name").(string), d.Get("name").(string)) + id := virtualnetworkrules.NewVirtualNetworkRuleID(subscriptionId, d.Get("resource_group_name").(string), d.Get("server_name").(string), d.Get("name").(string)) if d.IsNewResource() { - existing, err := client.Get(ctx, id.ResourceGroup, id.ServerName, id.Name) + existing, err := client.Get(ctx, id) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return fmt.Errorf("checking for presence of existing %s: %+v", id, err) } } - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return tf.ImportAsExistsError("azurerm_postgresql_virtual_network_rule", id.ID()) } } - parameters := postgresql.VirtualNetworkRule{ - VirtualNetworkRuleProperties: &postgresql.VirtualNetworkRuleProperties{ - VirtualNetworkSubnetID: utils.String(d.Get("subnet_id").(string)), + parameters := virtualnetworkrules.VirtualNetworkRule{ + Properties: &virtualnetworkrules.VirtualNetworkRuleProperties{ + VirtualNetworkSubnetId: d.Get("subnet_id").(string), IgnoreMissingVnetServiceEndpoint: utils.Bool(d.Get("ignore_missing_vnet_service_endpoint").(bool)), }, } - future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.ServerName, id.Name, parameters) - if err != nil { + if err := client.CreateOrUpdateThenPoll(ctx, id, parameters); err != nil { return fmt.Errorf("creating %s: %+v", id, err) } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for creation of %s: %+v", id, err) - } - // Wait for the provisioning state to become ready - log.Printf("[DEBUG] Waiting for %s to become ready: %+v", id, err) + log.Printf("[DEBUG] Waiting for %s to become ready", id) stateConf := &pluginsdk.StateChangeConf{ Pending: []string{"Initializing", "InProgress", "Unknown", "ResponseNotFound"}, Target: []string{"Ready"}, @@ -120,7 +115,7 @@ func resourcePostgreSQLVirtualNetworkRuleCreateUpdate(d *pluginsdk.ResourceData, stateConf.Timeout = d.Timeout(pluginsdk.TimeoutUpdate) } - if _, err = stateConf.WaitForStateContext(ctx); err != nil { + if _, err := stateConf.WaitForStateContext(ctx); err != nil { return fmt.Errorf("waiting for %s to be created or updated: %+v", id, err) } @@ -133,29 +128,31 @@ func resourcePostgreSQLVirtualNetworkRuleRead(d *pluginsdk.ResourceData, meta in ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.VirtualNetworkRuleID(d.Id()) + id, err := virtualnetworkrules.ParseVirtualNetworkRuleID(d.Id()) if err != nil { return err } - resp, err := client.Get(ctx, id.ResourceGroup, id.ServerName, id.Name) + resp, err := client.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { log.Printf("[INFO] Error reading PostgreSQL Virtual Network Rule %q - removing from state", d.Id()) d.SetId("") return nil } - return fmt.Errorf("retrieving Virtual Network Rule %q (PostgreSQL Server %q / Resource Group %q): %+v", id.Name, id.ServerName, id.ResourceGroup, err) + return fmt.Errorf("retrieving %s: %+v", id, err) } - d.Set("name", id.Name) - d.Set("resource_group_name", id.ResourceGroup) + d.Set("name", id.VirtualNetworkRuleName) + d.Set("resource_group_name", id.ResourceGroupName) d.Set("server_name", id.ServerName) - if props := resp.VirtualNetworkRuleProperties; props != nil { - d.Set("subnet_id", props.VirtualNetworkSubnetID) - d.Set("ignore_missing_vnet_service_endpoint", props.IgnoreMissingVnetServiceEndpoint) + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("subnet_id", props.VirtualNetworkSubnetId) + d.Set("ignore_missing_vnet_service_endpoint", props.IgnoreMissingVnetServiceEndpoint) + } } return nil @@ -166,28 +163,23 @@ func resourcePostgreSQLVirtualNetworkRuleDelete(d *pluginsdk.ResourceData, meta ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.VirtualNetworkRuleID(d.Id()) + id, err := virtualnetworkrules.ParseVirtualNetworkRuleID(d.Id()) if err != nil { return err } - future, err := client.Delete(ctx, id.ResourceGroup, id.ServerName, id.Name) - if err != nil { - return fmt.Errorf("deleting PostgreSQL Virtual Network Rule %q (PostgreSQL Server: %q, Resource Group: %q): %+v", id.Name, id.ServerName, id.ResourceGroup, err) - } - - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for deletion of Virtual Network Rule %q (PostgreSQL Server %q / Resource Group %q): %+v", id.Name, id.ServerName, id.ResourceGroup, err) + if err := client.DeleteThenPoll(ctx, *id); err != nil { + return fmt.Errorf("deleting %s: %+v", id, err) } return nil } -func postgreSQLVirtualNetworkStateStatusCodeRefreshFunc(ctx context.Context, client *postgresql.VirtualNetworkRulesClient, id parse.VirtualNetworkRuleId) pluginsdk.StateRefreshFunc { +func postgreSQLVirtualNetworkStateStatusCodeRefreshFunc(ctx context.Context, client *virtualnetworkrules.VirtualNetworkRulesClient, id virtualnetworkrules.VirtualNetworkRuleId) pluginsdk.StateRefreshFunc { return func() (interface{}, string, error) { - resp, err := client.Get(ctx, id.ResourceGroup, id.ServerName, id.Name) + resp, err := client.Get(ctx, id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { log.Printf("[DEBUG] Retrieving %s returned 404.", id) return nil, "ResponseNotFound", nil } @@ -195,9 +187,11 @@ func postgreSQLVirtualNetworkStateStatusCodeRefreshFunc(ctx context.Context, cli return nil, "", fmt.Errorf("polling for the state of the %s: %+v", id, err) } - if props := resp.VirtualNetworkRuleProperties; props != nil { - log.Printf("[DEBUG] Retrieving %s returned Status %s", id, props.State) - return resp, string(props.State), nil + if model := resp.Model; model != nil { + if props := model.Properties; props != nil && props.State != nil { + log.Printf("[DEBUG] Retrieving %s returned Status %s", id, string(*props.State)) + return resp, string(*props.State), nil + } } // Valid response was returned but VirtualNetworkRuleProperties was nil. Basically the rule exists, but with no properties for some reason. Assume Unknown instead of returning error. diff --git a/internal/services/postgres/postgresql_virtual_network_rule_resource_test.go b/internal/services/postgres/postgresql_virtual_network_rule_resource_test.go index 1c817c7e4816..064decb00b96 100644 --- a/internal/services/postgres/postgresql_virtual_network_rule_resource_test.go +++ b/internal/services/postgres/postgresql_virtual_network_rule_resource_test.go @@ -6,10 +6,10 @@ import ( "regexp" "testing" + "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/virtualnetworkrules" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -109,32 +109,27 @@ func TestAccPostgreSQLVirtualNetworkRule_IgnoreEndpointValid(t *testing.T) { } func (r PostgreSQLVirtualNetworkRuleResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.VirtualNetworkRuleID(state.ID) + id, err := virtualnetworkrules.ParseVirtualNetworkRuleID(state.ID) if err != nil { return nil, err } - resp, err := clients.Postgres.VirtualNetworkRulesClient.Get(ctx, id.ResourceGroup, id.ServerName, id.Name) + resp, err := clients.Postgres.VirtualNetworkRulesClient.Get(ctx, *id) if err != nil { - return nil, fmt.Errorf("reading Postgresql Virtual Network Rule (%s): %+v", id.String(), err) + return nil, fmt.Errorf("reading %s: %+v", id, err) } - return utils.Bool(resp.ID != nil), nil + return utils.Bool(resp.Model != nil), nil } func (r PostgreSQLVirtualNetworkRuleResource) Destroy(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.VirtualNetworkRuleID(state.ID) + id, err := virtualnetworkrules.ParseVirtualNetworkRuleID(state.ID) if err != nil { return nil, err } - future, err := client.Postgres.VirtualNetworkRulesClient.Delete(ctx, id.ResourceGroup, id.ServerName, id.Name) - if err != nil { - return nil, fmt.Errorf("deleting Postgresql Virtual Network Rule (%s): %+v", id.String(), err) - } - - if err := future.WaitForCompletionRef(ctx, client.Postgres.VirtualNetworkRulesClient.Client); err != nil { - return nil, fmt.Errorf("waiting for deletion of Postgresql Virtual Network Rule (%s): %+v", id.String(), err) + if err := client.Postgres.VirtualNetworkRulesClient.DeleteThenPoll(ctx, *id); err != nil { + return nil, fmt.Errorf("deleting %s: %+v", id, err) } return utils.Bool(true), nil diff --git a/internal/services/postgres/resourceids.go b/internal/services/postgres/resourceids.go index 09280329ad93..3a7c16023bbe 100644 --- a/internal/services/postgres/resourceids.go +++ b/internal/services/postgres/resourceids.go @@ -1,13 +1,3 @@ package postgres //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=AzureActiveDirectoryAdministrator -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/administrators/activeDirectory -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Configuration -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/configurations/configuration1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Database -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/databases/database1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=FirewallRule -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/firewallRules/firewallRule1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Server -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ServerKey -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/keys/key1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=VirtualNetworkRule -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/virtualNetworkRules/virtualNetworkRule1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=FlexibleServer -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/flexibleServer1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=FlexibleServerFirewallRule -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/flexibleServer1/firewallRules/firewallRule1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=FlexibleServerConfiguration -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/flexibleServer1/configurations/configuration1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=FlexibleServerDatabase -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/flexibleServer1/databases/database1 diff --git a/internal/services/postgres/validate/configuration_id.go b/internal/services/postgres/validate/configuration_id.go deleted file mode 100644 index 5fbc75f538b1..000000000000 --- a/internal/services/postgres/validate/configuration_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" -) - -func ConfigurationID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.ConfigurationID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/postgres/validate/configuration_id_test.go b/internal/services/postgres/validate/configuration_id_test.go deleted file mode 100644 index 098402a2fa38..000000000000 --- a/internal/services/postgres/validate/configuration_id_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestConfigurationID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - - { - // empty - Input: "", - Valid: false, - }, - - { - // missing SubscriptionId - Input: "/", - Valid: false, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Valid: false, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Valid: false, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Valid: false, - }, - - { - // missing ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/", - Valid: false, - }, - - { - // missing value for ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/", - Valid: false, - }, - - { - // missing Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/", - Valid: false, - }, - - { - // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/configurations/", - Valid: false, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/configurations/configuration1", - Valid: true, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.DBFORPOSTGRESQL/SERVERS/SERVER1/CONFIGURATIONS/CONFIGURATION1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := ConfigurationID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/postgres/validate/database_id.go b/internal/services/postgres/validate/database_id.go deleted file mode 100644 index 24a8ecbddcf3..000000000000 --- a/internal/services/postgres/validate/database_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" -) - -func DatabaseID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.DatabaseID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/postgres/validate/database_id_test.go b/internal/services/postgres/validate/database_id_test.go deleted file mode 100644 index 8744c371280c..000000000000 --- a/internal/services/postgres/validate/database_id_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestDatabaseID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - - { - // empty - Input: "", - Valid: false, - }, - - { - // missing SubscriptionId - Input: "/", - Valid: false, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Valid: false, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Valid: false, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Valid: false, - }, - - { - // missing ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/", - Valid: false, - }, - - { - // missing value for ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/", - Valid: false, - }, - - { - // missing Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/", - Valid: false, - }, - - { - // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/databases/", - Valid: false, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/databases/database1", - Valid: true, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.DBFORPOSTGRESQL/SERVERS/SERVER1/DATABASES/DATABASE1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := DatabaseID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/postgres/validate/firewall_rule_id.go b/internal/services/postgres/validate/firewall_rule_id.go deleted file mode 100644 index e0ded2db618a..000000000000 --- a/internal/services/postgres/validate/firewall_rule_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" -) - -func FirewallRuleID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.FirewallRuleID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/postgres/validate/firewall_rule_id_test.go b/internal/services/postgres/validate/firewall_rule_id_test.go deleted file mode 100644 index 77777ead15bc..000000000000 --- a/internal/services/postgres/validate/firewall_rule_id_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestFirewallRuleID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - - { - // empty - Input: "", - Valid: false, - }, - - { - // missing SubscriptionId - Input: "/", - Valid: false, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Valid: false, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Valid: false, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Valid: false, - }, - - { - // missing ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/", - Valid: false, - }, - - { - // missing value for ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/", - Valid: false, - }, - - { - // missing Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/", - Valid: false, - }, - - { - // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/firewallRules/", - Valid: false, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/firewallRules/firewallRule1", - Valid: true, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.DBFORPOSTGRESQL/SERVERS/SERVER1/FIREWALLRULES/FIREWALLRULE1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := FirewallRuleID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/postgres/validate/flexible_server_configuration_id.go b/internal/services/postgres/validate/flexible_server_configuration_id.go deleted file mode 100644 index fc654717d926..000000000000 --- a/internal/services/postgres/validate/flexible_server_configuration_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" -) - -func FlexibleServerConfigurationID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.FlexibleServerConfigurationID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/postgres/validate/flexible_server_configuration_id_test.go b/internal/services/postgres/validate/flexible_server_configuration_id_test.go deleted file mode 100644 index 682bd62c85c7..000000000000 --- a/internal/services/postgres/validate/flexible_server_configuration_id_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestFlexibleServerConfigurationID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - - { - // empty - Input: "", - Valid: false, - }, - - { - // missing SubscriptionId - Input: "/", - Valid: false, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Valid: false, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Valid: false, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Valid: false, - }, - - { - // missing FlexibleServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/", - Valid: false, - }, - - { - // missing value for FlexibleServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/", - Valid: false, - }, - - { - // missing ConfigurationName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/flexibleServer1/", - Valid: false, - }, - - { - // missing value for ConfigurationName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/flexibleServer1/configurations/", - Valid: false, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/flexibleServer1/configurations/configuration1", - Valid: true, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.DBFORPOSTGRESQL/FLEXIBLESERVERS/FLEXIBLESERVER1/CONFIGURATIONS/CONFIGURATION1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := FlexibleServerConfigurationID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/postgres/validate/flexible_server_database_id.go b/internal/services/postgres/validate/flexible_server_database_id.go deleted file mode 100644 index c899f3d7fc8f..000000000000 --- a/internal/services/postgres/validate/flexible_server_database_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" -) - -func FlexibleServerDatabaseID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.FlexibleServerDatabaseID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/postgres/validate/flexible_server_database_id_test.go b/internal/services/postgres/validate/flexible_server_database_id_test.go deleted file mode 100644 index 9ee1cd685943..000000000000 --- a/internal/services/postgres/validate/flexible_server_database_id_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestFlexibleServerDatabaseID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - - { - // empty - Input: "", - Valid: false, - }, - - { - // missing SubscriptionId - Input: "/", - Valid: false, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Valid: false, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Valid: false, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Valid: false, - }, - - { - // missing FlexibleServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/", - Valid: false, - }, - - { - // missing value for FlexibleServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/", - Valid: false, - }, - - { - // missing DatabaseName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/flexibleServer1/", - Valid: false, - }, - - { - // missing value for DatabaseName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/flexibleServer1/databases/", - Valid: false, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/flexibleServer1/databases/database1", - Valid: true, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.DBFORPOSTGRESQL/FLEXIBLESERVERS/FLEXIBLESERVER1/DATABASES/DATABASE1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := FlexibleServerDatabaseID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/postgres/validate/flexible_server_firewall_rule_id.go b/internal/services/postgres/validate/flexible_server_firewall_rule_id.go deleted file mode 100644 index 62063f69a97d..000000000000 --- a/internal/services/postgres/validate/flexible_server_firewall_rule_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" -) - -func FlexibleServerFirewallRuleID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.FlexibleServerFirewallRuleID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/postgres/validate/flexible_server_firewall_rule_id_test.go b/internal/services/postgres/validate/flexible_server_firewall_rule_id_test.go deleted file mode 100644 index 8eed3cdd11fe..000000000000 --- a/internal/services/postgres/validate/flexible_server_firewall_rule_id_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestFlexibleServerFirewallRuleID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - - { - // empty - Input: "", - Valid: false, - }, - - { - // missing SubscriptionId - Input: "/", - Valid: false, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Valid: false, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Valid: false, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Valid: false, - }, - - { - // missing FlexibleServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/", - Valid: false, - }, - - { - // missing value for FlexibleServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/", - Valid: false, - }, - - { - // missing FirewallRuleName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/flexibleServer1/", - Valid: false, - }, - - { - // missing value for FirewallRuleName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/flexibleServer1/firewallRules/", - Valid: false, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/flexibleServer1/firewallRules/firewallRule1", - Valid: true, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.DBFORPOSTGRESQL/FLEXIBLESERVERS/FLEXIBLESERVER1/FIREWALLRULES/FIREWALLRULE1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := FlexibleServerFirewallRuleID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/postgres/validate/flexible_server_id.go b/internal/services/postgres/validate/flexible_server_id.go deleted file mode 100644 index 1b998295da2f..000000000000 --- a/internal/services/postgres/validate/flexible_server_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" -) - -func FlexibleServerID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.FlexibleServerID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/postgres/validate/flexible_server_id_test.go b/internal/services/postgres/validate/flexible_server_id_test.go deleted file mode 100644 index b0f0eae7d837..000000000000 --- a/internal/services/postgres/validate/flexible_server_id_test.go +++ /dev/null @@ -1,76 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestFlexibleServerID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - - { - // empty - Input: "", - Valid: false, - }, - - { - // missing SubscriptionId - Input: "/", - Valid: false, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Valid: false, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Valid: false, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Valid: false, - }, - - { - // missing Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/", - Valid: false, - }, - - { - // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/", - Valid: false, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/flexibleServers/flexibleServer1", - Valid: true, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.DBFORPOSTGRESQL/FLEXIBLESERVERS/FLEXIBLESERVER1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := FlexibleServerID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/postgres/validate/server_id.go b/internal/services/postgres/validate/server_id.go deleted file mode 100644 index a7864ea1966c..000000000000 --- a/internal/services/postgres/validate/server_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" -) - -func ServerID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.ServerID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/postgres/validate/server_id_test.go b/internal/services/postgres/validate/server_id_test.go deleted file mode 100644 index 1fcf76082f48..000000000000 --- a/internal/services/postgres/validate/server_id_test.go +++ /dev/null @@ -1,76 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestServerID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - - { - // empty - Input: "", - Valid: false, - }, - - { - // missing SubscriptionId - Input: "/", - Valid: false, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Valid: false, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Valid: false, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Valid: false, - }, - - { - // missing Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/", - Valid: false, - }, - - { - // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/", - Valid: false, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1", - Valid: true, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.DBFORPOSTGRESQL/SERVERS/SERVER1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := ServerID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/postgres/validate/server_key_id.go b/internal/services/postgres/validate/server_key_id.go deleted file mode 100644 index fda821517df8..000000000000 --- a/internal/services/postgres/validate/server_key_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" -) - -func ServerKeyID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.ServerKeyID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/postgres/validate/server_key_id_test.go b/internal/services/postgres/validate/server_key_id_test.go deleted file mode 100644 index c63b0d673ad5..000000000000 --- a/internal/services/postgres/validate/server_key_id_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestServerKeyID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - - { - // empty - Input: "", - Valid: false, - }, - - { - // missing SubscriptionId - Input: "/", - Valid: false, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Valid: false, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Valid: false, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Valid: false, - }, - - { - // missing ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/", - Valid: false, - }, - - { - // missing value for ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/", - Valid: false, - }, - - { - // missing KeyName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/", - Valid: false, - }, - - { - // missing value for KeyName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/keys/", - Valid: false, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/keys/key1", - Valid: true, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.DBFORPOSTGRESQL/SERVERS/SERVER1/KEYS/KEY1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := ServerKeyID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/postgres/validate/virtual_network_rule_id.go b/internal/services/postgres/validate/virtual_network_rule_id.go deleted file mode 100644 index 550db479d5e1..000000000000 --- a/internal/services/postgres/validate/virtual_network_rule_id.go +++ /dev/null @@ -1,23 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - - "github.com/hashicorp/terraform-provider-azurerm/internal/services/postgres/parse" -) - -func VirtualNetworkRuleID(input interface{}, key string) (warnings []string, errors []error) { - v, ok := input.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected %q to be a string", key)) - return - } - - if _, err := parse.VirtualNetworkRuleID(v); err != nil { - errors = append(errors, err) - } - - return -} diff --git a/internal/services/postgres/validate/virtual_network_rule_id_test.go b/internal/services/postgres/validate/virtual_network_rule_id_test.go deleted file mode 100644 index bb3af88774cd..000000000000 --- a/internal/services/postgres/validate/virtual_network_rule_id_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package validate - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import "testing" - -func TestVirtualNetworkRuleID(t *testing.T) { - cases := []struct { - Input string - Valid bool - }{ - - { - // empty - Input: "", - Valid: false, - }, - - { - // missing SubscriptionId - Input: "/", - Valid: false, - }, - - { - // missing value for SubscriptionId - Input: "/subscriptions/", - Valid: false, - }, - - { - // missing ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Valid: false, - }, - - { - // missing value for ResourceGroup - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Valid: false, - }, - - { - // missing ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/", - Valid: false, - }, - - { - // missing value for ServerName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/", - Valid: false, - }, - - { - // missing Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/", - Valid: false, - }, - - { - // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/virtualNetworkRules/", - Valid: false, - }, - - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforPostgreSQL/servers/server1/virtualNetworkRules/virtualNetworkRule1", - Valid: true, - }, - - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.DBFORPOSTGRESQL/SERVERS/SERVER1/VIRTUALNETWORKRULES/VIRTUALNETWORKRULE1", - Valid: false, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.Input) - _, errors := VirtualNetworkRuleID(tc.Input, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/internal/services/privatedns/private_dns_a_record_data_source.go b/internal/services/privatedns/private_dns_a_record_data_source.go new file mode 100644 index 000000000000..10a00a32012f --- /dev/null +++ b/internal/services/privatedns/private_dns_a_record_data_source.go @@ -0,0 +1,95 @@ +package privatedns + +import ( + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/privatedns/2018-09-01/recordsets" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" +) + +func dataSourcePrivateDnsARecord() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Read: dataSourcePrivateDnsARecordRead, + + Timeouts: &pluginsdk.ResourceTimeout{ + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "resource_group_name": commonschema.ResourceGroupNameForDataSource(), + + "zone_name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "records": { + Type: pluginsdk.TypeSet, + Computed: true, + Elem: &pluginsdk.Schema{Type: pluginsdk.TypeString}, + Set: pluginsdk.HashString, + }, + + "ttl": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "fqdn": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "tags": commonschema.TagsDataSource(), + }, + } +} + +func dataSourcePrivateDnsARecordRead(d *pluginsdk.ResourceData, meta interface{}) error { + recordSetsClient := meta.(*clients.Client).PrivateDns.RecordSetsClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + + id := recordsets.NewRecordTypeID(subscriptionId, d.Get("resource_group_name").(string), d.Get("zone_name").(string), recordsets.RecordTypeA, d.Get("name").(string)) + + resp, err := recordSetsClient.Get(ctx, id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return fmt.Errorf("%s was not found", id) + } + return fmt.Errorf("reading %s: %+v", id, err) + } + + d.SetId(id.ID()) + + d.Set("name", id.RelativeRecordSetName) + d.Set("resource_group_name", id.ResourceGroupName) + d.Set("zone_name", id.PrivateZoneName) + + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("ttl", props.Ttl) + d.Set("fqdn", props.Fqdn) + + if err := d.Set("records", flattenAzureRmPrivateDnsARecords(props.ARecords)); err != nil { + return fmt.Errorf("setting `records`: %+v", err) + } + + return tags.FlattenAndSet(d, props.Metadata) + } + } + + return nil +} diff --git a/internal/services/privatedns/private_dns_a_record_data_source_test.go b/internal/services/privatedns/private_dns_a_record_data_source_test.go new file mode 100644 index 000000000000..e4d82a1de91c --- /dev/null +++ b/internal/services/privatedns/private_dns_a_record_data_source_test.go @@ -0,0 +1,43 @@ +package privatedns_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" +) + +type PrivateDnsARecordDataSource struct{} + +func TestAccDataSourcePrivateDnsARecord_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_private_dns_a_record", "test") + r := PrivateDnsARecordDataSource{} + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("name").Exists(), + check.That(data.ResourceName).Key("resource_group_name").Exists(), + check.That(data.ResourceName).Key("zone_name").Exists(), + check.That(data.ResourceName).Key("records.#").HasValue("2"), + check.That(data.ResourceName).Key("ttl").Exists(), + check.That(data.ResourceName).Key("fqdn").Exists(), + check.That(data.ResourceName).Key("tags.%").HasValue("0"), + ), + }, + }) +} + +func (PrivateDnsARecordDataSource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +data "azurerm_private_dns_a_record" "test" { + name = azurerm_private_dns_a_record.test.name + resource_group_name = azurerm_resource_group.test.name + zone_name = azurerm_private_dns_zone.test.name +} +`, PrivateDnsARecordResource{}.basic(data)) +} diff --git a/internal/services/privatedns/private_dns_a_record_resource.go b/internal/services/privatedns/private_dns_a_record_resource.go index 0b07277f51c4..6945e4e0c7b8 100644 --- a/internal/services/privatedns/private_dns_a_record_resource.go +++ b/internal/services/privatedns/private_dns_a_record_resource.go @@ -192,11 +192,11 @@ func flattenAzureRmPrivateDnsARecords(records *[]recordsets.ARecord) []string { } for _, record := range *records { - if record.Ipv4Address == nil { + if record.IPv4Address == nil { continue } - results = append(results, *record.Ipv4Address) + results = append(results, *record.IPv4Address) } return results @@ -209,7 +209,7 @@ func expandAzureRmPrivateDnsARecords(d *pluginsdk.ResourceData) *[]recordsets.AR for i, v := range recordStrings { ipv4 := v.(string) records[i] = recordsets.ARecord{ - Ipv4Address: &ipv4, + IPv4Address: &ipv4, } } diff --git a/internal/services/privatedns/private_dns_aaaa_record_data_source.go b/internal/services/privatedns/private_dns_aaaa_record_data_source.go new file mode 100644 index 000000000000..832b1a4bcca1 --- /dev/null +++ b/internal/services/privatedns/private_dns_aaaa_record_data_source.go @@ -0,0 +1,96 @@ +package privatedns + +import ( + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/privatedns/2018-09-01/recordsets" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/set" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" +) + +func dataSourcePrivateDnsAaaaRecord() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Read: dataSourcePrivateDnsAAAARecordRead, + + Timeouts: &pluginsdk.ResourceTimeout{ + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "resource_group_name": commonschema.ResourceGroupNameForDataSource(), + + "zone_name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "records": { + Type: pluginsdk.TypeSet, + Computed: true, + Elem: &pluginsdk.Schema{Type: pluginsdk.TypeString}, + Set: set.HashIPv6Address, + }, + + "ttl": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "fqdn": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "tags": commonschema.TagsDataSource(), + }, + } +} + +func dataSourcePrivateDnsAAAARecordRead(d *pluginsdk.ResourceData, meta interface{}) error { + recordSetsClient := meta.(*clients.Client).PrivateDns.RecordSetsClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + + id := recordsets.NewRecordTypeID(subscriptionId, d.Get("resource_group_name").(string), d.Get("zone_name").(string), recordsets.RecordTypeAAAA, d.Get("name").(string)) + + resp, err := recordSetsClient.Get(ctx, id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return fmt.Errorf("%s was not found", id) + } + return fmt.Errorf("reading %s: %+v", id, err) + } + + d.SetId(id.ID()) + + d.Set("name", id.RelativeRecordSetName) + d.Set("resource_group_name", id.ResourceGroupName) + d.Set("zone_name", id.PrivateZoneName) + + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("ttl", props.Ttl) + d.Set("fqdn", props.Fqdn) + + if err := d.Set("records", flattenAzureRmPrivateDnsAaaaRecords(props.AaaaRecords)); err != nil { + return fmt.Errorf("setting `records`: %+v", err) + } + + return tags.FlattenAndSet(d, props.Metadata) + } + } + + return nil +} diff --git a/internal/services/privatedns/private_dns_aaaa_record_data_source_test.go b/internal/services/privatedns/private_dns_aaaa_record_data_source_test.go new file mode 100644 index 000000000000..db9486d0dcd2 --- /dev/null +++ b/internal/services/privatedns/private_dns_aaaa_record_data_source_test.go @@ -0,0 +1,43 @@ +package privatedns_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" +) + +type PrivateDnsAAAARecordDataSource struct{} + +func TestAccDataSourcePrivateDnsAAAARecord_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_private_dns_aaaa_record", "test") + r := PrivateDnsAAAARecordDataSource{} + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("name").Exists(), + check.That(data.ResourceName).Key("resource_group_name").Exists(), + check.That(data.ResourceName).Key("zone_name").Exists(), + check.That(data.ResourceName).Key("records.#").HasValue("2"), + check.That(data.ResourceName).Key("ttl").Exists(), + check.That(data.ResourceName).Key("fqdn").Exists(), + check.That(data.ResourceName).Key("tags.%").HasValue("0"), + ), + }, + }) +} + +func (PrivateDnsAAAARecordDataSource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +data "azurerm_private_dns_aaaa_record" "test" { + name = azurerm_private_dns_aaaa_record.test.name + resource_group_name = azurerm_resource_group.test.name + zone_name = azurerm_private_dns_zone.test.name +} +`, PrivateDnsAAAARecordResource{}.basic(data)) +} diff --git a/internal/services/privatedns/private_dns_aaaa_record_resource.go b/internal/services/privatedns/private_dns_aaaa_record_resource.go index 45d6ebac54fe..c58eaed50d18 100644 --- a/internal/services/privatedns/private_dns_aaaa_record_resource.go +++ b/internal/services/privatedns/private_dns_aaaa_record_resource.go @@ -188,11 +188,11 @@ func flattenAzureRmPrivateDnsAaaaRecords(records *[]recordsets.AaaaRecord) []str } for _, record := range *records { - if record.Ipv6Address == nil { + if record.IPv6Address == nil { continue } - results = append(results, *record.Ipv6Address) + results = append(results, *record.IPv6Address) } return results @@ -205,7 +205,7 @@ func expandAzureRmPrivateDnsAaaaRecords(d *pluginsdk.ResourceData) *[]recordsets for i, v := range recordStrings { ipv6 := v.(string) records[i] = recordsets.AaaaRecord{ - Ipv6Address: &ipv6, + IPv6Address: &ipv6, } } diff --git a/internal/services/privatedns/private_dns_cname_record_data_source.go b/internal/services/privatedns/private_dns_cname_record_data_source.go new file mode 100644 index 000000000000..18f1b5a21fb6 --- /dev/null +++ b/internal/services/privatedns/private_dns_cname_record_data_source.go @@ -0,0 +1,101 @@ +package privatedns + +import ( + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/response" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/privatedns/2018-09-01/recordsets" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" +) + +func dataSourcePrivateDnsCNameRecord() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Read: dataSourcePrivateDnsCNameRecordRead, + + Timeouts: &pluginsdk.ResourceTimeout{ + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "resource_group_name": commonschema.ResourceGroupNameForDataSource(), + + "zone_name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "record": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "ttl": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "fqdn": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "target_resource_id": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "tags": commonschema.TagsDataSource(), + }, + } +} + +func dataSourcePrivateDnsCNameRecordRead(d *pluginsdk.ResourceData, meta interface{}) error { + recordSetsClient := meta.(*clients.Client).PrivateDns.RecordSetsClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + + id := recordsets.NewRecordTypeID(subscriptionId, d.Get("resource_group_name").(string), d.Get("zone_name").(string), recordsets.RecordTypeCNAME, d.Get("name").(string)) + + resp, err := recordSetsClient.Get(ctx, id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return fmt.Errorf("%s was not found", id) + } + return fmt.Errorf("reading %s: %+v", id, err) + } + + d.SetId(id.ID()) + + d.Set("name", id.RelativeRecordSetName) + d.Set("resource_group_name", id.ResourceGroupName) + d.Set("zone_name", id.PrivateZoneName) + + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("ttl", props.Ttl) + d.Set("fqdn", props.Fqdn) + + cname := "" + if props.CnameRecord != nil && props.CnameRecord.Cname != nil { + cname = *props.CnameRecord.Cname + } + d.Set("record", cname) + + return tags.FlattenAndSet(d, props.Metadata) + } + } + + return nil +} diff --git a/internal/services/privatedns/private_dns_cname_record_data_source_test.go b/internal/services/privatedns/private_dns_cname_record_data_source_test.go new file mode 100644 index 000000000000..e258e35c377c --- /dev/null +++ b/internal/services/privatedns/private_dns_cname_record_data_source_test.go @@ -0,0 +1,43 @@ +package privatedns_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" +) + +type PrivateDnsCNameRecordDataSource struct{} + +func TestAccDataSourcePrivateDnsCNameRecord_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_private_dns_cname_record", "test") + r := PrivateDnsCNameRecordDataSource{} + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("name").Exists(), + check.That(data.ResourceName).Key("resource_group_name").Exists(), + check.That(data.ResourceName).Key("zone_name").Exists(), + check.That(data.ResourceName).Key("record").HasValue("contoso.com"), + check.That(data.ResourceName).Key("ttl").Exists(), + check.That(data.ResourceName).Key("fqdn").Exists(), + check.That(data.ResourceName).Key("tags.%").HasValue("0"), + ), + }, + }) +} + +func (PrivateDnsCNameRecordDataSource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +data "azurerm_private_dns_cname_record" "test" { + name = azurerm_private_dns_cname_record.test.name + resource_group_name = azurerm_resource_group.test.name + zone_name = azurerm_private_dns_zone.test.name +} +`, PrivateDnsCNameRecordResource{}.basic(data)) +} diff --git a/internal/services/privatedns/private_dns_mx_record_data_source.go b/internal/services/privatedns/private_dns_mx_record_data_source.go new file mode 100644 index 000000000000..74114ebd393f --- /dev/null +++ b/internal/services/privatedns/private_dns_mx_record_data_source.go @@ -0,0 +1,106 @@ +package privatedns + +import ( + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/privatedns/2018-09-01/recordsets" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" +) + +func dataSourcePrivateDnsMxRecord() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Read: dataSourcePrivateDnsMxRecordRead, + + Timeouts: &pluginsdk.ResourceTimeout{ + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Optional: true, + }, + + "resource_group_name": commonschema.ResourceGroupNameForDataSource(), + + "zone_name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "record": { + Type: pluginsdk.TypeSet, + Computed: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "preference": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + "exchange": { + Type: pluginsdk.TypeString, + Computed: true, + }, + }, + }, + Set: resourcePrivateDnsMxRecordHash, + }, + + "ttl": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "fqdn": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "tags": commonschema.TagsDataSource(), + }, + } +} + +func dataSourcePrivateDnsMxRecordRead(d *pluginsdk.ResourceData, meta interface{}) error { + recordSetsClient := meta.(*clients.Client).PrivateDns.RecordSetsClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + + id := recordsets.NewRecordTypeID(subscriptionId, d.Get("resource_group_name").(string), d.Get("zone_name").(string), recordsets.RecordTypeMX, d.Get("name").(string)) + + resp, err := recordSetsClient.Get(ctx, id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return fmt.Errorf("%s was not found", id) + } + return fmt.Errorf("reading %s: %+v", id, err) + } + + d.SetId(id.ID()) + + d.Set("name", id.RelativeRecordSetName) + d.Set("resource_group_name", id.ResourceGroupName) + d.Set("zone_name", id.PrivateZoneName) + + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("ttl", props.Ttl) + d.Set("fqdn", props.Fqdn) + + if err := d.Set("record", flattenAzureRmPrivateDnsMxRecords(props.MxRecords)); err != nil { + return err + } + + return tags.FlattenAndSet(d, props.Metadata) + } + } + + return nil +} diff --git a/internal/services/privatedns/private_dns_mx_record_data_source_test.go b/internal/services/privatedns/private_dns_mx_record_data_source_test.go new file mode 100644 index 000000000000..5ffba71ecdff --- /dev/null +++ b/internal/services/privatedns/private_dns_mx_record_data_source_test.go @@ -0,0 +1,43 @@ +package privatedns_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" +) + +type PrivateDnsMxRecordDataSource struct{} + +func TestAccDataSourcePrivateDnsMxRecord_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_private_dns_mx_record", "test") + r := PrivateDnsMxRecordDataSource{} + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("name").Exists(), + check.That(data.ResourceName).Key("resource_group_name").Exists(), + check.That(data.ResourceName).Key("zone_name").Exists(), + check.That(data.ResourceName).Key("record.#").HasValue("2"), + check.That(data.ResourceName).Key("ttl").Exists(), + check.That(data.ResourceName).Key("fqdn").Exists(), + check.That(data.ResourceName).Key("tags.%").HasValue("0"), + ), + }, + }) +} + +func (PrivateDnsMxRecordDataSource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +data "azurerm_private_dns_mx_record" "test" { + name = azurerm_private_dns_mx_record.test.name + resource_group_name = azurerm_resource_group.test.name + zone_name = azurerm_private_dns_zone.test.name +} +`, PrivateDnsMxRecordResource{}.basic(data)) +} diff --git a/internal/services/privatedns/private_dns_mx_record_resource.go b/internal/services/privatedns/private_dns_mx_record_resource.go index 85b4c9116d91..baacaf37710f 100644 --- a/internal/services/privatedns/private_dns_mx_record_resource.go +++ b/internal/services/privatedns/private_dns_mx_record_resource.go @@ -1,6 +1,7 @@ package privatedns import ( + "bytes" "fmt" "time" @@ -240,3 +241,14 @@ func expandAzureRmPrivateDnsMxRecords(d *pluginsdk.ResourceData) *[]recordsets.M return &records } + +func resourcePrivateDnsMxRecordHash(v interface{}) int { + var buf bytes.Buffer + + if m, ok := v.(map[string]interface{}); ok { + buf.WriteString(fmt.Sprintf("%d-", m["preference"].(int))) + buf.WriteString(fmt.Sprintf("%s-", m["exchange"].(string))) + } + + return pluginsdk.HashString(buf.String()) +} diff --git a/internal/services/privatedns/private_dns_ptr_record_data_source.go b/internal/services/privatedns/private_dns_ptr_record_data_source.go new file mode 100644 index 000000000000..810d513a56d8 --- /dev/null +++ b/internal/services/privatedns/private_dns_ptr_record_data_source.go @@ -0,0 +1,95 @@ +package privatedns + +import ( + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/privatedns/2018-09-01/recordsets" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" +) + +func dataSourcePrivateDnsPtrRecord() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Read: dataSourcePrivateDnsPtrRecordRead, + + Timeouts: &pluginsdk.ResourceTimeout{ + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "resource_group_name": commonschema.ResourceGroupNameForDataSource(), + + "zone_name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "records": { + Type: pluginsdk.TypeSet, + Computed: true, + Elem: &pluginsdk.Schema{Type: pluginsdk.TypeString}, + Set: pluginsdk.HashString, + }, + + "ttl": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "fqdn": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "tags": commonschema.TagsDataSource(), + }, + } +} + +func dataSourcePrivateDnsPtrRecordRead(d *pluginsdk.ResourceData, meta interface{}) error { + recordSetsClient := meta.(*clients.Client).PrivateDns.RecordSetsClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + + id := recordsets.NewRecordTypeID(subscriptionId, d.Get("resource_group_name").(string), d.Get("zone_name").(string), recordsets.RecordTypePTR, d.Get("name").(string)) + + resp, err := recordSetsClient.Get(ctx, id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return fmt.Errorf("%s was not found", id) + } + return fmt.Errorf("reading %s: %+v", id, err) + } + + d.SetId(id.ID()) + + d.Set("name", id.RelativeRecordSetName) + d.Set("resource_group_name", id.ResourceGroupName) + d.Set("zone_name", id.PrivateZoneName) + + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("ttl", props.Ttl) + d.Set("fqdn", props.Fqdn) + + if err := d.Set("records", flattenAzureRmPrivateDnsPtrRecords(props.PtrRecords)); err != nil { + return err + } + + return tags.FlattenAndSet(d, props.Metadata) + } + } + + return nil +} diff --git a/internal/services/privatedns/private_dns_ptr_record_data_source_test.go b/internal/services/privatedns/private_dns_ptr_record_data_source_test.go new file mode 100644 index 000000000000..9f256843578a --- /dev/null +++ b/internal/services/privatedns/private_dns_ptr_record_data_source_test.go @@ -0,0 +1,43 @@ +package privatedns_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" +) + +type PrivateDnsPtrRecordDataSource struct{} + +func TestAccDataSourcePrivateDnsPtrRecord_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_private_dns_ptr_record", "test") + r := PrivateDnsPtrRecordDataSource{} + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("name").Exists(), + check.That(data.ResourceName).Key("resource_group_name").Exists(), + check.That(data.ResourceName).Key("zone_name").Exists(), + check.That(data.ResourceName).Key("records.#").HasValue("2"), + check.That(data.ResourceName).Key("ttl").Exists(), + check.That(data.ResourceName).Key("fqdn").Exists(), + check.That(data.ResourceName).Key("tags.%").HasValue("0"), + ), + }, + }) +} + +func (PrivateDnsPtrRecordDataSource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +data "azurerm_private_dns_ptr_record" "test" { + name = azurerm_private_dns_ptr_record.test.name + resource_group_name = azurerm_resource_group.test.name + zone_name = azurerm_private_dns_zone.test.name +} +`, PrivateDnsPtrRecordResource{}.basic(data)) +} diff --git a/internal/services/privatedns/private_dns_soa_record_data_source.go b/internal/services/privatedns/private_dns_soa_record_data_source.go new file mode 100644 index 000000000000..614ae5258efa --- /dev/null +++ b/internal/services/privatedns/private_dns_soa_record_data_source.go @@ -0,0 +1,129 @@ +package privatedns + +import ( + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/privatedns/2018-09-01/recordsets" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" +) + +func dataSourcePrivateDnsSoaRecord() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Read: dataSourcePrivateDnsSoaRecordRead, + + Timeouts: &pluginsdk.ResourceTimeout{ + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Optional: true, + Default: "@", + }, + + "resource_group_name": commonschema.ResourceGroupNameForDataSource(), + + "zone_name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "email": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "host_name": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "expire_time": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "minimum_ttl": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "refresh_time": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "retry_time": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "serial_number": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "ttl": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "fqdn": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "tags": commonschema.TagsDataSource(), + }, + } +} + +func dataSourcePrivateDnsSoaRecordRead(d *pluginsdk.ResourceData, meta interface{}) error { + recordSetsClient := meta.(*clients.Client).PrivateDns.RecordSetsClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + + id := recordsets.NewRecordTypeID(subscriptionId, d.Get("resource_group_name").(string), d.Get("zone_name").(string), recordsets.RecordTypeSOA, "@") + resp, err := recordSetsClient.Get(ctx, id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return fmt.Errorf("%s was not found", id) + } + return fmt.Errorf("reading %s: %+v", id, err) + } + + d.SetId(id.ID()) + + d.Set("resource_group_name", id.ResourceGroupName) + d.Set("zone_name", id.PrivateZoneName) + + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("ttl", props.Ttl) + d.Set("fqdn", props.Fqdn) + + if soaRecord := props.SoaRecord; soaRecord != nil { + d.Set("email", soaRecord.Email) + d.Set("host_name", soaRecord.Host) + d.Set("expire_time", soaRecord.ExpireTime) + d.Set("minimum_ttl", soaRecord.MinimumTtl) + d.Set("refresh_time", soaRecord.RefreshTime) + d.Set("retry_time", soaRecord.RetryTime) + d.Set("serial_number", soaRecord.SerialNumber) + } + + return tags.FlattenAndSet(d, props.Metadata) + } + + } + + return nil +} diff --git a/internal/services/privatedns/private_dns_soa_record_data_source_test.go b/internal/services/privatedns/private_dns_soa_record_data_source_test.go new file mode 100644 index 000000000000..7fa2bad1994e --- /dev/null +++ b/internal/services/privatedns/private_dns_soa_record_data_source_test.go @@ -0,0 +1,71 @@ +package privatedns_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" +) + +type PrivateDnsSoaRecordDataSource struct{} + +func TestAccDataSourcePrivateDnsSoaRecord_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_private_dns_soa_record", "test") + r := PrivateDnsSoaRecordDataSource{} + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: r.basicWithDataSource(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("resource_group_name").Exists(), + check.That(data.ResourceName).Key("zone_name").Exists(), + check.That(data.ResourceName).Key("fqdn").Exists(), + check.That(data.ResourceName).Key("name").HasValue("@"), + check.That(data.ResourceName).Key("email").HasValue("testemail.com"), + check.That(data.ResourceName).Key("host_name").HasValue("azureprivatedns.net"), + check.That(data.ResourceName).Key("expire_time").HasValue("2419200"), + check.That(data.ResourceName).Key("minimum_ttl").HasValue("10"), + check.That(data.ResourceName).Key("refresh_time").HasValue("3600"), + check.That(data.ResourceName).Key("retry_time").HasValue("300"), + check.That(data.ResourceName).Key("serial_number").HasValue("1"), + check.That(data.ResourceName).Key("ttl").HasValue("3600"), + check.That(data.ResourceName).Key("tags.%").HasValue("0"), + ), + }, + }) +} + +func (PrivateDnsSoaRecordDataSource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_private_dns_zone" "test" { + name = "acctestzone%d.com" + resource_group_name = azurerm_resource_group.test.name + + soa_record { + email = "testemail.com" + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger) +} + +func (d PrivateDnsSoaRecordDataSource) basicWithDataSource(data acceptance.TestData) string { + config := d.basic(data) + return fmt.Sprintf(` +%s + +data "azurerm_private_dns_soa_record" "test" { + resource_group_name = azurerm_resource_group.test.name + zone_name = azurerm_private_dns_zone.test.name +} +`, config) +} diff --git a/internal/services/privatedns/private_dns_srv_record_data_source.go b/internal/services/privatedns/private_dns_srv_record_data_source.go new file mode 100644 index 000000000000..db4e79146ba1 --- /dev/null +++ b/internal/services/privatedns/private_dns_srv_record_data_source.go @@ -0,0 +1,116 @@ +package privatedns + +import ( + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/privatedns/2018-09-01/recordsets" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" +) + +func dataSourcePrivateDnsSrvRecord() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Read: dataSourcePrivateDnsSrvRecordRead, + + Timeouts: &pluginsdk.ResourceTimeout{ + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "resource_group_name": commonschema.ResourceGroupNameForDataSource(), + + "zone_name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "record": { + Type: pluginsdk.TypeSet, + Computed: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "priority": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "weight": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "port": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "target": { + Type: pluginsdk.TypeString, + Computed: true, + }, + }, + }, + Set: resourcePrivateDnsSrvRecordHash, + }, + + "ttl": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "fqdn": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "tags": commonschema.TagsDataSource(), + }, + } +} + +func dataSourcePrivateDnsSrvRecordRead(d *pluginsdk.ResourceData, meta interface{}) error { + recordSetsClient := meta.(*clients.Client).PrivateDns.RecordSetsClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + + id := recordsets.NewRecordTypeID(subscriptionId, d.Get("resource_group_name").(string), d.Get("zone_name").(string), recordsets.RecordTypeSRV, d.Get("name").(string)) + resp, err := recordSetsClient.Get(ctx, id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return fmt.Errorf("%s was not found", id) + } + return fmt.Errorf("reading %s: %+v", id, err) + } + + d.SetId(id.ID()) + + d.Set("name", id.RelativeRecordSetName) + d.Set("resource_group_name", id.ResourceGroupName) + d.Set("zone_name", id.PrivateZoneName) + + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("ttl", props.Ttl) + d.Set("fqdn", props.Fqdn) + + if err := d.Set("record", flattenAzureRmPrivateDnsSrvRecords(props.SrvRecords)); err != nil { + return err + } + + return tags.FlattenAndSet(d, props.Metadata) + } + } + + return nil +} diff --git a/internal/services/privatedns/private_dns_srv_record_data_source_test.go b/internal/services/privatedns/private_dns_srv_record_data_source_test.go new file mode 100644 index 000000000000..1fe5592d7cf9 --- /dev/null +++ b/internal/services/privatedns/private_dns_srv_record_data_source_test.go @@ -0,0 +1,43 @@ +package privatedns_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" +) + +type PrivateDnsSrvRecordDataSource struct{} + +func TestAccDataSourcePrivateDnsSrvRecord_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_private_dns_srv_record", "test") + r := PrivateDnsSrvRecordDataSource{} + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("name").Exists(), + check.That(data.ResourceName).Key("resource_group_name").Exists(), + check.That(data.ResourceName).Key("zone_name").Exists(), + check.That(data.ResourceName).Key("record.#").HasValue("2"), + check.That(data.ResourceName).Key("ttl").Exists(), + check.That(data.ResourceName).Key("fqdn").Exists(), + check.That(data.ResourceName).Key("tags.%").HasValue("0"), + ), + }, + }) +} + +func (PrivateDnsSrvRecordDataSource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +data "azurerm_private_dns_srv_record" "test" { + name = azurerm_private_dns_srv_record.test.name + resource_group_name = azurerm_resource_group.test.name + zone_name = azurerm_private_dns_zone.test.name +} +`, PrivateDnsSrvRecordResource{}.basic(data)) +} diff --git a/internal/services/privatedns/private_dns_srv_record_resource.go b/internal/services/privatedns/private_dns_srv_record_resource.go index 847b4925bb34..24873f3bd753 100644 --- a/internal/services/privatedns/private_dns_srv_record_resource.go +++ b/internal/services/privatedns/private_dns_srv_record_resource.go @@ -1,6 +1,7 @@ package privatedns import ( + "bytes" "fmt" "time" @@ -252,3 +253,16 @@ func expandAzureRmPrivateDnsSrvRecords(d *pluginsdk.ResourceData) *[]recordsets. return &records } + +func resourcePrivateDnsSrvRecordHash(v interface{}) int { + var buf bytes.Buffer + + if m, ok := v.(map[string]interface{}); ok { + buf.WriteString(fmt.Sprintf("%d-", m["priority"].(int))) + buf.WriteString(fmt.Sprintf("%d-", m["weight"].(int))) + buf.WriteString(fmt.Sprintf("%d-", m["port"].(int))) + buf.WriteString(fmt.Sprintf("%s-", m["target"].(string))) + } + + return pluginsdk.HashString(buf.String()) +} diff --git a/internal/services/privatedns/private_dns_txt_record_data_source.go b/internal/services/privatedns/private_dns_txt_record_data_source.go new file mode 100644 index 000000000000..e95913ac01ac --- /dev/null +++ b/internal/services/privatedns/private_dns_txt_record_data_source.go @@ -0,0 +1,102 @@ +package privatedns + +import ( + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/privatedns/2018-09-01/recordsets" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" +) + +func dataSourcePrivateDnsTxtRecord() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Read: dataSourcePrivateDnsTxtRecordRead, + + Timeouts: &pluginsdk.ResourceTimeout{ + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "resource_group_name": commonschema.ResourceGroupNameForDataSource(), + + "zone_name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "record": { + Type: pluginsdk.TypeSet, + Computed: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "value": { + Type: pluginsdk.TypeString, + Computed: true, + }, + }, + }, + }, + + "ttl": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "fqdn": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "tags": commonschema.TagsDataSource(), + }, + } +} + +func dataSourcePrivateDnsTxtRecordRead(d *pluginsdk.ResourceData, meta interface{}) error { + recordSetsClient := meta.(*clients.Client).PrivateDns.RecordSetsClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + + id := recordsets.NewRecordTypeID(subscriptionId, d.Get("resource_group_name").(string), d.Get("zone_name").(string), recordsets.RecordTypeTXT, d.Get("name").(string)) + + resp, err := recordSetsClient.Get(ctx, id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return fmt.Errorf("%s was not found", id) + } + return fmt.Errorf("reading %s: %+v", id, err) + } + + d.SetId(id.ID()) + + d.Set("name", id.RelativeRecordSetName) + d.Set("resource_group_name", id.ResourceGroupName) + d.Set("zone_name", id.PrivateZoneName) + + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("ttl", props.Ttl) + d.Set("fqdn", props.Fqdn) + + if err := d.Set("record", flattenAzureRmPrivateDnsTxtRecords(props.TxtRecords)); err != nil { + return err + } + + return tags.FlattenAndSet(d, props.Metadata) + + } + } + + return nil +} diff --git a/internal/services/privatedns/private_dns_txt_record_data_source_test.go b/internal/services/privatedns/private_dns_txt_record_data_source_test.go new file mode 100644 index 000000000000..0412df7f8a66 --- /dev/null +++ b/internal/services/privatedns/private_dns_txt_record_data_source_test.go @@ -0,0 +1,43 @@ +package privatedns_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" +) + +type PrivateDnsTxtRecordDataSource struct{} + +func TestAccDataSourcePrivateDnsTxtRecord_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_private_dns_txt_record", "test") + r := PrivateDnsTxtRecordDataSource{} + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("name").Exists(), + check.That(data.ResourceName).Key("resource_group_name").Exists(), + check.That(data.ResourceName).Key("zone_name").Exists(), + check.That(data.ResourceName).Key("record.#").HasValue("2"), + check.That(data.ResourceName).Key("ttl").Exists(), + check.That(data.ResourceName).Key("fqdn").Exists(), + check.That(data.ResourceName).Key("tags.%").HasValue("0"), + ), + }, + }) +} + +func (PrivateDnsTxtRecordDataSource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +data "azurerm_private_dns_txt_record" "test" { + name = azurerm_private_dns_txt_record.test.name + resource_group_name = azurerm_resource_group.test.name + zone_name = azurerm_private_dns_zone.test.name +} +`, PrivateDnsTxtRecordResource{}.basic(data)) +} diff --git a/internal/services/privatedns/private_dns_zone_data_source.go b/internal/services/privatedns/private_dns_zone_data_source.go index 2d528c2112ed..6e112d3b3ef9 100644 --- a/internal/services/privatedns/private_dns_zone_data_source.go +++ b/internal/services/privatedns/private_dns_zone_data_source.go @@ -66,12 +66,10 @@ func dataSourcePrivateDnsZoneRead(d *pluginsdk.ResourceData, meta interface{}) e ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - name := d.Get("name").(string) - resourceGroup := d.Get("resource_group_name").(string) - id := privatezones.NewPrivateDnsZoneID(subscriptionId, resourceGroup, name) + id := privatezones.NewPrivateDnsZoneID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) var resp *privatezones.PrivateZone - if resourceGroup != "" { + if id.ResourceGroupName != "" { zone, err := client.Get(ctx, id) if err != nil || zone.Model == nil { if response.WasNotFound(zone.HttpResponse) { @@ -83,23 +81,23 @@ func dataSourcePrivateDnsZoneRead(d *pluginsdk.ResourceData, meta interface{}) e } else { resourcesClient := meta.(*clients.Client).Resource.ResourcesClient - zone, err := findPrivateZone(ctx, client, resourcesClient, name) + zone, err := findPrivateZone(ctx, client, resourcesClient, id.PrivateZoneName) if err != nil { return err } if zone == nil { - return fmt.Errorf("Private DNS Zone %q was not found", name) + return fmt.Errorf("%s was not found", id) } resp = &zone.zone - resourceGroup = zone.resourceGroup + id.ResourceGroupName = zone.resourceGroup } d.SetId(id.ID()) - d.Set("name", name) - d.Set("resource_group_name", resourceGroup) + d.Set("name", id.PrivateZoneName) + d.Set("resource_group_name", id.ResourceGroupName) if props := resp.Properties; props != nil { d.Set("number_of_record_sets", props.NumberOfRecordSets) diff --git a/internal/services/privatedns/private_dns_zone_data_source_test.go b/internal/services/privatedns/private_dns_zone_data_source_test.go index c3da28038a20..56bcf029b1a7 100644 --- a/internal/services/privatedns/private_dns_zone_data_source_test.go +++ b/internal/services/privatedns/private_dns_zone_data_source_test.go @@ -14,10 +14,13 @@ func TestAccDataSourcePrivateDNSZone_basic(t *testing.T) { data := acceptance.BuildTestData(t, "data.azurerm_private_dns_zone", "test") r := PrivateDnsZoneDatasource{} + resourceName := "azurerm_private_dns_zone.test" + data.DataSourceTest(t, []acceptance.TestStep{ { Config: r.basic(data), Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("id").MatchesOtherKey(check.That(resourceName).Key("id")), check.That(data.ResourceName).Key("tags.%").HasValue("0"), ), }, @@ -28,10 +31,13 @@ func TestAccDataSourcePrivateDNSZone_tags(t *testing.T) { data := acceptance.BuildTestData(t, "data.azurerm_private_dns_zone", "test") r := PrivateDnsZoneDatasource{} + resourceName := "azurerm_private_dns_zone.test" + data.DataSourceTest(t, []acceptance.TestStep{ { Config: r.tags(data), Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("id").MatchesOtherKey(check.That(resourceName).Key("id")), check.That(data.ResourceName).Key("tags.%").HasValue("1"), check.That(data.ResourceName).Key("tags.hello").HasValue("world"), ), @@ -42,42 +48,37 @@ func TestAccDataSourcePrivateDNSZone_tags(t *testing.T) { func TestAccDataSourcePrivateDNSZone_withoutResourceGroupName(t *testing.T) { data := acceptance.BuildTestData(t, "data.azurerm_private_dns_zone", "test") r := PrivateDnsZoneDatasource{} - resourceGroupName := fmt.Sprintf("acctestRG-%d", data.RandomInteger) + resourceName := "azurerm_private_dns_zone.test" + + // This test is split across multiple test steps to avoid an API race + // condition that occures when running multiple test cases in parallel data.DataSourceTest(t, []acceptance.TestStep{ { - Config: r.onlyNamePrep(data, resourceGroupName), + Config: r.template(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(resourceName).Key("id").Exists(), + ), }, { - Config: r.onlyName(data, resourceGroupName), + Config: r.withoutResourceGroupName(data), Check: acceptance.ComposeTestCheckFunc( - check.That(data.ResourceName).Key("resource_group_name").HasValue(resourceGroupName), + check.That(data.ResourceName).Key("id").MatchesOtherKey(check.That(resourceName).Key("id")), + check.That(data.ResourceName).Key("resource_group_name").MatchesOtherKey(check.That(resourceName).Key("resource_group_name")), ), }, }) } -func (PrivateDnsZoneDatasource) basic(data acceptance.TestData) string { +func (r PrivateDnsZoneDatasource) basic(data acceptance.TestData) string { return fmt.Sprintf(` -provider "azurerm" { - features {} -} - -resource "azurerm_resource_group" "test" { - name = "acctestRG-%d" - location = "%s" -} - -resource "azurerm_private_dns_zone" "test" { - name = "acctestzone%d.internal" - resource_group_name = azurerm_resource_group.test.name -} +%[1]s data "azurerm_private_dns_zone" "test" { name = azurerm_private_dns_zone.test.name resource_group_name = azurerm_private_dns_zone.test.resource_group_name } -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger) +`, r.template(data)) } func (PrivateDnsZoneDatasource) tags(data acceptance.TestData) string { @@ -87,12 +88,12 @@ provider "azurerm" { } resource "azurerm_resource_group" "test" { - name = "acctestRG-%d" - location = "%s" + name = "acctestRG-%[1]d" + location = "%[2]s" } resource "azurerm_private_dns_zone" "test" { - name = "acctestzone%d.internal" + name = "acctestzone%[1]d.internal" resource_group_name = azurerm_resource_group.test.name tags = { @@ -104,33 +105,33 @@ data "azurerm_private_dns_zone" "test" { name = azurerm_private_dns_zone.test.name resource_group_name = azurerm_private_dns_zone.test.resource_group_name } -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger) +`, data.RandomInteger, data.Locations.Primary) } -func (PrivateDnsZoneDatasource) onlyNamePrep(data acceptance.TestData, resourceGroupName string) string { +func (PrivateDnsZoneDatasource) template(data acceptance.TestData) string { return fmt.Sprintf(` provider "azurerm" { features {} } resource "azurerm_resource_group" "test" { - name = "%s" - location = "%s" + name = "acctestRG-%[1]d" + location = "%[2]s" } resource "azurerm_private_dns_zone" "test" { - name = "acctestzone%d.internal" + name = "acctestzone%[1]d.internal" resource_group_name = azurerm_resource_group.test.name } -`, resourceGroupName, data.Locations.Primary, data.RandomInteger) +`, data.RandomInteger, data.Locations.Primary) } -func (r PrivateDnsZoneDatasource) onlyName(data acceptance.TestData, resourceGroupName string) string { +func (r PrivateDnsZoneDatasource) withoutResourceGroupName(data acceptance.TestData) string { return fmt.Sprintf(` -%s +%[1]s data "azurerm_private_dns_zone" "test" { name = azurerm_private_dns_zone.test.name } -`, r.onlyNamePrep(data, resourceGroupName)) +`, r.template(data)) } diff --git a/internal/services/privatedns/registration.go b/internal/services/privatedns/registration.go index 26035b51507c..40b0b0fd4217 100644 --- a/internal/services/privatedns/registration.go +++ b/internal/services/privatedns/registration.go @@ -25,7 +25,15 @@ func (r Registration) WebsiteCategories() []string { // SupportedDataSources returns the supported Data Sources supported by this Service func (r Registration) SupportedDataSources() map[string]*pluginsdk.Resource { return map[string]*pluginsdk.Resource{ - "azurerm_private_dns_zone": dataSourcePrivateDnsZone(), + "azurerm_private_dns_zone": dataSourcePrivateDnsZone(), + "azurerm_private_dns_a_record": dataSourcePrivateDnsARecord(), + "azurerm_private_dns_aaaa_record": dataSourcePrivateDnsAaaaRecord(), + "azurerm_private_dns_cname_record": dataSourcePrivateDnsCNameRecord(), + "azurerm_private_dns_mx_record": dataSourcePrivateDnsMxRecord(), + "azurerm_private_dns_ptr_record": dataSourcePrivateDnsPtrRecord(), + "azurerm_private_dns_soa_record": dataSourcePrivateDnsSoaRecord(), + "azurerm_private_dns_srv_record": dataSourcePrivateDnsSrvRecord(), + "azurerm_private_dns_txt_record": dataSourcePrivateDnsTxtRecord(), } } diff --git a/internal/services/recoveryservices/backup_policy_vm_resource.go b/internal/services/recoveryservices/backup_policy_vm_resource.go index 7f6325f03ac3..80c96013db1c 100644 --- a/internal/services/recoveryservices/backup_policy_vm_resource.go +++ b/internal/services/recoveryservices/backup_policy_vm_resource.go @@ -353,6 +353,16 @@ func expandBackupProtectionPolicyVMSchedule(d *pluginsdk.ResourceData, times []d return nil, fmt.Errorf("`hour_duration` must be specified when `backup.0.frequency` is `Hourly`") } + if interval == 0 && duration == 0 { + return nil, fmt.Errorf("`hour_interval` and `hour_duration` must be specified when `backup.0.frequency` is `Hourly`") + } + if interval == 0 { + return nil, fmt.Errorf("`hour_interval` must be specified when `backup.0.frequency` is `Hourly`") + } + if duration == 0 { + return nil, fmt.Errorf("`hour_duration` must be specified when `backup.0.frequency` is `Hourly`") + } + if duration%interval != 0 { return nil, fmt.Errorf("`hour_duration` must be multiplier of `hour_interval`") } diff --git a/internal/services/recoveryservices/backup_policy_vm_workload_resource.go b/internal/services/recoveryservices/backup_policy_vm_workload_resource.go new file mode 100644 index 000000000000..abd9f4cca0f9 --- /dev/null +++ b/internal/services/recoveryservices/backup_policy_vm_workload_resource.go @@ -0,0 +1,1096 @@ +package recoveryservices + +import ( + "context" + "fmt" + "regexp" + "time" + + "github.com/Azure/azure-sdk-for-go/services/recoveryservices/mgmt/2021-12-01/backup" + "github.com/Azure/go-autorest/autorest/date" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" + "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/recoveryservices/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/recoveryservices/validate" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/set" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/suppress" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type BackupProtectionPolicyVMWorkloadModel struct { + Name string `tfschema:"name"` + ResourceGroupName string `tfschema:"resource_group_name"` + RecoveryVaultName string `tfschema:"recovery_vault_name"` + ProtectionPolicies []ProtectionPolicy `tfschema:"protection_policy"` + Settings []Settings `tfschema:"settings"` + WorkloadType string `tfschema:"workload_type"` +} + +type ProtectionPolicy struct { + Backup []Backup `tfschema:"backup"` + PolicyType string `tfschema:"policy_type"` + RetentionDaily []RetentionDaily `tfschema:"retention_daily"` + RetentionWeekly []RetentionWeekly `tfschema:"retention_weekly"` + RetentionMonthly []RetentionMonthly `tfschema:"retention_monthly"` + RetentionYearly []RetentionYearly `tfschema:"retention_yearly"` + SimpleRetention []SimpleRetention `tfschema:"simple_retention"` +} + +type Backup struct { + Frequency string `tfschema:"frequency"` + FrequencyInMinutes int32 `tfschema:"frequency_in_minutes"` + Time string `tfschema:"time"` + Weekdays []string `tfschema:"weekdays"` +} + +type RetentionDaily struct { + Count int32 `tfschema:"count"` +} + +type RetentionWeekly struct { + Count int32 `tfschema:"count"` + Weekdays []string `tfschema:"weekdays"` +} + +type RetentionMonthly struct { + Count int32 `tfschema:"count"` + FormatType string `tfschema:"format_type"` + Monthdays []int `tfschema:"monthdays"` + Weeks []string `tfschema:"weeks"` + Weekdays []string `tfschema:"weekdays"` +} + +type RetentionYearly struct { + Count int32 `tfschema:"count"` + FormatType string `tfschema:"format_type"` + Months []string `tfschema:"months"` + Monthdays []int `tfschema:"monthdays"` + Weeks []string `tfschema:"weeks"` + Weekdays []string `tfschema:"weekdays"` +} + +type SimpleRetention struct { + Count int32 `tfschema:"count"` +} + +type Settings struct { + CompressionEnabled bool `tfschema:"compression_enabled"` + TimeZone string `tfschema:"time_zone"` +} + +type BackupProtectionPolicyVMWorkloadResource struct{} + +var _ sdk.ResourceWithUpdate = BackupProtectionPolicyVMWorkloadResource{} + +func (r BackupProtectionPolicyVMWorkloadResource) ResourceType() string { + return "azurerm_backup_policy_vm_workload" +} + +func (r BackupProtectionPolicyVMWorkloadResource) ModelObject() interface{} { + return &BackupProtectionPolicyVMWorkloadModel{} +} + +func (r BackupProtectionPolicyVMWorkloadResource) IDValidationFunc() pluginsdk.SchemaValidateFunc { + return validate.BackupPolicyID +} + +func (r BackupProtectionPolicyVMWorkloadResource) Arguments() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.BackupPolicyName, + }, + + "resource_group_name": commonschema.ResourceGroupName(), + + "recovery_vault_name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.RecoveryServicesVaultName, + }, + + "protection_policy": { + Type: pluginsdk.TypeSet, + Required: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "policy_type": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(backup.PolicyTypeDifferential), + string(backup.PolicyTypeFull), + string(backup.PolicyTypeIncremental), + string(backup.PolicyTypeLog), + }, false), + }, + + "backup": { + Type: pluginsdk.TypeList, + Required: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "frequency": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + string(backup.ScheduleRunTypeDaily), + string(backup.ScheduleRunTypeWeekly), + }, false), + }, + + "frequency_in_minutes": { + Type: pluginsdk.TypeInt, + Optional: true, + ValidateFunc: validation.IntInSlice([]int{ + 15, + 30, + 60, + 120, + 240, + 480, + 720, + 1440, + }), + }, + + "time": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.StringMatch( + regexp.MustCompile("^([01][0-9]|[2][0-3]):([03][0])$"), + "Time of day must match the format HH:mm where HH is 00-23 and mm is 00 or 30", + ), + }, + + "weekdays": { + Type: pluginsdk.TypeSet, + Optional: true, + Set: set.HashStringIgnoreCase, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + DiffSuppressFunc: suppress.CaseDifference, + ValidateFunc: validation.IsDayOfTheWeek(true), + }, + }, + }, + }, + }, + + "retention_daily": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "count": { + Type: pluginsdk.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(7, 9999), + }, + }, + }, + }, + + "retention_weekly": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "count": { + Type: pluginsdk.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(1, 5163), + }, + + "weekdays": { + Type: pluginsdk.TypeSet, + Required: true, + Set: set.HashStringIgnoreCase, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + DiffSuppressFunc: suppress.CaseDifference, + ValidateFunc: validation.IsDayOfTheWeek(true), + }, + }, + }, + }, + }, + + "retention_monthly": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "count": { + Type: pluginsdk.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(1, 1188), + }, + + "format_type": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(backup.RetentionScheduleFormatDaily), + string(backup.RetentionScheduleFormatWeekly), + }, false), + }, + + "monthdays": { + Type: pluginsdk.TypeSet, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeInt, + ValidateFunc: validation.IntBetween(0, 28), + }, + }, + + "weeks": { + Type: pluginsdk.TypeSet, + Optional: true, + Set: set.HashStringIgnoreCase, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringInSlice([]string{ + string(backup.WeekOfMonthFirst), + string(backup.WeekOfMonthSecond), + string(backup.WeekOfMonthThird), + string(backup.WeekOfMonthFourth), + string(backup.WeekOfMonthLast), + }, false), + }, + }, + + "weekdays": { + Type: pluginsdk.TypeSet, + Optional: true, + Set: set.HashStringIgnoreCase, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + DiffSuppressFunc: suppress.CaseDifference, + ValidateFunc: validation.IsDayOfTheWeek(true), + }, + }, + }, + }, + }, + + "retention_yearly": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "count": { + Type: pluginsdk.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(1, 99), + }, + + "format_type": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(backup.RetentionScheduleFormatDaily), + string(backup.RetentionScheduleFormatWeekly), + }, false), + }, + + "months": { + Type: pluginsdk.TypeSet, + Required: true, + Set: set.HashStringIgnoreCase, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + DiffSuppressFunc: suppress.CaseDifference, + ValidateFunc: validation.IsMonth(true), + }, + }, + + "monthdays": { + Type: pluginsdk.TypeSet, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeInt, + ValidateFunc: validation.IntBetween(0, 28), + }, + }, + + "weeks": { + Type: pluginsdk.TypeSet, + Optional: true, + Set: set.HashStringIgnoreCase, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringInSlice([]string{ + string(backup.WeekOfMonthFirst), + string(backup.WeekOfMonthSecond), + string(backup.WeekOfMonthThird), + string(backup.WeekOfMonthFourth), + string(backup.WeekOfMonthLast), + }, false), + }, + }, + + "weekdays": { + Type: pluginsdk.TypeSet, + Optional: true, + Set: set.HashStringIgnoreCase, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + DiffSuppressFunc: suppress.CaseDifference, + ValidateFunc: validation.IsDayOfTheWeek(true), + }, + }, + }, + }, + }, + + "simple_retention": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "count": { + Type: pluginsdk.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(7, 35), + }, + }, + }, + }, + }, + }, + }, + + "settings": { + Type: pluginsdk.TypeList, + Required: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "time_zone": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "compression_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: false, + }, + }, + }, + }, + + "workload_type": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{ + string(backup.WorkloadTypeSQLDataBase), + string(backup.WorkloadTypeSAPHanaDatabase), + }, false), + }, + } +} + +func (r BackupProtectionPolicyVMWorkloadResource) Attributes() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{} +} + +func (r BackupProtectionPolicyVMWorkloadResource) Create() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + var model BackupProtectionPolicyVMWorkloadModel + if err := metadata.Decode(&model); err != nil { + return fmt.Errorf("decoding: %+v", err) + } + + client := metadata.Client.RecoveryServices.ProtectionPoliciesClient + subscriptionId := metadata.Client.Account.SubscriptionId + + id := parse.NewBackupPolicyID(subscriptionId, model.ResourceGroupName, model.RecoveryVaultName, model.Name) + + existing, err := client.Get(ctx, id.VaultName, id.ResourceGroup, id.Name) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("checking for existing %s: %+v", id, err) + } + } + if !utils.ResponseWasNotFound(existing.Response) { + return tf.ImportAsExistsError("azurerm_backup_policy_vm_workload", id.ID()) + } + + protectionPolicy, err := expandBackupProtectionPolicyVMWorkloadProtectionPolicies(model.ProtectionPolicies, model.WorkloadType) + if err != nil { + return err + } + + properties := &backup.ProtectionPolicyResource{ + Properties: &backup.AzureVMWorkloadProtectionPolicy{ + BackupManagementType: backup.ManagementTypeBasicProtectionPolicyBackupManagementTypeAzureWorkload, + Settings: expandBackupProtectionPolicyVMWorkloadSettings(model.Settings), + SubProtectionPolicy: protectionPolicy, + WorkLoadType: backup.WorkloadType(model.WorkloadType), + }, + } + + if _, err := client.CreateOrUpdate(ctx, id.VaultName, id.ResourceGroup, id.Name, *properties); err != nil { + return fmt.Errorf("creating %s: %+v", id, err) + } + + metadata.SetID(id) + return nil + }, + } +} + +func (r BackupProtectionPolicyVMWorkloadResource) Update() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.RecoveryServices.ProtectionPoliciesClient + + id, err := parse.BackupPolicyID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + var model BackupProtectionPolicyVMWorkloadModel + if err := metadata.Decode(&model); err != nil { + return fmt.Errorf("decoding: %+v", err) + } + + existing, err := client.Get(ctx, id.VaultName, id.ResourceGroup, id.Name) + if err != nil { + return fmt.Errorf("retrieving %s: %+v", *id, err) + } + + props, _ := existing.Properties.AsAzureVMWorkloadProtectionPolicy() + + if metadata.ResourceData.HasChange("settings") { + props.Settings = expandBackupProtectionPolicyVMWorkloadSettings(model.Settings) + } + + if metadata.ResourceData.HasChange("protection_policy") { + protectionPolicy, err := expandBackupProtectionPolicyVMWorkloadProtectionPolicies(model.ProtectionPolicies, model.WorkloadType) + if err != nil { + return err + } + + props.SubProtectionPolicy = protectionPolicy + } + + existing.Properties = props + + if _, err := client.CreateOrUpdate(ctx, id.VaultName, id.ResourceGroup, id.Name, existing); err != nil { + return fmt.Errorf("updating %s: %+v", *id, err) + } + + return nil + }, + } +} + +func (r BackupProtectionPolicyVMWorkloadResource) Read() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 5 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.RecoveryServices.ProtectionPoliciesClient + + id, err := parse.BackupPolicyID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + resp, err := client.Get(ctx, id.VaultName, id.ResourceGroup, id.Name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return metadata.MarkAsGone(id) + } + + return fmt.Errorf("retrieving %s: %+v", *id, err) + } + + state := BackupProtectionPolicyVMWorkloadModel{ + Name: id.Name, + ResourceGroupName: id.ResourceGroup, + RecoveryVaultName: id.VaultName, + } + + if props := resp.Properties; props != nil { + vmWorkload, _ := props.AsAzureVMWorkloadProtectionPolicy() + state.WorkloadType = string(vmWorkload.WorkLoadType) + state.Settings = flattenBackupProtectionPolicyVMWorkloadSettings(vmWorkload.Settings) + state.ProtectionPolicies = flattenBackupProtectionPolicyVMWorkloadProtectionPolicies(vmWorkload.SubProtectionPolicy) + } + + return metadata.Encode(&state) + }, + } +} + +func (r BackupProtectionPolicyVMWorkloadResource) Delete() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.RecoveryServices.ProtectionPoliciesClient + + id, err := parse.BackupPolicyID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + future, err := client.Delete(ctx, id.VaultName, id.ResourceGroup, id.Name) + if err != nil { + return fmt.Errorf("deleting %s: %+v", *id, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for the deletion of %s: %+v", *id, err) + } + + return nil + }, + } +} + +func expandBackupProtectionPolicyVMWorkloadSettings(input []Settings) *backup.Settings { + if len(input) == 0 { + return &backup.Settings{} + } + + settings := input[0] + result := &backup.Settings{ + IsCompression: utils.Bool(settings.CompressionEnabled), + } + + if settings.TimeZone != "" { + result.TimeZone = utils.String(settings.TimeZone) + } + + return result +} + +func flattenBackupProtectionPolicyVMWorkloadSettings(input *backup.Settings) []Settings { + if input == nil { + return make([]Settings, 0) + } + + result := make([]Settings, 0) + + result = append(result, Settings{ + CompressionEnabled: *input.IsCompression, + TimeZone: *input.TimeZone, + }) + + return result +} + +func expandBackupProtectionPolicyVMWorkloadProtectionPolicies(input []ProtectionPolicy, workloadType string) (*[]backup.SubProtectionPolicy, error) { + if len(input) == 0 { + return nil, nil + } + + results := make([]backup.SubProtectionPolicy, 0) + + for _, item := range input { + if workloadType == string(backup.WorkloadTypeSQLDataBase) && item.PolicyType == string(backup.PolicyTypeIncremental) { + return nil, fmt.Errorf("the Incremental backup isn't supported when `workload_type` is `SQLDataBase`") + } + + backupBlock := item.Backup[0] + + // getting this ready now because its shared between *everything*, time is... complicated for this resource + timeOfDay := backupBlock.Time + times := make([]date.Time, 0) + if timeOfDay != "" { + dateOfDay, err := time.Parse(time.RFC3339, fmt.Sprintf("2018-07-30T%s:00Z", timeOfDay)) + if err != nil { + return nil, fmt.Errorf("generating time from %q for policy): %+v", timeOfDay, err) + } + times = append(times, date.Time{Time: dateOfDay}) + } + + switch backupBlock.Frequency { + case string(backup.ScheduleRunTypeDaily): + if item.RetentionDaily == nil || len(item.RetentionDaily) == 0 { + return nil, fmt.Errorf("`retention_daily` must be set when `backup.0.frequency` is `Daily`") + } + + if weekdays := backupBlock.Weekdays; weekdays != nil && len(weekdays) > 0 { + return nil, fmt.Errorf("`backup.0.weekdays` should be not set when `backup.0.frequency` is `Daily`") + } + case string(backup.ScheduleRunTypeWeekly): + if item.RetentionDaily != nil && len(item.RetentionDaily) > 0 { + return nil, fmt.Errorf("`retention_daily` must be not set when `backup.0.frequency` is `Weekly`") + } + + if item.PolicyType != string(backup.PolicyTypeLog) && (backupBlock.Weekdays == nil || len(backupBlock.Weekdays) == 0) { + return nil, fmt.Errorf("`backup.weekdays` must be set when `policy_type` is not `Log` and `backup.frequency` is `Weekly`") + } + + if item.PolicyType == string(backup.PolicyTypeFull) && (item.RetentionWeekly == nil || len(item.RetentionWeekly) == 0) { + return nil, fmt.Errorf("`retention_weekly` must be set when `policy_type` is `Full` and `backup.frequency` is `Weekly`") + } + } + + result := backup.SubProtectionPolicy{ + PolicyType: backup.PolicyType(item.PolicyType), + SchedulePolicy: expandBackupProtectionPolicyVMWorkloadSchedulePolicy(item, times), + } + + if v, err := expandBackupProtectionPolicyVMWorkloadRetentionPolicy(item, times); err != nil { + return nil, err + } else { + result.RetentionPolicy = v + } + + results = append(results, result) + } + + return &results, nil +} + +func flattenBackupProtectionPolicyVMWorkloadProtectionPolicies(input *[]backup.SubProtectionPolicy) []ProtectionPolicy { + results := make([]ProtectionPolicy, 0) + if input == nil { + return results + } + + for _, item := range *input { + var policyType backup.PolicyType + if item.PolicyType != "" { + policyType = item.PolicyType + } + + result := ProtectionPolicy{ + PolicyType: string(policyType), + Backup: flattenBackupProtectionPolicyVMWorkloadSchedulePolicy(item.SchedulePolicy, policyType), + } + + if retentionPolicy := item.RetentionPolicy; retentionPolicy != nil { + if longTermRetentionPolicy, ok := retentionPolicy.AsLongTermRetentionPolicy(); ok { + result.RetentionDaily = flattenBackupProtectionPolicyVMWorkloadRetentionDaily(longTermRetentionPolicy.DailySchedule) + result.RetentionWeekly = flattenBackupProtectionPolicyVMWorkloadRetentionWeekly(longTermRetentionPolicy.WeeklySchedule) + result.RetentionMonthly = flattenBackupProtectionPolicyVMWorkloadRetentionMonthly(longTermRetentionPolicy.MonthlySchedule) + result.RetentionYearly = flattenBackupProtectionPolicyVMWorkloadRetentionYearly(longTermRetentionPolicy.YearlySchedule) + } else { + simpleRetentionPolicy, _ := retentionPolicy.AsSimpleRetentionPolicy() + result.SimpleRetention = flattenBackupProtectionPolicyVMWorkloadSimpleRetention(simpleRetentionPolicy.RetentionDuration) + } + } + + results = append(results, result) + } + + return results +} + +func expandBackupProtectionPolicyVMWorkloadSchedulePolicy(input ProtectionPolicy, times []date.Time) backup.BasicSchedulePolicy { + if input.PolicyType == string(backup.PolicyTypeLog) { + schedule := backup.LogSchedulePolicy{ + SchedulePolicyType: backup.SchedulePolicyTypeLogSchedulePolicy, + } + + if v := input.Backup[0].FrequencyInMinutes; v != 0 { + schedule.ScheduleFrequencyInMins = utils.Int32(v) + } + + result, _ := schedule.AsBasicSchedulePolicy() + return result + } else { + schedule := backup.SimpleSchedulePolicy{ + SchedulePolicyType: backup.SchedulePolicyTypeSimpleSchedulePolicy, + } + + backupBlock := input.Backup[0] + if backupBlock.Frequency != "" { + schedule.ScheduleRunFrequency = backup.ScheduleRunType(backupBlock.Frequency) + } + + if times != nil && len(times) > 0 { + schedule.ScheduleRunTimes = × + } + + if v := backupBlock.Weekdays; v != nil && len(v) > 0 { + days := make([]backup.DayOfWeek, 0) + for _, day := range v { + days = append(days, backup.DayOfWeek(day)) + } + schedule.ScheduleRunDays = &days + } + + result, _ := schedule.AsBasicSchedulePolicy() + return result + } +} + +func flattenBackupProtectionPolicyVMWorkloadSchedulePolicy(input backup.BasicSchedulePolicy, policyType backup.PolicyType) []Backup { + if input == nil { + return nil + } + + backupBlock := Backup{} + + if policyType == backup.PolicyTypeLog { + logSchedulePolicy, _ := input.AsLogSchedulePolicy() + + if v := logSchedulePolicy.ScheduleFrequencyInMins; v != nil { + backupBlock.FrequencyInMinutes = *v + } + } else { + simpleSchedulePolicy, _ := input.AsSimpleSchedulePolicy() + + backupBlock.Frequency = string(simpleSchedulePolicy.ScheduleRunFrequency) + + if times := simpleSchedulePolicy.ScheduleRunTimes; times != nil && len(*times) > 0 { + backupBlock.Time = (*times)[0].Format("15:04") + } + + if days := simpleSchedulePolicy.ScheduleRunDays; days != nil { + weekdays := make([]string, 0) + for _, d := range *days { + weekdays = append(weekdays, string(d)) + } + backupBlock.Weekdays = weekdays + } + } + + return []Backup{backupBlock} +} + +func expandBackupProtectionPolicyVMWorkloadRetentionPolicy(input ProtectionPolicy, times []date.Time) (backup.BasicRetentionPolicy, error) { + if input.PolicyType == string(backup.PolicyTypeFull) { + retentionPolicy := backup.LongTermRetentionPolicy{ + RetentionPolicyType: backup.RetentionPolicyTypeLongTermRetentionPolicy, + } + + if input.RetentionDaily != nil && len(input.RetentionDaily) > 0 { + retentionDaily := input.RetentionDaily[0] + + retentionPolicy.DailySchedule = &backup.DailyRetentionSchedule{ + RetentionTimes: ×, + RetentionDuration: &backup.RetentionDuration{ + Count: utils.Int32(retentionDaily.Count), + DurationType: backup.RetentionDurationTypeDays, + }, + } + } + + if input.RetentionWeekly != nil && len(input.RetentionWeekly) > 0 { + retentionWeekly := input.RetentionWeekly[0] + + retentionPolicy.WeeklySchedule = &backup.WeeklyRetentionSchedule{ + RetentionTimes: ×, + RetentionDuration: &backup.RetentionDuration{ + Count: utils.Int32(retentionWeekly.Count), + DurationType: backup.RetentionDurationTypeWeeks, + }, + } + + if v := retentionWeekly.Weekdays; v != nil && len(v) > 0 { + days := make([]backup.DayOfWeek, 0) + for _, day := range v { + days = append(days, backup.DayOfWeek(day)) + } + retentionPolicy.WeeklySchedule.DaysOfTheWeek = &days + } + } + + if input.RetentionMonthly != nil && len(input.RetentionMonthly) > 0 { + retentionMonthly := input.RetentionMonthly[0] + + if input.Backup[0].Frequency == string(backup.ScheduleRunTypeWeekly) && retentionMonthly.FormatType != string(backup.RetentionScheduleFormatWeekly) { + return nil, fmt.Errorf("`retention_monthly.format_type` must be `Weekly` when `policy_type` is `Full` and `frequency` is `Weekly`") + } + + if retentionMonthly.FormatType == string(backup.RetentionScheduleFormatDaily) && (retentionMonthly.Monthdays == nil || len(retentionMonthly.Monthdays) == 0) { + return nil, fmt.Errorf("`retention_monthly.monthdays` must be set when `retention_monthly.format_type` is `Daily`") + } + + if retentionMonthly.FormatType == string(backup.RetentionScheduleFormatWeekly) && ((retentionMonthly.Weeks == nil || len(retentionMonthly.Weeks) == 0) || (retentionMonthly.Weekdays == nil || len(retentionMonthly.Weekdays) == 0)) { + return nil, fmt.Errorf("`retention_monthly.weeks` and `retention_monthly.weekdays` must be set when `retention_monthly.format_type` is `Weekly`") + } + + retentionPolicy.MonthlySchedule = &backup.MonthlyRetentionSchedule{ + RetentionScheduleFormatType: backup.RetentionScheduleFormat(retentionMonthly.FormatType), + RetentionScheduleDaily: expandBackupProtectionPolicyVMWorkloadRetentionDailyFormat(retentionMonthly.Monthdays), + RetentionScheduleWeekly: expandBackupProtectionPolicyVMWorkloadRetentionWeeklyFormat(retentionMonthly.Weekdays, retentionMonthly.Weeks), + RetentionTimes: ×, + RetentionDuration: &backup.RetentionDuration{ + Count: utils.Int32(retentionMonthly.Count), + DurationType: backup.RetentionDurationTypeMonths, + }, + } + } + + if input.RetentionYearly != nil && len(input.RetentionYearly) > 0 { + retentionYearly := input.RetentionYearly[0] + + if input.Backup[0].Frequency == string(backup.ScheduleRunTypeWeekly) && retentionYearly.FormatType != string(backup.RetentionScheduleFormatWeekly) { + return nil, fmt.Errorf("`retention_yearly.format_type` must be `Weekly` when `policy_type` is `Full` and `frequency` is `Weekly`") + } + + if retentionYearly.FormatType == string(backup.RetentionScheduleFormatDaily) && (retentionYearly.Monthdays == nil || len(retentionYearly.Monthdays) == 0) { + return nil, fmt.Errorf("`retention_yearly.monthdays` must be set when `retention_yearly.format_type` is `Daily`") + } + + if retentionYearly.FormatType == string(backup.RetentionScheduleFormatWeekly) && ((retentionYearly.Weeks == nil || len(retentionYearly.Weeks) == 0) || (retentionYearly.Weekdays == nil || len(retentionYearly.Weekdays) == 0)) { + return nil, fmt.Errorf("`retention_yearly.weeks` and `retention_yearly.weekdays` must be set when `retention_yearly.format_type` is `Weekly`") + } + + retentionPolicy.YearlySchedule = &backup.YearlyRetentionSchedule{ + RetentionScheduleFormatType: backup.RetentionScheduleFormat(retentionYearly.FormatType), + RetentionScheduleDaily: expandBackupProtectionPolicyVMWorkloadRetentionDailyFormat(retentionYearly.Monthdays), + RetentionScheduleWeekly: expandBackupProtectionPolicyVMWorkloadRetentionWeeklyFormat(retentionYearly.Weekdays, retentionYearly.Weeks), + RetentionTimes: ×, + RetentionDuration: &backup.RetentionDuration{ + Count: utils.Int32(retentionYearly.Count), + DurationType: backup.RetentionDurationTypeYears, + }, + } + + if v := retentionYearly.Months; v != nil { + months := make([]backup.MonthOfYear, 0) + for _, month := range v { + months = append(months, backup.MonthOfYear(month)) + } + retentionPolicy.YearlySchedule.MonthsOfYear = &months + } + } + + return retentionPolicy, nil + } else { + retentionPolicy := backup.SimpleRetentionPolicy{ + RetentionPolicyType: backup.RetentionPolicyTypeSimpleRetentionPolicy, + } + + if input.SimpleRetention != nil && len(input.SimpleRetention) > 0 { + simpleRetention := input.SimpleRetention[0] + + retentionPolicy.RetentionDuration = &backup.RetentionDuration{ + Count: utils.Int32(simpleRetention.Count), + DurationType: backup.RetentionDurationTypeDays, + } + } + + return retentionPolicy, nil + } +} + +func flattenBackupProtectionPolicyVMWorkloadRetentionDaily(input *backup.DailyRetentionSchedule) []RetentionDaily { + if input == nil { + return nil + } + + retentionDailyBlock := RetentionDaily{} + + if duration := input.RetentionDuration; duration != nil { + if v := duration.Count; v != nil { + retentionDailyBlock.Count = *v + } + } + + return []RetentionDaily{retentionDailyBlock} +} + +func flattenBackupProtectionPolicyVMWorkloadRetentionWeekly(input *backup.WeeklyRetentionSchedule) []RetentionWeekly { + if input == nil { + return nil + } + + retentionWeeklyBlock := RetentionWeekly{} + + if duration := input.RetentionDuration; duration != nil { + if v := duration.Count; v != nil { + retentionWeeklyBlock.Count = *v + } + } + + if days := input.DaysOfTheWeek; days != nil { + weekdays := make([]string, 0) + for _, d := range *days { + weekdays = append(weekdays, string(d)) + } + retentionWeeklyBlock.Weekdays = weekdays + } + + return []RetentionWeekly{retentionWeeklyBlock} +} + +func flattenBackupProtectionPolicyVMWorkloadRetentionMonthly(input *backup.MonthlyRetentionSchedule) []RetentionMonthly { + if input == nil { + return nil + } + + retentionMonthlyBlock := RetentionMonthly{} + + if duration := input.RetentionDuration; duration != nil { + if v := duration.Count; v != nil { + retentionMonthlyBlock.Count = *v + } + } + + if formatType := input.RetentionScheduleFormatType; formatType != "" { + retentionMonthlyBlock.FormatType = string(formatType) + } + + if weekly := input.RetentionScheduleWeekly; weekly != nil { + retentionMonthlyBlock.Weekdays, retentionMonthlyBlock.Weeks = flattenBackupProtectionPolicyVMWorkloadRetentionWeeklyFormat(weekly) + } + + if daily := input.RetentionScheduleDaily; daily != nil { + retentionMonthlyBlock.Monthdays = flattenBackupProtectionPolicyVMWorkloadRetentionDailyFormat(daily) + } + + return []RetentionMonthly{retentionMonthlyBlock} +} + +func flattenBackupProtectionPolicyVMWorkloadRetentionYearly(input *backup.YearlyRetentionSchedule) []RetentionYearly { + if input == nil { + return nil + } + + retentionYearlyBlock := RetentionYearly{} + + if duration := input.RetentionDuration; duration != nil { + if v := duration.Count; v != nil { + retentionYearlyBlock.Count = *v + } + } + + if formatType := input.RetentionScheduleFormatType; formatType != "" { + retentionYearlyBlock.FormatType = string(formatType) + } + + if weekly := input.RetentionScheduleWeekly; weekly != nil { + retentionYearlyBlock.Weekdays, retentionYearlyBlock.Weeks = flattenBackupProtectionPolicyVMWorkloadRetentionWeeklyFormat(weekly) + } + + if v := input.MonthsOfYear; v != nil { + months := make([]string, 0) + for _, d := range *v { + months = append(months, string(d)) + } + retentionYearlyBlock.Months = months + } + + if daily := input.RetentionScheduleDaily; daily != nil { + retentionYearlyBlock.Monthdays = flattenBackupProtectionPolicyVMWorkloadRetentionDailyFormat(daily) + } + + return []RetentionYearly{retentionYearlyBlock} +} + +func flattenBackupProtectionPolicyVMWorkloadSimpleRetention(input *backup.RetentionDuration) []SimpleRetention { + if input == nil { + return nil + } + + simpleRetentionBlock := SimpleRetention{} + + if v := input.Count; v != nil { + simpleRetentionBlock.Count = *v + } + + return []SimpleRetention{simpleRetentionBlock} +} + +func expandBackupProtectionPolicyVMWorkloadRetentionDailyFormat(input []int) *backup.DailyRetentionFormat { + if input == nil || len(input) == 0 { + return nil + } + + daily := backup.DailyRetentionFormat{} + + days := make([]backup.Day, 0) + for _, item := range input { + day := backup.Day{ + Date: utils.Int32(int32((item))), + } + + if item == 0 { + day.IsLast = utils.Bool(true) + } else { + day.IsLast = utils.Bool(false) + } + + days = append(days, day) + } + daily.DaysOfTheMonth = &days + + return &daily +} + +func expandBackupProtectionPolicyVMWorkloadRetentionWeeklyFormat(weekdays, weeks []string) *backup.WeeklyRetentionFormat { + if (weekdays == nil && weeks == nil) || (len(weekdays) == 0 && len(weeks) == 0) { + return nil + } + + weekly := backup.WeeklyRetentionFormat{} + + if weekdays != nil && len(weekdays) > 0 { + weekdaysBlock := make([]backup.DayOfWeek, 0) + for _, day := range weekdays { + weekdaysBlock = append(weekdaysBlock, backup.DayOfWeek(day)) + } + weekly.DaysOfTheWeek = &weekdaysBlock + } + + if weeks != nil && len(weeks) > 0 { + weeksBlock := make([]backup.WeekOfMonth, 0) + for _, week := range weeks { + weeksBlock = append(weeksBlock, backup.WeekOfMonth(week)) + } + weekly.WeeksOfTheMonth = &weeksBlock + } + + return &weekly +} + +func flattenBackupProtectionPolicyVMWorkloadRetentionWeeklyFormat(input *backup.WeeklyRetentionFormat) (weekdays, weeks []string) { + if v := input.DaysOfTheWeek; v != nil { + days := make([]string, 0) + for _, d := range *v { + days = append(days, string(d)) + } + weekdays = days + } + + if v := input.WeeksOfTheMonth; v != nil { + days := make([]string, 0) + for _, d := range *v { + days = append(days, string(d)) + } + weeks = days + } + + return weekdays, weeks +} + +func flattenBackupProtectionPolicyVMWorkloadRetentionDailyFormat(input *backup.DailyRetentionFormat) []int { + result := make([]int, 0) + + if days := input.DaysOfTheMonth; days != nil { + for _, d := range *days { + result = append(result, int(*d.Date)) + } + } + + return result +} diff --git a/internal/services/recoveryservices/backup_policy_vm_workload_resource_test.go b/internal/services/recoveryservices/backup_policy_vm_workload_resource_test.go new file mode 100644 index 000000000000..c17fae6af74c --- /dev/null +++ b/internal/services/recoveryservices/backup_policy_vm_workload_resource_test.go @@ -0,0 +1,319 @@ +package recoveryservices_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/recoveryservices/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type BackupProtectionPolicyVMWorkloadResource struct{} + +func TestAccBackupProtectionPolicyVMWorkload_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_backup_policy_vm_workload", "test") + r := BackupProtectionPolicyVMWorkloadResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeAggregateTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccBackupProtectionPolicyVMWorkload_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_backup_policy_vm_workload", "test") + r := BackupProtectionPolicyVMWorkloadResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.complete(data), + Check: acceptance.ComposeAggregateTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.update(data), + Check: acceptance.ComposeAggregateTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func (t BackupProtectionPolicyVMWorkloadResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + id, err := parse.BackupPolicyID(state.ID) + if err != nil { + return nil, err + } + + resp, err := clients.RecoveryServices.ProtectionPoliciesClient.Get(ctx, id.VaultName, id.ResourceGroup, id.Name) + if err != nil { + return nil, fmt.Errorf("reading Recovery Service Protection Policy (%s): %+v", id.String(), err) + } + + return utils.Bool(resp.ID != nil), nil +} + +func (r BackupProtectionPolicyVMWorkloadResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-bpvmw-%d" + location = "%s" +} + +resource "azurerm_recovery_services_vault" "test" { + name = "acctest-rsv-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku = "Standard" + soft_delete_enabled = false +} + +resource "azurerm_backup_policy_vm_workload" "test" { + name = "acctest-bpvmw-%d" + resource_group_name = azurerm_resource_group.test.name + recovery_vault_name = azurerm_recovery_services_vault.test.name + + workload_type = "SQLDataBase" + + settings { + time_zone = "UTC" + compression_enabled = false + } + + protection_policy { + policy_type = "Full" + + backup { + frequency = "Daily" + time = "15:00" + } + + retention_daily { + count = 8 + } + + retention_monthly { + format_type = "Daily" + count = 10 + monthdays = [27, 28] + } + + retention_yearly { + format_type = "Daily" + count = 10 + months = ["February"] + monthdays = [27, 28] + } + } + + protection_policy { + policy_type = "Log" + + backup { + frequency_in_minutes = 15 + } + + simple_retention { + count = 8 + } + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} + +func (r BackupProtectionPolicyVMWorkloadResource) complete(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-bpvmw-%d" + location = "%s" +} + +resource "azurerm_recovery_services_vault" "test" { + name = "acctest-rsv-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku = "Standard" + soft_delete_enabled = false +} + +resource "azurerm_backup_policy_vm_workload" "test" { + name = "acctest-bpvmw-%d" + resource_group_name = azurerm_resource_group.test.name + recovery_vault_name = azurerm_recovery_services_vault.test.name + + workload_type = "SAPHanaDatabase" + + settings { + time_zone = "UTC" + compression_enabled = true + } + + protection_policy { + policy_type = "Full" + + backup { + frequency = "Weekly" + time = "15:00" + weekdays = ["Monday", "Tuesday"] + } + + retention_weekly { + weekdays = ["Monday", "Tuesday"] + count = 4 + } + + retention_monthly { + format_type = "Weekly" + weeks = ["Third"] + weekdays = ["Tuesday"] + count = 10 + } + + retention_yearly { + format_type = "Weekly" + months = ["May", "February"] + weeks = ["Third"] + weekdays = ["Tuesday"] + count = 8 + } + } + + protection_policy { + policy_type = "Incremental" + + backup { + frequency = "Weekly" + weekdays = ["Saturday", "Friday"] + time = "23:00" + } + + simple_retention { + count = 11 + } + } + + protection_policy { + policy_type = "Log" + + backup { + frequency_in_minutes = 15 + } + + simple_retention { + count = 8 + } + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} + +func (r BackupProtectionPolicyVMWorkloadResource) update(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-bpvmw-%d" + location = "%s" +} + +resource "azurerm_recovery_services_vault" "test" { + name = "acctest-rsv-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku = "Standard" + soft_delete_enabled = false +} + +resource "azurerm_backup_policy_vm_workload" "test" { + name = "acctest-bpvmw-%d" + resource_group_name = azurerm_resource_group.test.name + recovery_vault_name = azurerm_recovery_services_vault.test.name + + workload_type = "SAPHanaDatabase" + + settings { + time_zone = "Pacific Standard Time" + compression_enabled = false + } + + protection_policy { + policy_type = "Full" + + backup { + frequency = "Weekly" + time = "16:00" + weekdays = ["Tuesday", "Thursday"] + } + + retention_weekly { + weekdays = ["Tuesday", "Thursday"] + count = 5 + } + + retention_monthly { + format_type = "Weekly" + weeks = ["Third", "First"] + weekdays = ["Tuesday", "Thursday"] + count = 11 + } + + retention_yearly { + format_type = "Weekly" + months = ["July", "February"] + weeks = ["Third", "First"] + weekdays = ["Tuesday", "Thursday"] + count = 9 + } + } + + protection_policy { + policy_type = "Differential" + + backup { + frequency = "Weekly" + weekdays = ["Saturday", "Sunday"] + time = "17:00" + } + + simple_retention { + count = 12 + } + } + + protection_policy { + policy_type = "Log" + + backup { + frequency_in_minutes = 30 + } + + simple_retention { + count = 9 + } + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} diff --git a/internal/services/recoveryservices/registration.go b/internal/services/recoveryservices/registration.go index 1554272cf34c..d8ec8352fe30 100644 --- a/internal/services/recoveryservices/registration.go +++ b/internal/services/recoveryservices/registration.go @@ -7,12 +7,25 @@ import ( type Registration struct{} -var _ sdk.UntypedServiceRegistrationWithAGitHubLabel = Registration{} +var ( + _ sdk.TypedServiceRegistration = Registration{} + _ sdk.UntypedServiceRegistrationWithAGitHubLabel = Registration{} +) func (r Registration) AssociatedGitHubLabel() string { return "service/recovery-services" } +func (r Registration) DataSources() []sdk.DataSource { + return []sdk.DataSource{} +} + +func (r Registration) Resources() []sdk.Resource { + return []sdk.Resource{ + BackupProtectionPolicyVMWorkloadResource{}, + } +} + // Name is the name of this Service func (r Registration) Name() string { return "Recovery Services" diff --git a/internal/services/recoveryservices/site_recovery_replicated_vm_resource.go b/internal/services/recoveryservices/site_recovery_replicated_vm_resource.go index bd15cf701759..539cba753f20 100644 --- a/internal/services/recoveryservices/site_recovery_replicated_vm_resource.go +++ b/internal/services/recoveryservices/site_recovery_replicated_vm_resource.go @@ -14,6 +14,7 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + keyVaultValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/keyvault/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/services/recoveryservices/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/recoveryservices/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" @@ -186,6 +187,63 @@ func resourceSiteRecoveryReplicatedVM() *pluginsdk.Resource { ValidateFunc: azure.ValidateResourceID, DiffSuppressFunc: suppress.CaseDifference, }, + + "target_disk_encryption": { + Type: pluginsdk.TypeList, + ConfigMode: pluginsdk.SchemaConfigModeAttr, + Optional: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "disk_encryption_key": { + Type: pluginsdk.TypeList, + ConfigMode: pluginsdk.SchemaConfigModeAttr, + Required: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "secret_url": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: keyVaultValidate.NestedItemId, + }, + + "vault_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: keyVaultValidate.VaultID, + }, + }, + }, + }, + "key_encryption_key": { + Type: pluginsdk.TypeList, + ConfigMode: pluginsdk.SchemaConfigModeAttr, + Optional: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "key_url": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: keyVaultValidate.NestedItemId, + }, + + "vault_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: keyVaultValidate.VaultID, + }, + }, + }, + }, + }, + }, + }, }, }, }, @@ -291,6 +349,7 @@ func resourceSiteRecoveryReplicatedItemCreate(d *pluginsdk.ResourceData, meta in RecoveryReplicaDiskAccountType: &targetReplicaDiskType, RecoveryTargetDiskAccountType: &targetDiskType, RecoveryDiskEncryptionSetID: &targetEncryptionDiskSetID, + DiskEncryptionInfo: expandTargetDiskEncryption(diskInput["target_disk_encryption"].([]interface{})), }) } @@ -388,6 +447,7 @@ func resourceSiteRecoveryReplicatedItemUpdateInternal(ctx context.Context, d *pl DiskID: &diskId, RecoveryReplicaDiskAccountType: &targetReplicaDiskType, RecoveryTargetDiskAccountType: &targetDiskType, + DiskEncryptionInfo: expandTargetDiskEncryption(diskInput["target_disk_encryption"].([]interface{})), }) } @@ -515,6 +575,8 @@ func resourceSiteRecoveryReplicatedItemRead(d *pluginsdk.ResourceData, meta inte } diskOutput["target_disk_encryption_set_id"] = recoveryEncryptionSetId + diskOutput["target_disk_encryption"] = flattenTargetDiskEncryption(disk) + disksOutput = append(disksOutput, diskOutput) } d.Set("managed_disk", pluginsdk.NewSet(resourceSiteRecoveryReplicatedVMDiskHash, disksOutput)) @@ -653,3 +715,75 @@ func waitForReplicationToBeHealthyRefreshFunc(d *pluginsdk.ResourceData, meta in return resp, *resp.Properties.ReplicationHealth, nil } } + +func expandTargetDiskEncryption(diskEncryptionInfoList []interface{}) *siterecovery.DiskEncryptionInfo { + if len(diskEncryptionInfoList) == 0 { + return &siterecovery.DiskEncryptionInfo{} + } + diskEncryptionInfoMap := diskEncryptionInfoList[0].(map[string]interface{}) + + dek := diskEncryptionInfoMap["disk_encryption_key"].([]interface{})[0].(map[string]interface{}) + diskEncryptionInfo := &siterecovery.DiskEncryptionInfo{ + DiskEncryptionKeyInfo: &siterecovery.DiskEncryptionKeyInfo{ + SecretIdentifier: utils.String(dek["secret_url"].(string)), + KeyVaultResourceArmID: utils.String(dek["vault_id"].(string)), + }, + } + + if keyEncryptionKey := diskEncryptionInfoMap["key_encryption_key"].([]interface{}); len(keyEncryptionKey) > 0 { + kek := keyEncryptionKey[0].(map[string]interface{}) + diskEncryptionInfo.KeyEncryptionKeyInfo = &siterecovery.KeyEncryptionKeyInfo{ + KeyIdentifier: utils.String(kek["key_url"].(string)), + KeyVaultResourceArmID: utils.String(kek["vault_id"].(string)), + } + } + + return diskEncryptionInfo +} + +func flattenTargetDiskEncryption(disk siterecovery.A2AProtectedManagedDiskDetails) []interface{} { + secretUrl := "" + dekVaultId := "" + keyUrl := "" + kekVaultId := "" + + if disk.SecretIdentifier != nil { + secretUrl = *disk.SecretIdentifier + } + if disk.DekKeyVaultArmID != nil { + dekVaultId = *disk.DekKeyVaultArmID + } + if disk.KeyIdentifier != nil { + keyUrl = *disk.KeyIdentifier + } + if disk.KekKeyVaultArmID != nil { + kekVaultId = *disk.KekKeyVaultArmID + } + + if secretUrl == "" && dekVaultId == "" && keyUrl == "" && kekVaultId == "" { + return []interface{}{} + } + + diskEncryptionKeys := make([]interface{}, 0) + if secretUrl != "" || dekVaultId != "" { + diskEncryptionKeys = append(diskEncryptionKeys, map[string]interface{}{ + "secret_url": secretUrl, + "vault_id": dekVaultId, + }) + } + + keyEncryptionKeys := make([]interface{}, 0) + if keyUrl != "" || kekVaultId != "" { + keyEncryptionKeys = append(keyEncryptionKeys, map[string]interface{}{ + "key_url": keyUrl, + "vault_id": kekVaultId, + }) + } + + return []interface{}{ + map[string]interface{}{ + "disk_encryption_key": diskEncryptionKeys, + "key_encryption_key": keyEncryptionKeys, + }, + } +} diff --git a/internal/services/recoveryservices/site_recovery_replicated_vm_resource_test.go b/internal/services/recoveryservices/site_recovery_replicated_vm_resource_test.go index 7c11849d169a..be81e6c00052 100644 --- a/internal/services/recoveryservices/site_recovery_replicated_vm_resource_test.go +++ b/internal/services/recoveryservices/site_recovery_replicated_vm_resource_test.go @@ -60,6 +60,21 @@ func TestAccSiteRecoveryReplicatedVm_zone2zone(t *testing.T) { }) } +func TestAccSiteRecoveryReplicatedVm_targetDiskEncryption(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_site_recovery_replicated_vm", "test") + r := SiteRecoveryReplicatedVmResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.targetDiskEncryption(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func (SiteRecoveryReplicatedVmResource) basic(data acceptance.TestData) string { return fmt.Sprintf(` provider "azurerm" { @@ -882,6 +897,265 @@ resource "azurerm_site_recovery_replicated_vm" "test" { `, data.RandomInteger, data.Locations.Primary, data.Locations.Secondary) } +func (SiteRecoveryReplicatedVmResource) targetDiskEncryption(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features { + key_vault { + purge_soft_delete_on_destroy = false + purge_soft_deleted_keys_on_destroy = false + purge_soft_deleted_secrets_on_destroy = false + } + } +} + +data "azurerm_client_config" "current" {} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-recovery-%[1]d-1" + location = "%[2]s" +} +resource "azurerm_resource_group" "test2" { + name = "acctestRG-recovery-%[1]d-2" + location = "%[3]s" +} + +resource "azurerm_key_vault" "test1" { + name = "acckv-%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + tenant_id = data.azurerm_client_config.current.tenant_id + sku_name = "premium" + enabled_for_disk_encryption = true + purge_protection_enabled = true +} + +resource "azurerm_key_vault_access_policy" "service-principal" { + key_vault_id = azurerm_key_vault.test1.id + tenant_id = data.azurerm_client_config.current.tenant_id + object_id = data.azurerm_client_config.current.object_id + + key_permissions = [ + "Create", + "Delete", + "Get", + "Update", + ] + + secret_permissions = [ + "Get", + "Delete", + "Set", + ] +} + +resource "azurerm_key_vault_key" "test1" { + name = "examplekey" + key_vault_id = azurerm_key_vault.test1.id + key_type = "RSA" + key_size = 3072 + + key_opts = [ + "decrypt", + "encrypt", + "sign", + "unwrapKey", + "verify", + "wrapKey", + ] + + depends_on = [ + azurerm_key_vault_access_policy.service-principal + ] +} + +resource "azurerm_recovery_services_vault" "test" { + name = "acctest-vault-%[1]d" + location = azurerm_resource_group.test2.location + resource_group_name = azurerm_resource_group.test2.name + sku = "Standard" + soft_delete_enabled = false +} +resource "azurerm_site_recovery_fabric" "test1" { + resource_group_name = azurerm_resource_group.test2.name + recovery_vault_name = azurerm_recovery_services_vault.test.name + name = "acctest-fabric1-%[1]d" + location = azurerm_resource_group.test.location +} +resource "azurerm_site_recovery_protection_container" "test1" { + resource_group_name = azurerm_resource_group.test2.name + recovery_vault_name = azurerm_recovery_services_vault.test.name + recovery_fabric_name = azurerm_site_recovery_fabric.test1.name + name = "acctest-protection-cont1-%[1]d" +} +resource "azurerm_site_recovery_protection_container" "test2" { + resource_group_name = azurerm_resource_group.test2.name + recovery_vault_name = azurerm_recovery_services_vault.test.name + recovery_fabric_name = azurerm_site_recovery_fabric.test1.name + name = "acctest-protection-cont2-t-%[1]d" +} +resource "azurerm_site_recovery_replication_policy" "test" { + resource_group_name = azurerm_resource_group.test2.name + recovery_vault_name = azurerm_recovery_services_vault.test.name + name = "acctest-policy-%[1]d" + recovery_point_retention_in_minutes = 24 * 60 + application_consistent_snapshot_frequency_in_minutes = 4 * 60 +} +resource "azurerm_site_recovery_protection_container_mapping" "test" { + resource_group_name = azurerm_resource_group.test2.name + recovery_vault_name = azurerm_recovery_services_vault.test.name + recovery_fabric_name = azurerm_site_recovery_fabric.test1.name + recovery_source_protection_container_name = azurerm_site_recovery_protection_container.test1.name + recovery_target_protection_container_id = azurerm_site_recovery_protection_container.test2.id + recovery_replication_policy_id = azurerm_site_recovery_replication_policy.test.id + name = "mapping-%[1]d" +} +resource "azurerm_virtual_network" "test1" { + name = "net-%[1]d" + resource_group_name = azurerm_resource_group.test.name + address_space = ["192.168.1.0/24"] + location = azurerm_site_recovery_fabric.test1.location +} +resource "azurerm_subnet" "test1" { + name = "snet-%[1]d" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test1.name + address_prefixes = ["192.168.1.0/24"] +} +resource "azurerm_network_interface" "test" { + name = "vm-%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + ip_configuration { + name = "vm-%[1]d" + subnet_id = azurerm_subnet.test1.id + private_ip_address_allocation = "Dynamic" + } +} + +resource "azurerm_windows_virtual_machine" "vm" { + name = "acctvm%[4]s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + size = "Standard_D2s_v3" + admin_username = "adminuser" + admin_password = "P@ssw0rd1234!" + zone = "1" + network_interface_ids = [ + azurerm_network_interface.test.id, + ] + + source_image_reference { + publisher = "MicrosoftWindowsServer" + offer = "WindowsServer" + sku = "2022-Datacenter" + version = "latest" + } + + os_disk { + storage_account_type = "Standard_LRS" + caching = "ReadWrite" + } +} + +resource "azurerm_virtual_machine_extension" "test" { + name = "AzureDiskEncryption" + publisher = "Microsoft.Azure.Security" + type = "AzureDiskEncryption" + type_handler_version = "2.2" + auto_upgrade_minor_version = false + virtual_machine_id = azurerm_windows_virtual_machine.vm.id + + settings = < skuWeight[new.(string)] + } + return false + }), + ), } } diff --git a/internal/services/redis/redis_cache_resource_test.go b/internal/services/redis/redis_cache_resource_test.go index 411212a21910..f77f76f76cb8 100644 --- a/internal/services/redis/redis_cache_resource_test.go +++ b/internal/services/redis/redis_cache_resource_test.go @@ -496,6 +496,27 @@ func TestAccRedisCache_identity(t *testing.T) { }) } +func TestAccRedisCache_SkuDowngrade(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_redis_cache", "test") + r := RedisCacheResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.standard(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.SkuDowngrade(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + }) +} + func (t RedisCacheResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { id, err := parse.CacheID(state.ID) if err != nil { @@ -1307,6 +1328,35 @@ resource "azurerm_redis_cache" "test" { `, data.RandomInteger, data.Locations.Primary, data.RandomString, data.RandomInteger) } +func (RedisCacheResource) SkuDowngrade(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_redis_cache" "test" { + name = "acctestRedis-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + capacity = 1 + family = "C" + sku_name = "Basic" + enable_non_ssl_port = false + redis_configuration { + } + + tags = { + environment = "production" + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger) +} + func testCheckSSLInConnectionString(resourceName string, propertyName string, requireSSL bool) acceptance.TestCheckFunc { return func(s *acceptance.State) error { // Ensure we have enough information in state to look up in API diff --git a/internal/services/resource/resource_group_template_deployment_resource_test.go b/internal/services/resource/resource_group_template_deployment_resource_test.go index 415c4566f47d..cd9cd2835551 100644 --- a/internal/services/resource/resource_group_template_deployment_resource_test.go +++ b/internal/services/resource/resource_group_template_deployment_resource_test.go @@ -72,7 +72,24 @@ func TestAccResourceGroupTemplateDeployment_singleItemIncorrectCasing(t *testing check.That(data.ResourceName).ExistsInAzure(r), ), }, + }) +} + +func TestAccResourceGroupTemplateDeployment_inconsistentProviderCasing(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_resource_group_template_deployment", "test") + r := ResourceGroupTemplateDeploymentResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.inconsistentProviderCasing(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, data.ImportStep(), + { // delete item + Config: r.inconsistentProviderCasingEmpty(data), + }, }) } @@ -452,6 +469,83 @@ PARAM `, data.RandomInteger, data.Locations.Primary, data.RandomInteger, value) } +func (ResourceGroupTemplateDeploymentResource) inconsistentProviderCasing(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = %q +} + +resource "azurerm_resource_group_template_deployment" "test" { + name = "acctest" + resource_group_name = azurerm_resource_group.test.name + deployment_mode = "Complete" + + template_content = <